Merge pull request #5679 from stenzek/no-host-state-in-uids
ShaderGen: Decouple host state from shader UIDs
This commit is contained in:
commit
a11bde7d16
|
@ -158,18 +158,23 @@ void GeometryShaderCache::Init()
|
||||||
Clear();
|
Clear();
|
||||||
|
|
||||||
if (g_ActiveConfig.bShaderCache)
|
if (g_ActiveConfig.bShaderCache)
|
||||||
{
|
LoadShaderCache();
|
||||||
if (!File::Exists(File::GetUserPath(D_SHADERCACHE_IDX)))
|
}
|
||||||
File::CreateDir(File::GetUserPath(D_SHADERCACHE_IDX));
|
|
||||||
|
|
||||||
std::string cache_filename =
|
void GeometryShaderCache::LoadShaderCache()
|
||||||
StringFromFormat("%sdx11-%s-gs.cache", File::GetUserPath(D_SHADERCACHE_IDX).c_str(),
|
{
|
||||||
SConfig::GetInstance().GetGameID().c_str());
|
GeometryShaderCacheInserter inserter;
|
||||||
GeometryShaderCacheInserter inserter;
|
g_gs_disk_cache.OpenAndRead(GetDiskShaderCacheFileName(APIType::D3D, "GS", true, true), inserter);
|
||||||
g_gs_disk_cache.OpenAndRead(cache_filename, inserter);
|
}
|
||||||
}
|
|
||||||
|
|
||||||
last_entry = nullptr;
|
void GeometryShaderCache::Reload()
|
||||||
|
{
|
||||||
|
g_gs_disk_cache.Sync();
|
||||||
|
g_gs_disk_cache.Close();
|
||||||
|
Clear();
|
||||||
|
|
||||||
|
if (g_ActiveConfig.bShaderCache)
|
||||||
|
LoadShaderCache();
|
||||||
}
|
}
|
||||||
|
|
||||||
// ONLY to be used during shutdown.
|
// ONLY to be used during shutdown.
|
||||||
|
@ -180,6 +185,7 @@ void GeometryShaderCache::Clear()
|
||||||
GeometryShaders.clear();
|
GeometryShaders.clear();
|
||||||
|
|
||||||
last_entry = nullptr;
|
last_entry = nullptr;
|
||||||
|
last_uid = {};
|
||||||
}
|
}
|
||||||
|
|
||||||
void GeometryShaderCache::Shutdown()
|
void GeometryShaderCache::Shutdown()
|
||||||
|
@ -230,7 +236,8 @@ bool GeometryShaderCache::SetShader(u32 primitive_type)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Need to compile a new shader
|
// Need to compile a new shader
|
||||||
ShaderCode code = GenerateGeometryShaderCode(APIType::D3D, uid.GetUidData());
|
ShaderCode code =
|
||||||
|
GenerateGeometryShaderCode(APIType::D3D, ShaderHostConfig::GetCurrent(), uid.GetUidData());
|
||||||
|
|
||||||
D3DBlob* pbytecode;
|
D3DBlob* pbytecode;
|
||||||
if (!D3D::CompileGeometryShader(code.GetBuffer(), &pbytecode))
|
if (!D3D::CompileGeometryShader(code.GetBuffer(), &pbytecode))
|
||||||
|
|
|
@ -15,6 +15,7 @@ class GeometryShaderCache
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
static void Init();
|
static void Init();
|
||||||
|
static void Reload();
|
||||||
static void Clear();
|
static void Clear();
|
||||||
static void Shutdown();
|
static void Shutdown();
|
||||||
static bool SetShader(u32 primitive_type); // TODO: Should be renamed to LoadShader
|
static bool SetShader(u32 primitive_type); // TODO: Should be renamed to LoadShader
|
||||||
|
@ -38,6 +39,8 @@ private:
|
||||||
|
|
||||||
typedef std::map<GeometryShaderUid, GSCacheEntry> GSCache;
|
typedef std::map<GeometryShaderUid, GSCacheEntry> GSCache;
|
||||||
|
|
||||||
|
static void LoadShaderCache();
|
||||||
|
|
||||||
static GSCache GeometryShaders;
|
static GSCache GeometryShaders;
|
||||||
static const GSCacheEntry* last_entry;
|
static const GSCacheEntry* last_entry;
|
||||||
static GeometryShaderUid last_uid;
|
static GeometryShaderUid last_uid;
|
||||||
|
|
|
@ -498,18 +498,23 @@ void PixelShaderCache::Init()
|
||||||
SETSTAT(stats.numPixelShadersAlive, 0);
|
SETSTAT(stats.numPixelShadersAlive, 0);
|
||||||
|
|
||||||
if (g_ActiveConfig.bShaderCache)
|
if (g_ActiveConfig.bShaderCache)
|
||||||
{
|
LoadShaderCache();
|
||||||
if (!File::Exists(File::GetUserPath(D_SHADERCACHE_IDX)))
|
}
|
||||||
File::CreateDir(File::GetUserPath(D_SHADERCACHE_IDX));
|
|
||||||
|
|
||||||
std::string cache_filename =
|
void PixelShaderCache::LoadShaderCache()
|
||||||
StringFromFormat("%sdx11-%s-ps.cache", File::GetUserPath(D_SHADERCACHE_IDX).c_str(),
|
{
|
||||||
SConfig::GetInstance().GetGameID().c_str());
|
PixelShaderCacheInserter inserter;
|
||||||
PixelShaderCacheInserter inserter;
|
g_ps_disk_cache.OpenAndRead(GetDiskShaderCacheFileName(APIType::D3D, "PS", true, true), inserter);
|
||||||
g_ps_disk_cache.OpenAndRead(cache_filename, inserter);
|
}
|
||||||
}
|
|
||||||
|
|
||||||
last_entry = nullptr;
|
void PixelShaderCache::Reload()
|
||||||
|
{
|
||||||
|
g_ps_disk_cache.Sync();
|
||||||
|
g_ps_disk_cache.Close();
|
||||||
|
Clear();
|
||||||
|
|
||||||
|
if (g_ActiveConfig.bShaderCache)
|
||||||
|
LoadShaderCache();
|
||||||
}
|
}
|
||||||
|
|
||||||
// ONLY to be used during shutdown.
|
// ONLY to be used during shutdown.
|
||||||
|
@ -520,6 +525,7 @@ void PixelShaderCache::Clear()
|
||||||
PixelShaders.clear();
|
PixelShaders.clear();
|
||||||
|
|
||||||
last_entry = nullptr;
|
last_entry = nullptr;
|
||||||
|
last_uid = {};
|
||||||
}
|
}
|
||||||
|
|
||||||
// Used in Swap() when AA mode has changed
|
// Used in Swap() when AA mode has changed
|
||||||
|
@ -583,7 +589,8 @@ bool PixelShaderCache::SetShader()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Need to compile a new shader
|
// Need to compile a new shader
|
||||||
ShaderCode code = GeneratePixelShaderCode(APIType::D3D, uid.GetUidData());
|
ShaderCode code =
|
||||||
|
GeneratePixelShaderCode(APIType::D3D, ShaderHostConfig::GetCurrent(), uid.GetUidData());
|
||||||
|
|
||||||
D3DBlob* pbytecode;
|
D3DBlob* pbytecode;
|
||||||
if (!D3D::CompilePixelShader(code.GetBuffer(), &pbytecode))
|
if (!D3D::CompilePixelShader(code.GetBuffer(), &pbytecode))
|
||||||
|
|
|
@ -15,6 +15,7 @@ class PixelShaderCache
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
static void Init();
|
static void Init();
|
||||||
|
static void Reload();
|
||||||
static void Clear();
|
static void Clear();
|
||||||
static void Shutdown();
|
static void Shutdown();
|
||||||
static bool SetShader(); // TODO: Should be renamed to LoadShader
|
static bool SetShader(); // TODO: Should be renamed to LoadShader
|
||||||
|
@ -46,6 +47,8 @@ private:
|
||||||
|
|
||||||
typedef std::map<PixelShaderUid, PSCacheEntry> PSCache;
|
typedef std::map<PixelShaderUid, PSCacheEntry> PSCache;
|
||||||
|
|
||||||
|
static void LoadShaderCache();
|
||||||
|
|
||||||
static PSCache PixelShaders;
|
static PSCache PixelShaders;
|
||||||
static const PSCacheEntry* last_entry;
|
static const PSCacheEntry* last_entry;
|
||||||
static PixelShaderUid last_uid;
|
static PixelShaderUid last_uid;
|
||||||
|
|
|
@ -894,6 +894,13 @@ void Renderer::SwapImpl(u32 xfbAddr, u32 fbWidth, u32 fbStride, u32 fbHeight,
|
||||||
D3D11_CLEAR_DEPTH, 0.f, 0);
|
D3D11_CLEAR_DEPTH, 0.f, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (CheckForHostConfigChanges())
|
||||||
|
{
|
||||||
|
VertexShaderCache::Reload();
|
||||||
|
GeometryShaderCache::Reload();
|
||||||
|
PixelShaderCache::Reload();
|
||||||
|
}
|
||||||
|
|
||||||
// begin next frame
|
// begin next frame
|
||||||
RestoreAPIState();
|
RestoreAPIState();
|
||||||
D3D::BeginFrame();
|
D3D::BeginFrame();
|
||||||
|
|
|
@ -159,18 +159,23 @@ void VertexShaderCache::Init()
|
||||||
SETSTAT(stats.numVertexShadersAlive, 0);
|
SETSTAT(stats.numVertexShadersAlive, 0);
|
||||||
|
|
||||||
if (g_ActiveConfig.bShaderCache)
|
if (g_ActiveConfig.bShaderCache)
|
||||||
{
|
LoadShaderCache();
|
||||||
if (!File::Exists(File::GetUserPath(D_SHADERCACHE_IDX)))
|
}
|
||||||
File::CreateDir(File::GetUserPath(D_SHADERCACHE_IDX));
|
|
||||||
|
|
||||||
std::string cache_filename =
|
void VertexShaderCache::LoadShaderCache()
|
||||||
StringFromFormat("%sdx11-%s-vs.cache", File::GetUserPath(D_SHADERCACHE_IDX).c_str(),
|
{
|
||||||
SConfig::GetInstance().GetGameID().c_str());
|
VertexShaderCacheInserter inserter;
|
||||||
VertexShaderCacheInserter inserter;
|
g_vs_disk_cache.OpenAndRead(GetDiskShaderCacheFileName(APIType::D3D, "VS", true, true), inserter);
|
||||||
g_vs_disk_cache.OpenAndRead(cache_filename, inserter);
|
}
|
||||||
}
|
|
||||||
|
|
||||||
last_entry = nullptr;
|
void VertexShaderCache::Reload()
|
||||||
|
{
|
||||||
|
g_vs_disk_cache.Sync();
|
||||||
|
g_vs_disk_cache.Close();
|
||||||
|
Clear();
|
||||||
|
|
||||||
|
if (g_ActiveConfig.bShaderCache)
|
||||||
|
LoadShaderCache();
|
||||||
}
|
}
|
||||||
|
|
||||||
void VertexShaderCache::Clear()
|
void VertexShaderCache::Clear()
|
||||||
|
@ -180,6 +185,7 @@ void VertexShaderCache::Clear()
|
||||||
vshaders.clear();
|
vshaders.clear();
|
||||||
|
|
||||||
last_entry = nullptr;
|
last_entry = nullptr;
|
||||||
|
last_uid = {};
|
||||||
}
|
}
|
||||||
|
|
||||||
void VertexShaderCache::Shutdown()
|
void VertexShaderCache::Shutdown()
|
||||||
|
@ -222,7 +228,8 @@ bool VertexShaderCache::SetShader()
|
||||||
return (entry.shader != nullptr);
|
return (entry.shader != nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
ShaderCode code = GenerateVertexShaderCode(APIType::D3D, uid.GetUidData());
|
ShaderCode code =
|
||||||
|
GenerateVertexShaderCode(APIType::D3D, ShaderHostConfig::GetCurrent(), uid.GetUidData());
|
||||||
|
|
||||||
D3DBlob* pbytecode = nullptr;
|
D3DBlob* pbytecode = nullptr;
|
||||||
D3D::CompileVertexShader(code.GetBuffer(), &pbytecode);
|
D3D::CompileVertexShader(code.GetBuffer(), &pbytecode);
|
||||||
|
|
|
@ -17,6 +17,7 @@ class VertexShaderCache
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
static void Init();
|
static void Init();
|
||||||
|
static void Reload();
|
||||||
static void Clear();
|
static void Clear();
|
||||||
static void Shutdown();
|
static void Shutdown();
|
||||||
static bool SetShader(); // TODO: Should be renamed to LoadShader
|
static bool SetShader(); // TODO: Should be renamed to LoadShader
|
||||||
|
@ -53,6 +54,8 @@ private:
|
||||||
};
|
};
|
||||||
typedef std::map<VertexShaderUid, VSCacheEntry> VSCache;
|
typedef std::map<VertexShaderUid, VSCacheEntry> VSCache;
|
||||||
|
|
||||||
|
static void LoadShaderCache();
|
||||||
|
|
||||||
static VSCache vshaders;
|
static VSCache vshaders;
|
||||||
static const VSCacheEntry* last_entry;
|
static const VSCacheEntry* last_entry;
|
||||||
static VertexShaderUid last_uid;
|
static VertexShaderUid last_uid;
|
||||||
|
|
|
@ -46,7 +46,7 @@ protected:
|
||||||
}
|
}
|
||||||
ShaderCode GenerateCode(APIType api_type, VertexShaderUid uid) override
|
ShaderCode GenerateCode(APIType api_type, VertexShaderUid uid) override
|
||||||
{
|
{
|
||||||
return GenerateVertexShaderCode(api_type, uid.GetUidData());
|
return GenerateVertexShaderCode(api_type, ShaderHostConfig::GetCurrent(), uid.GetUidData());
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -62,7 +62,7 @@ protected:
|
||||||
}
|
}
|
||||||
ShaderCode GenerateCode(APIType api_type, GeometryShaderUid uid) override
|
ShaderCode GenerateCode(APIType api_type, GeometryShaderUid uid) override
|
||||||
{
|
{
|
||||||
return GenerateGeometryShaderCode(api_type, uid.GetUidData());
|
return GenerateGeometryShaderCode(api_type, ShaderHostConfig::GetCurrent(), uid.GetUidData());
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -78,7 +78,7 @@ protected:
|
||||||
}
|
}
|
||||||
ShaderCode GenerateCode(APIType api_type, PixelShaderUid uid) override
|
ShaderCode GenerateCode(APIType api_type, PixelShaderUid uid) override
|
||||||
{
|
{
|
||||||
return GeneratePixelShaderCode(api_type, uid.GetUidData());
|
return GeneratePixelShaderCode(api_type, ShaderHostConfig::GetCurrent(), uid.GetUidData());
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -217,12 +217,13 @@ SHADER* ProgramShaderCache::SetShader(u32 primitive_type)
|
||||||
last_entry = &newentry;
|
last_entry = &newentry;
|
||||||
newentry.in_cache = 0;
|
newentry.in_cache = 0;
|
||||||
|
|
||||||
ShaderCode vcode = GenerateVertexShaderCode(APIType::OpenGL, uid.vuid.GetUidData());
|
ShaderHostConfig host_config = ShaderHostConfig::GetCurrent();
|
||||||
ShaderCode pcode = GeneratePixelShaderCode(APIType::OpenGL, uid.puid.GetUidData());
|
ShaderCode vcode = GenerateVertexShaderCode(APIType::OpenGL, host_config, uid.vuid.GetUidData());
|
||||||
|
ShaderCode pcode = GeneratePixelShaderCode(APIType::OpenGL, host_config, uid.puid.GetUidData());
|
||||||
ShaderCode gcode;
|
ShaderCode gcode;
|
||||||
if (g_ActiveConfig.backend_info.bSupportsGeometryShaders &&
|
if (g_ActiveConfig.backend_info.bSupportsGeometryShaders &&
|
||||||
!uid.guid.GetUidData()->IsPassthrough())
|
!uid.guid.GetUidData()->IsPassthrough())
|
||||||
gcode = GenerateGeometryShaderCode(APIType::OpenGL, uid.guid.GetUidData());
|
gcode = GenerateGeometryShaderCode(APIType::OpenGL, host_config, uid.guid.GetUidData());
|
||||||
|
|
||||||
#if defined(_DEBUG) || defined(DEBUGFAST)
|
#if defined(_DEBUG) || defined(DEBUGFAST)
|
||||||
if (g_ActiveConfig.iLog & CONF_SAVESHADERS)
|
if (g_ActiveConfig.iLog & CONF_SAVESHADERS)
|
||||||
|
@ -504,29 +505,7 @@ void ProgramShaderCache::Init()
|
||||||
|
|
||||||
// Read our shader cache, only if supported and enabled
|
// Read our shader cache, only if supported and enabled
|
||||||
if (g_ogl_config.bSupportsGLSLCache && g_ActiveConfig.bShaderCache)
|
if (g_ogl_config.bSupportsGLSLCache && g_ActiveConfig.bShaderCache)
|
||||||
{
|
LoadProgramBinaries();
|
||||||
GLint Supported;
|
|
||||||
glGetIntegerv(GL_NUM_PROGRAM_BINARY_FORMATS, &Supported);
|
|
||||||
if (!Supported)
|
|
||||||
{
|
|
||||||
ERROR_LOG(VIDEO, "GL_ARB_get_program_binary is supported, but no binary format is known. So "
|
|
||||||
"disable shader cache.");
|
|
||||||
g_ogl_config.bSupportsGLSLCache = false;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (!File::Exists(File::GetUserPath(D_SHADERCACHE_IDX)))
|
|
||||||
File::CreateDir(File::GetUserPath(D_SHADERCACHE_IDX));
|
|
||||||
|
|
||||||
std::string cache_filename =
|
|
||||||
StringFromFormat("%sogl-%s-shaders.cache", File::GetUserPath(D_SHADERCACHE_IDX).c_str(),
|
|
||||||
SConfig::GetInstance().GetGameID().c_str());
|
|
||||||
|
|
||||||
ProgramShaderCacheInserter inserter;
|
|
||||||
g_program_disk_cache.OpenAndRead(cache_filename, inserter);
|
|
||||||
}
|
|
||||||
SETSTAT(stats.numPixelShadersAlive, pshaders.size());
|
|
||||||
}
|
|
||||||
|
|
||||||
CreateHeader();
|
CreateHeader();
|
||||||
|
|
||||||
|
@ -534,47 +513,93 @@ void ProgramShaderCache::Init()
|
||||||
last_entry = nullptr;
|
last_entry = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ProgramShaderCache::Reload()
|
||||||
|
{
|
||||||
|
const bool use_cache = g_ogl_config.bSupportsGLSLCache && g_ActiveConfig.bShaderCache;
|
||||||
|
if (use_cache)
|
||||||
|
SaveProgramBinaries();
|
||||||
|
|
||||||
|
g_program_disk_cache.Close();
|
||||||
|
DestroyShaders();
|
||||||
|
|
||||||
|
if (use_cache)
|
||||||
|
LoadProgramBinaries();
|
||||||
|
|
||||||
|
CurrentProgram = 0;
|
||||||
|
last_entry = nullptr;
|
||||||
|
last_uid = {};
|
||||||
|
}
|
||||||
|
|
||||||
void ProgramShaderCache::Shutdown()
|
void ProgramShaderCache::Shutdown()
|
||||||
{
|
{
|
||||||
// store all shaders in cache on disk
|
// store all shaders in cache on disk
|
||||||
if (g_ogl_config.bSupportsGLSLCache)
|
if (g_ogl_config.bSupportsGLSLCache && g_ActiveConfig.bShaderCache)
|
||||||
|
SaveProgramBinaries();
|
||||||
|
g_program_disk_cache.Close();
|
||||||
|
|
||||||
|
DestroyShaders();
|
||||||
|
s_buffer.reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ProgramShaderCache::LoadProgramBinaries()
|
||||||
|
{
|
||||||
|
GLint Supported;
|
||||||
|
glGetIntegerv(GL_NUM_PROGRAM_BINARY_FORMATS, &Supported);
|
||||||
|
if (!Supported)
|
||||||
{
|
{
|
||||||
for (auto& entry : pshaders)
|
ERROR_LOG(VIDEO, "GL_ARB_get_program_binary is supported, but no binary format is known. So "
|
||||||
|
"disable shader cache.");
|
||||||
|
g_ogl_config.bSupportsGLSLCache = false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
std::string cache_filename =
|
||||||
|
GetDiskShaderCacheFileName(APIType::OpenGL, "ProgramBinaries", true, true);
|
||||||
|
ProgramShaderCacheInserter inserter;
|
||||||
|
g_program_disk_cache.OpenAndRead(cache_filename, inserter);
|
||||||
|
}
|
||||||
|
SETSTAT(stats.numPixelShadersAlive, pshaders.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
void ProgramShaderCache::SaveProgramBinaries()
|
||||||
|
{
|
||||||
|
for (auto& entry : pshaders)
|
||||||
|
{
|
||||||
|
// Clear any prior error code
|
||||||
|
glGetError();
|
||||||
|
|
||||||
|
if (entry.second.in_cache)
|
||||||
{
|
{
|
||||||
// Clear any prior error code
|
continue;
|
||||||
glGetError();
|
|
||||||
|
|
||||||
if (entry.second.in_cache)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
GLint link_status = GL_FALSE, delete_status = GL_TRUE, binary_size = 0;
|
|
||||||
glGetProgramiv(entry.second.shader.glprogid, GL_LINK_STATUS, &link_status);
|
|
||||||
glGetProgramiv(entry.second.shader.glprogid, GL_DELETE_STATUS, &delete_status);
|
|
||||||
glGetProgramiv(entry.second.shader.glprogid, GL_PROGRAM_BINARY_LENGTH, &binary_size);
|
|
||||||
if (glGetError() != GL_NO_ERROR || link_status == GL_FALSE || delete_status == GL_TRUE ||
|
|
||||||
!binary_size)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<u8> data(binary_size + sizeof(GLenum));
|
|
||||||
u8* binary = &data[sizeof(GLenum)];
|
|
||||||
GLenum* prog_format = (GLenum*)&data[0];
|
|
||||||
glGetProgramBinary(entry.second.shader.glprogid, binary_size, nullptr, prog_format, binary);
|
|
||||||
if (glGetError() != GL_NO_ERROR)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
g_program_disk_cache.Append(entry.first, &data[0], binary_size + sizeof(GLenum));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
g_program_disk_cache.Sync();
|
GLint link_status = GL_FALSE, delete_status = GL_TRUE, binary_size = 0;
|
||||||
g_program_disk_cache.Close();
|
glGetProgramiv(entry.second.shader.glprogid, GL_LINK_STATUS, &link_status);
|
||||||
|
glGetProgramiv(entry.second.shader.glprogid, GL_DELETE_STATUS, &delete_status);
|
||||||
|
glGetProgramiv(entry.second.shader.glprogid, GL_PROGRAM_BINARY_LENGTH, &binary_size);
|
||||||
|
if (glGetError() != GL_NO_ERROR || link_status == GL_FALSE || delete_status == GL_TRUE ||
|
||||||
|
!binary_size)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<u8> data(binary_size + sizeof(GLenum));
|
||||||
|
u8* binary = &data[sizeof(GLenum)];
|
||||||
|
GLenum* prog_format = (GLenum*)&data[0];
|
||||||
|
glGetProgramBinary(entry.second.shader.glprogid, binary_size, nullptr, prog_format, binary);
|
||||||
|
if (glGetError() != GL_NO_ERROR)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
g_program_disk_cache.Append(entry.first, &data[0], binary_size + sizeof(GLenum));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
g_program_disk_cache.Sync();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ProgramShaderCache::DestroyShaders()
|
||||||
|
{
|
||||||
glUseProgram(0);
|
glUseProgram(0);
|
||||||
|
|
||||||
for (auto& entry : pshaders)
|
for (auto& entry : pshaders)
|
||||||
|
@ -582,8 +607,6 @@ void ProgramShaderCache::Shutdown()
|
||||||
entry.second.Destroy();
|
entry.second.Destroy();
|
||||||
}
|
}
|
||||||
pshaders.clear();
|
pshaders.clear();
|
||||||
|
|
||||||
s_buffer.reset();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ProgramShaderCache::CreateHeader()
|
void ProgramShaderCache::CreateHeader()
|
||||||
|
|
|
@ -72,6 +72,7 @@ public:
|
||||||
static void UploadConstants();
|
static void UploadConstants();
|
||||||
|
|
||||||
static void Init();
|
static void Init();
|
||||||
|
static void Reload();
|
||||||
static void Shutdown();
|
static void Shutdown();
|
||||||
static void CreateHeader();
|
static void CreateHeader();
|
||||||
|
|
||||||
|
@ -82,6 +83,10 @@ private:
|
||||||
void Read(const SHADERUID& key, const u8* value, u32 value_size) override;
|
void Read(const SHADERUID& key, const u8* value, u32 value_size) override;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static void LoadProgramBinaries();
|
||||||
|
static void SaveProgramBinaries();
|
||||||
|
static void DestroyShaders();
|
||||||
|
|
||||||
typedef std::map<SHADERUID, PCacheEntry> PCache;
|
typedef std::map<SHADERUID, PCacheEntry> PCache;
|
||||||
static PCache pshaders;
|
static PCache pshaders;
|
||||||
static PCacheEntry* last_entry;
|
static PCacheEntry* last_entry;
|
||||||
|
|
|
@ -43,6 +43,7 @@
|
||||||
#include "VideoCommon/PixelEngine.h"
|
#include "VideoCommon/PixelEngine.h"
|
||||||
#include "VideoCommon/PixelShaderManager.h"
|
#include "VideoCommon/PixelShaderManager.h"
|
||||||
#include "VideoCommon/RenderState.h"
|
#include "VideoCommon/RenderState.h"
|
||||||
|
#include "VideoCommon/ShaderGenCommon.h"
|
||||||
#include "VideoCommon/VertexShaderManager.h"
|
#include "VideoCommon/VertexShaderManager.h"
|
||||||
#include "VideoCommon/VideoBackendBase.h"
|
#include "VideoCommon/VideoBackendBase.h"
|
||||||
#include "VideoCommon/VideoConfig.h"
|
#include "VideoCommon/VideoConfig.h"
|
||||||
|
@ -664,6 +665,9 @@ Renderer::Renderer()
|
||||||
g_Config.VerifyValidity();
|
g_Config.VerifyValidity();
|
||||||
UpdateActiveConfig();
|
UpdateActiveConfig();
|
||||||
|
|
||||||
|
// Since we modify the config here, we need to update the last host bits, it may have changed.
|
||||||
|
m_last_host_config_bits = ShaderHostConfig::GetCurrent().bits;
|
||||||
|
|
||||||
OSD::AddMessage(StringFromFormat("Video Info: %s, %s, %s", g_ogl_config.gl_vendor,
|
OSD::AddMessage(StringFromFormat("Video Info: %s, %s, %s", g_ogl_config.gl_vendor,
|
||||||
g_ogl_config.gl_renderer, g_ogl_config.gl_version),
|
g_ogl_config.gl_renderer, g_ogl_config.gl_version),
|
||||||
5000);
|
5000);
|
||||||
|
@ -1469,6 +1473,10 @@ void Renderer::SwapImpl(u32 xfbAddr, u32 fbWidth, u32 fbStride, u32 fbHeight,
|
||||||
UpdateActiveConfig();
|
UpdateActiveConfig();
|
||||||
g_texture_cache->OnConfigChanged(g_ActiveConfig);
|
g_texture_cache->OnConfigChanged(g_ActiveConfig);
|
||||||
|
|
||||||
|
// Invalidate shader cache when the host config changes.
|
||||||
|
if (CheckForHostConfigChanges())
|
||||||
|
ProgramShaderCache::Reload();
|
||||||
|
|
||||||
// For testing zbuffer targets.
|
// For testing zbuffer targets.
|
||||||
// Renderer::SetZBufferRender();
|
// Renderer::SetZBufferRender();
|
||||||
// SaveTexture("tex.png", GL_TEXTURE_2D, s_FakeZTarget,
|
// SaveTexture("tex.png", GL_TEXTURE_2D, s_FakeZTarget,
|
||||||
|
|
|
@ -1274,12 +1274,12 @@ bool FramebufferManager::CompilePokeShaders()
|
||||||
layout(triangles) in;
|
layout(triangles) in;
|
||||||
layout(triangle_strip, max_vertices = EFB_LAYERS * 3) out;
|
layout(triangle_strip, max_vertices = EFB_LAYERS * 3) out;
|
||||||
|
|
||||||
in VertexData
|
VARYING_LOCATION(0) in VertexData
|
||||||
{
|
{
|
||||||
vec4 col0;
|
vec4 col0;
|
||||||
} in_data[];
|
} in_data[];
|
||||||
|
|
||||||
out VertexData
|
VARYING_LOCATION(0) out VertexData
|
||||||
{
|
{
|
||||||
vec4 col0;
|
vec4 col0;
|
||||||
} out_data;
|
} out_data;
|
||||||
|
|
|
@ -49,9 +49,17 @@ bool ObjectCache::Initialize()
|
||||||
if (!CreatePipelineLayouts())
|
if (!CreatePipelineLayouts())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
LoadShaderCaches();
|
if (g_ActiveConfig.bShaderCache)
|
||||||
if (!CreatePipelineCache(true))
|
{
|
||||||
return false;
|
LoadShaderCaches();
|
||||||
|
if (!LoadPipelineCache())
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (!CreatePipelineCache())
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
if (!CreateUtilityShaderVertexFormat())
|
if (!CreateUtilityShaderVertexFormat())
|
||||||
return false;
|
return false;
|
||||||
|
@ -438,12 +446,6 @@ void ObjectCache::ClearPipelineCache()
|
||||||
m_compute_pipeline_objects.clear();
|
m_compute_pipeline_objects.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string ObjectCache::GetDiskCacheFileName(const char* type)
|
|
||||||
{
|
|
||||||
return StringFromFormat("%svulkan-%s-%s.cache", File::GetUserPath(D_SHADERCACHE_IDX).c_str(),
|
|
||||||
SConfig::GetInstance().GetGameID().c_str(), type);
|
|
||||||
}
|
|
||||||
|
|
||||||
class PipelineCacheReadCallback : public LinearDiskCacheReader<u32, u8>
|
class PipelineCacheReadCallback : public LinearDiskCacheReader<u32, u8>
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
@ -465,26 +467,47 @@ public:
|
||||||
void Read(const u32& key, const u8* value, u32 value_size) override {}
|
void Read(const u32& key, const u8* value, u32 value_size) override {}
|
||||||
};
|
};
|
||||||
|
|
||||||
bool ObjectCache::CreatePipelineCache(bool load_from_disk)
|
bool ObjectCache::CreatePipelineCache()
|
||||||
|
{
|
||||||
|
// Vulkan pipeline caches can be shared between games for shader compile time reduction.
|
||||||
|
// This assumes that drivers don't create all pipelines in the cache on load time, only
|
||||||
|
// when a lookup occurs that matches a pipeline (or pipeline data) in the cache.
|
||||||
|
m_pipeline_cache_filename = GetDiskShaderCacheFileName(APIType::Vulkan, "Pipeline", false, true);
|
||||||
|
|
||||||
|
VkPipelineCacheCreateInfo info = {
|
||||||
|
VK_STRUCTURE_TYPE_PIPELINE_CACHE_CREATE_INFO, // VkStructureType sType
|
||||||
|
nullptr, // const void* pNext
|
||||||
|
0, // VkPipelineCacheCreateFlags flags
|
||||||
|
0, // size_t initialDataSize
|
||||||
|
nullptr // const void* pInitialData
|
||||||
|
};
|
||||||
|
|
||||||
|
VkResult res =
|
||||||
|
vkCreatePipelineCache(g_vulkan_context->GetDevice(), &info, nullptr, &m_pipeline_cache);
|
||||||
|
if (res == VK_SUCCESS)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
LOG_VULKAN_ERROR(res, "vkCreatePipelineCache failed: ");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ObjectCache::LoadPipelineCache()
|
||||||
{
|
{
|
||||||
// We have to keep the pipeline cache file name around since when we save it
|
// We have to keep the pipeline cache file name around since when we save it
|
||||||
// we delete the old one, by which time the game's unique ID is already cleared.
|
// we delete the old one, by which time the game's unique ID is already cleared.
|
||||||
m_pipeline_cache_filename = GetDiskCacheFileName("pipeline");
|
m_pipeline_cache_filename = GetDiskShaderCacheFileName(APIType::Vulkan, "Pipeline", false, true);
|
||||||
|
|
||||||
std::vector<u8> disk_data;
|
std::vector<u8> disk_data;
|
||||||
if (load_from_disk)
|
LinearDiskCache<u32, u8> disk_cache;
|
||||||
{
|
PipelineCacheReadCallback read_callback(&disk_data);
|
||||||
LinearDiskCache<u32, u8> disk_cache;
|
if (disk_cache.OpenAndRead(m_pipeline_cache_filename, read_callback) != 1)
|
||||||
PipelineCacheReadCallback read_callback(&disk_data);
|
disk_data.clear();
|
||||||
if (disk_cache.OpenAndRead(m_pipeline_cache_filename, read_callback) != 1)
|
|
||||||
disk_data.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!disk_data.empty() && !ValidatePipelineCache(disk_data.data(), disk_data.size()))
|
if (!disk_data.empty() && !ValidatePipelineCache(disk_data.data(), disk_data.size()))
|
||||||
{
|
{
|
||||||
// Don't use this data. In fact, we should delete it to prevent it from being used next time.
|
// Don't use this data. In fact, we should delete it to prevent it from being used next time.
|
||||||
File::Delete(m_pipeline_cache_filename);
|
File::Delete(m_pipeline_cache_filename);
|
||||||
disk_data.clear();
|
return CreatePipelineCache();
|
||||||
}
|
}
|
||||||
|
|
||||||
VkPipelineCacheCreateInfo info = {
|
VkPipelineCacheCreateInfo info = {
|
||||||
|
@ -492,7 +515,7 @@ bool ObjectCache::CreatePipelineCache(bool load_from_disk)
|
||||||
nullptr, // const void* pNext
|
nullptr, // const void* pNext
|
||||||
0, // VkPipelineCacheCreateFlags flags
|
0, // VkPipelineCacheCreateFlags flags
|
||||||
disk_data.size(), // size_t initialDataSize
|
disk_data.size(), // size_t initialDataSize
|
||||||
!disk_data.empty() ? disk_data.data() : nullptr, // const void* pInitialData
|
disk_data.data() // const void* pInitialData
|
||||||
};
|
};
|
||||||
|
|
||||||
VkResult res =
|
VkResult res =
|
||||||
|
@ -502,14 +525,7 @@ bool ObjectCache::CreatePipelineCache(bool load_from_disk)
|
||||||
|
|
||||||
// Failed to create pipeline cache, try with it empty.
|
// Failed to create pipeline cache, try with it empty.
|
||||||
LOG_VULKAN_ERROR(res, "vkCreatePipelineCache failed, trying empty cache: ");
|
LOG_VULKAN_ERROR(res, "vkCreatePipelineCache failed, trying empty cache: ");
|
||||||
info.initialDataSize = 0;
|
return CreatePipelineCache();
|
||||||
info.pInitialData = nullptr;
|
|
||||||
res = vkCreatePipelineCache(g_vulkan_context->GetDevice(), &info, nullptr, &m_pipeline_cache);
|
|
||||||
if (res == VK_SUCCESS)
|
|
||||||
return true;
|
|
||||||
|
|
||||||
LOG_VULKAN_ERROR(res, "vkCreatePipelineCache failed: ");
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Based on Vulkan 1.0 specification,
|
// Based on Vulkan 1.0 specification,
|
||||||
|
@ -644,19 +660,19 @@ struct ShaderCacheReader : public LinearDiskCacheReader<Uid, u32>
|
||||||
|
|
||||||
void ObjectCache::LoadShaderCaches()
|
void ObjectCache::LoadShaderCaches()
|
||||||
{
|
{
|
||||||
if (g_ActiveConfig.bShaderCache)
|
ShaderCacheReader<VertexShaderUid> vs_reader(m_vs_cache.shader_map);
|
||||||
|
m_vs_cache.disk_cache.OpenAndRead(GetDiskShaderCacheFileName(APIType::Vulkan, "VS", true, true),
|
||||||
|
vs_reader);
|
||||||
|
|
||||||
|
ShaderCacheReader<PixelShaderUid> ps_reader(m_ps_cache.shader_map);
|
||||||
|
m_ps_cache.disk_cache.OpenAndRead(GetDiskShaderCacheFileName(APIType::Vulkan, "PS", true, true),
|
||||||
|
ps_reader);
|
||||||
|
|
||||||
|
if (g_vulkan_context->SupportsGeometryShaders())
|
||||||
{
|
{
|
||||||
ShaderCacheReader<VertexShaderUid> vs_reader(m_vs_cache.shader_map);
|
ShaderCacheReader<GeometryShaderUid> gs_reader(m_gs_cache.shader_map);
|
||||||
m_vs_cache.disk_cache.OpenAndRead(GetDiskCacheFileName("vs"), vs_reader);
|
m_gs_cache.disk_cache.OpenAndRead(GetDiskShaderCacheFileName(APIType::Vulkan, "GS", true, true),
|
||||||
|
gs_reader);
|
||||||
ShaderCacheReader<PixelShaderUid> ps_reader(m_ps_cache.shader_map);
|
|
||||||
m_ps_cache.disk_cache.OpenAndRead(GetDiskCacheFileName("ps"), ps_reader);
|
|
||||||
|
|
||||||
if (g_vulkan_context->SupportsGeometryShaders())
|
|
||||||
{
|
|
||||||
ShaderCacheReader<GeometryShaderUid> gs_reader(m_gs_cache.shader_map);
|
|
||||||
m_gs_cache.disk_cache.OpenAndRead(GetDiskCacheFileName("gs"), gs_reader);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
SETSTAT(stats.numPixelShadersCreated, static_cast<int>(m_ps_cache.shader_map.size()));
|
SETSTAT(stats.numPixelShadersCreated, static_cast<int>(m_ps_cache.shader_map.size()));
|
||||||
|
@ -668,6 +684,7 @@ void ObjectCache::LoadShaderCaches()
|
||||||
template <typename T>
|
template <typename T>
|
||||||
static void DestroyShaderCache(T& cache)
|
static void DestroyShaderCache(T& cache)
|
||||||
{
|
{
|
||||||
|
cache.disk_cache.Sync();
|
||||||
cache.disk_cache.Close();
|
cache.disk_cache.Close();
|
||||||
for (const auto& it : cache.shader_map)
|
for (const auto& it : cache.shader_map)
|
||||||
{
|
{
|
||||||
|
@ -684,6 +701,11 @@ void ObjectCache::DestroyShaderCaches()
|
||||||
|
|
||||||
if (g_vulkan_context->SupportsGeometryShaders())
|
if (g_vulkan_context->SupportsGeometryShaders())
|
||||||
DestroyShaderCache(m_gs_cache);
|
DestroyShaderCache(m_gs_cache);
|
||||||
|
|
||||||
|
SETSTAT(stats.numPixelShadersCreated, 0);
|
||||||
|
SETSTAT(stats.numPixelShadersAlive, 0);
|
||||||
|
SETSTAT(stats.numVertexShadersCreated, 0);
|
||||||
|
SETSTAT(stats.numVertexShadersAlive, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
VkShaderModule ObjectCache::GetVertexShaderForUid(const VertexShaderUid& uid)
|
VkShaderModule ObjectCache::GetVertexShaderForUid(const VertexShaderUid& uid)
|
||||||
|
@ -695,7 +717,8 @@ VkShaderModule ObjectCache::GetVertexShaderForUid(const VertexShaderUid& uid)
|
||||||
// Not in the cache, so compile the shader.
|
// Not in the cache, so compile the shader.
|
||||||
ShaderCompiler::SPIRVCodeVector spv;
|
ShaderCompiler::SPIRVCodeVector spv;
|
||||||
VkShaderModule module = VK_NULL_HANDLE;
|
VkShaderModule module = VK_NULL_HANDLE;
|
||||||
ShaderCode source_code = GenerateVertexShaderCode(APIType::Vulkan, uid.GetUidData());
|
ShaderCode source_code =
|
||||||
|
GenerateVertexShaderCode(APIType::Vulkan, ShaderHostConfig::GetCurrent(), uid.GetUidData());
|
||||||
if (ShaderCompiler::CompileVertexShader(&spv, source_code.GetBuffer().c_str(),
|
if (ShaderCompiler::CompileVertexShader(&spv, source_code.GetBuffer().c_str(),
|
||||||
source_code.GetBuffer().length()))
|
source_code.GetBuffer().length()))
|
||||||
{
|
{
|
||||||
|
@ -725,7 +748,8 @@ VkShaderModule ObjectCache::GetGeometryShaderForUid(const GeometryShaderUid& uid
|
||||||
// Not in the cache, so compile the shader.
|
// Not in the cache, so compile the shader.
|
||||||
ShaderCompiler::SPIRVCodeVector spv;
|
ShaderCompiler::SPIRVCodeVector spv;
|
||||||
VkShaderModule module = VK_NULL_HANDLE;
|
VkShaderModule module = VK_NULL_HANDLE;
|
||||||
ShaderCode source_code = GenerateGeometryShaderCode(APIType::Vulkan, uid.GetUidData());
|
ShaderCode source_code =
|
||||||
|
GenerateGeometryShaderCode(APIType::Vulkan, ShaderHostConfig::GetCurrent(), uid.GetUidData());
|
||||||
if (ShaderCompiler::CompileGeometryShader(&spv, source_code.GetBuffer().c_str(),
|
if (ShaderCompiler::CompileGeometryShader(&spv, source_code.GetBuffer().c_str(),
|
||||||
source_code.GetBuffer().length()))
|
source_code.GetBuffer().length()))
|
||||||
{
|
{
|
||||||
|
@ -750,7 +774,8 @@ VkShaderModule ObjectCache::GetPixelShaderForUid(const PixelShaderUid& uid)
|
||||||
// Not in the cache, so compile the shader.
|
// Not in the cache, so compile the shader.
|
||||||
ShaderCompiler::SPIRVCodeVector spv;
|
ShaderCompiler::SPIRVCodeVector spv;
|
||||||
VkShaderModule module = VK_NULL_HANDLE;
|
VkShaderModule module = VK_NULL_HANDLE;
|
||||||
ShaderCode source_code = GeneratePixelShaderCode(APIType::Vulkan, uid.GetUidData());
|
ShaderCode source_code =
|
||||||
|
GeneratePixelShaderCode(APIType::Vulkan, ShaderHostConfig::GetCurrent(), uid.GetUidData());
|
||||||
if (ShaderCompiler::CompileFragmentShader(&spv, source_code.GetBuffer().c_str(),
|
if (ShaderCompiler::CompileFragmentShader(&spv, source_code.GetBuffer().c_str(),
|
||||||
source_code.GetBuffer().length()))
|
source_code.GetBuffer().length()))
|
||||||
{
|
{
|
||||||
|
@ -804,6 +829,23 @@ void ObjectCache::RecompileSharedShaders()
|
||||||
PanicAlert("Failed to recompile shared shaders.");
|
PanicAlert("Failed to recompile shared shaders.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ObjectCache::ReloadShaderAndPipelineCaches()
|
||||||
|
{
|
||||||
|
SavePipelineCache();
|
||||||
|
DestroyShaderCaches();
|
||||||
|
DestroyPipelineCache();
|
||||||
|
|
||||||
|
if (g_ActiveConfig.bShaderCache)
|
||||||
|
{
|
||||||
|
LoadShaderCaches();
|
||||||
|
LoadPipelineCache();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
CreatePipelineCache();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
bool ObjectCache::CreateDescriptorSetLayouts()
|
bool ObjectCache::CreateDescriptorSetLayouts()
|
||||||
{
|
{
|
||||||
static const VkDescriptorSetLayoutBinding ubo_set_bindings[] = {
|
static const VkDescriptorSetLayoutBinding ubo_set_bindings[] = {
|
||||||
|
|
|
@ -154,16 +154,17 @@ public:
|
||||||
// Recompile shared shaders, call when stereo mode changes.
|
// Recompile shared shaders, call when stereo mode changes.
|
||||||
void RecompileSharedShaders();
|
void RecompileSharedShaders();
|
||||||
|
|
||||||
|
// Reload pipeline cache. This will destroy all pipelines.
|
||||||
|
void ReloadShaderAndPipelineCaches();
|
||||||
|
|
||||||
// Shared shader accessors
|
// Shared shader accessors
|
||||||
VkShaderModule GetScreenQuadVertexShader() const { return m_screen_quad_vertex_shader; }
|
VkShaderModule GetScreenQuadVertexShader() const { return m_screen_quad_vertex_shader; }
|
||||||
VkShaderModule GetPassthroughVertexShader() const { return m_passthrough_vertex_shader; }
|
VkShaderModule GetPassthroughVertexShader() const { return m_passthrough_vertex_shader; }
|
||||||
VkShaderModule GetScreenQuadGeometryShader() const { return m_screen_quad_geometry_shader; }
|
VkShaderModule GetScreenQuadGeometryShader() const { return m_screen_quad_geometry_shader; }
|
||||||
VkShaderModule GetPassthroughGeometryShader() const { return m_passthrough_geometry_shader; }
|
VkShaderModule GetPassthroughGeometryShader() const { return m_passthrough_geometry_shader; }
|
||||||
// Gets the filename of the specified type of cache object (e.g. vertex shader, pipeline).
|
|
||||||
std::string GetDiskCacheFileName(const char* type);
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool CreatePipelineCache(bool load_from_disk);
|
bool CreatePipelineCache();
|
||||||
|
bool LoadPipelineCache();
|
||||||
bool ValidatePipelineCache(const u8* data, size_t data_length);
|
bool ValidatePipelineCache(const u8* data, size_t data_length);
|
||||||
void DestroyPipelineCache();
|
void DestroyPipelineCache();
|
||||||
void LoadShaderCaches();
|
void LoadShaderCaches();
|
||||||
|
|
|
@ -114,7 +114,7 @@ bool Renderer::Initialize()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ensure all pipelines previously used by the game have been created.
|
// Ensure all pipelines previously used by the game have been created.
|
||||||
StateTracker::GetInstance()->LoadPipelineUIDCache();
|
StateTracker::GetInstance()->ReloadPipelineUIDCache();
|
||||||
|
|
||||||
// Initialize post processing.
|
// Initialize post processing.
|
||||||
m_post_processor = std::make_unique<VulkanPostProcessing>();
|
m_post_processor = std::make_unique<VulkanPostProcessing>();
|
||||||
|
@ -1126,13 +1126,10 @@ void Renderer::CheckForSurfaceChange()
|
||||||
void Renderer::CheckForConfigChanges()
|
void Renderer::CheckForConfigChanges()
|
||||||
{
|
{
|
||||||
// Save the video config so we can compare against to determine which settings have changed.
|
// Save the video config so we can compare against to determine which settings have changed.
|
||||||
u32 old_multisamples = g_ActiveConfig.iMultisamples;
|
|
||||||
int old_anisotropy = g_ActiveConfig.iMaxAnisotropy;
|
int old_anisotropy = g_ActiveConfig.iMaxAnisotropy;
|
||||||
int old_stereo_mode = g_ActiveConfig.iStereoMode;
|
|
||||||
int old_aspect_ratio = g_ActiveConfig.iAspectRatio;
|
int old_aspect_ratio = g_ActiveConfig.iAspectRatio;
|
||||||
int old_efb_scale = g_ActiveConfig.iEFBScale;
|
int old_efb_scale = g_ActiveConfig.iEFBScale;
|
||||||
bool old_force_filtering = g_ActiveConfig.bForceFiltering;
|
bool old_force_filtering = g_ActiveConfig.bForceFiltering;
|
||||||
bool old_ssaa = g_ActiveConfig.bSSAA;
|
|
||||||
bool old_use_xfb = g_ActiveConfig.bUseXFB;
|
bool old_use_xfb = g_ActiveConfig.bUseXFB;
|
||||||
bool old_use_realxfb = g_ActiveConfig.bUseRealXFB;
|
bool old_use_realxfb = g_ActiveConfig.bUseRealXFB;
|
||||||
|
|
||||||
|
@ -1142,11 +1139,8 @@ void Renderer::CheckForConfigChanges()
|
||||||
UpdateActiveConfig();
|
UpdateActiveConfig();
|
||||||
|
|
||||||
// Determine which (if any) settings have changed.
|
// Determine which (if any) settings have changed.
|
||||||
bool msaa_changed = old_multisamples != g_ActiveConfig.iMultisamples;
|
|
||||||
bool ssaa_changed = old_ssaa != g_ActiveConfig.bSSAA;
|
|
||||||
bool anisotropy_changed = old_anisotropy != g_ActiveConfig.iMaxAnisotropy;
|
bool anisotropy_changed = old_anisotropy != g_ActiveConfig.iMaxAnisotropy;
|
||||||
bool force_texture_filtering_changed = old_force_filtering != g_ActiveConfig.bForceFiltering;
|
bool force_texture_filtering_changed = old_force_filtering != g_ActiveConfig.bForceFiltering;
|
||||||
bool stereo_changed = old_stereo_mode != g_ActiveConfig.iStereoMode;
|
|
||||||
bool efb_scale_changed = old_efb_scale != g_ActiveConfig.iEFBScale;
|
bool efb_scale_changed = old_efb_scale != g_ActiveConfig.iEFBScale;
|
||||||
bool aspect_changed = old_aspect_ratio != g_ActiveConfig.iAspectRatio;
|
bool aspect_changed = old_aspect_ratio != g_ActiveConfig.iAspectRatio;
|
||||||
bool use_xfb_changed = old_use_xfb != g_ActiveConfig.bUseXFB;
|
bool use_xfb_changed = old_use_xfb != g_ActiveConfig.bUseXFB;
|
||||||
|
@ -1164,23 +1158,20 @@ void Renderer::CheckForConfigChanges()
|
||||||
|
|
||||||
// MSAA samples changed, we need to recreate the EFB render pass.
|
// MSAA samples changed, we need to recreate the EFB render pass.
|
||||||
// If the stereoscopy mode changed, we need to recreate the buffers as well.
|
// If the stereoscopy mode changed, we need to recreate the buffers as well.
|
||||||
if (msaa_changed || stereo_changed)
|
// SSAA changed on/off, we have to recompile shaders.
|
||||||
|
// Changing stereoscopy from off<->on also requires shaders to be recompiled.
|
||||||
|
if (CheckForHostConfigChanges())
|
||||||
{
|
{
|
||||||
g_command_buffer_mgr->WaitForGPUIdle();
|
g_command_buffer_mgr->WaitForGPUIdle();
|
||||||
FramebufferManager::GetInstance()->RecreateRenderPass();
|
FramebufferManager::GetInstance()->RecreateRenderPass();
|
||||||
FramebufferManager::GetInstance()->ResizeEFBTextures();
|
FramebufferManager::GetInstance()->ResizeEFBTextures();
|
||||||
BindEFBToStateTracker();
|
BindEFBToStateTracker();
|
||||||
}
|
|
||||||
|
|
||||||
// SSAA changed on/off, we can leave the buffers/render pass, but have to recompile shaders.
|
|
||||||
// Changing stereoscopy from off<->on also requires shaders to be recompiled.
|
|
||||||
if (msaa_changed || ssaa_changed || stereo_changed)
|
|
||||||
{
|
|
||||||
g_command_buffer_mgr->WaitForGPUIdle();
|
|
||||||
RecompileShaders();
|
RecompileShaders();
|
||||||
FramebufferManager::GetInstance()->RecompileShaders();
|
FramebufferManager::GetInstance()->RecompileShaders();
|
||||||
|
g_object_cache->ReloadShaderAndPipelineCaches();
|
||||||
g_object_cache->RecompileSharedShaders();
|
g_object_cache->RecompileSharedShaders();
|
||||||
StateTracker::GetInstance()->LoadPipelineUIDCache();
|
StateTracker::GetInstance()->InvalidateShaderPointers();
|
||||||
|
StateTracker::GetInstance()->ReloadPipelineUIDCache();
|
||||||
}
|
}
|
||||||
|
|
||||||
// For vsync, we need to change the present mode, which means recreating the swap chain.
|
// For vsync, we need to change the present mode, which means recreating the swap chain.
|
||||||
|
|
|
@ -115,7 +115,20 @@ bool StateTracker::Initialize()
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void StateTracker::LoadPipelineUIDCache()
|
void StateTracker::InvalidateShaderPointers()
|
||||||
|
{
|
||||||
|
// Clear UIDs, forcing a false match next time.
|
||||||
|
m_vs_uid = {};
|
||||||
|
m_gs_uid = {};
|
||||||
|
m_ps_uid = {};
|
||||||
|
|
||||||
|
// Invalidate shader pointers.
|
||||||
|
m_pipeline_state.vs = VK_NULL_HANDLE;
|
||||||
|
m_pipeline_state.gs = VK_NULL_HANDLE;
|
||||||
|
m_pipeline_state.ps = VK_NULL_HANDLE;
|
||||||
|
}
|
||||||
|
|
||||||
|
void StateTracker::ReloadPipelineUIDCache()
|
||||||
{
|
{
|
||||||
class PipelineInserter final : public LinearDiskCacheReader<SerializedPipelineUID, u32>
|
class PipelineInserter final : public LinearDiskCacheReader<SerializedPipelineUID, u32>
|
||||||
{
|
{
|
||||||
|
@ -130,12 +143,16 @@ void StateTracker::LoadPipelineUIDCache()
|
||||||
StateTracker* this_ptr;
|
StateTracker* this_ptr;
|
||||||
};
|
};
|
||||||
|
|
||||||
std::string filename = g_object_cache->GetDiskCacheFileName("pipeline-uid");
|
m_uid_cache.Sync();
|
||||||
PipelineInserter inserter(this);
|
m_uid_cache.Close();
|
||||||
|
|
||||||
// OpenAndRead calls Close() first, which will flush all data to disk when reloading.
|
// UID caches don't contain any host state, so use a single uid cache per gameid.
|
||||||
// This assertion must hold true, otherwise data corruption will result.
|
std::string filename = GetDiskShaderCacheFileName(APIType::Vulkan, "PipelineUID", true, false);
|
||||||
m_uid_cache.OpenAndRead(filename, inserter);
|
if (g_ActiveConfig.bShaderCache)
|
||||||
|
{
|
||||||
|
PipelineInserter inserter(this);
|
||||||
|
m_uid_cache.OpenAndRead(filename, inserter);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void StateTracker::AppendToPipelineUIDCache(const PipelineInfo& info)
|
void StateTracker::AppendToPipelineUIDCache(const PipelineInfo& info)
|
||||||
|
@ -873,7 +890,7 @@ VkPipeline StateTracker::GetPipelineAndCacheUID(const PipelineInfo& info)
|
||||||
auto result = g_object_cache->GetPipelineWithCacheResult(info);
|
auto result = g_object_cache->GetPipelineWithCacheResult(info);
|
||||||
|
|
||||||
// Add to the UID cache if it is a new pipeline.
|
// Add to the UID cache if it is a new pipeline.
|
||||||
if (!result.second)
|
if (!result.second && g_ActiveConfig.bShaderCache)
|
||||||
AppendToPipelineUIDCache(info);
|
AppendToPipelineUIDCache(info);
|
||||||
|
|
||||||
return result.first;
|
return result.first;
|
||||||
|
|
|
@ -117,7 +117,10 @@ public:
|
||||||
bool IsWithinRenderArea(s32 x, s32 y, u32 width, u32 height) const;
|
bool IsWithinRenderArea(s32 x, s32 y, u32 width, u32 height) const;
|
||||||
|
|
||||||
// Reloads the UID cache, ensuring all pipelines used by the game so far have been created.
|
// Reloads the UID cache, ensuring all pipelines used by the game so far have been created.
|
||||||
void LoadPipelineUIDCache();
|
void ReloadPipelineUIDCache();
|
||||||
|
|
||||||
|
// Clears shader pointers, ensuring that now-deleted modules are not used.
|
||||||
|
void InvalidateShaderPointers();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// Serialized version of PipelineInfo, used when loading/saving the pipeline UID cache.
|
// Serialized version of PipelineInfo, used when loading/saving the pipeline UID cache.
|
||||||
|
|
|
@ -290,7 +290,8 @@ void VideoBackend::Video_Cleanup()
|
||||||
g_command_buffer_mgr->WaitForGPUIdle();
|
g_command_buffer_mgr->WaitForGPUIdle();
|
||||||
|
|
||||||
// Save all cached pipelines out to disk for next time.
|
// Save all cached pipelines out to disk for next time.
|
||||||
g_object_cache->SavePipelineCache();
|
if (g_ActiveConfig.bShaderCache)
|
||||||
|
g_object_cache->SavePipelineCache();
|
||||||
|
|
||||||
g_perf_query.reset();
|
g_perf_query.reset();
|
||||||
g_texture_cache.reset();
|
g_texture_cache.reset();
|
||||||
|
|
|
@ -29,6 +29,7 @@ set(SRCS
|
||||||
PostProcessing.cpp
|
PostProcessing.cpp
|
||||||
RenderBase.cpp
|
RenderBase.cpp
|
||||||
RenderState.cpp
|
RenderState.cpp
|
||||||
|
ShaderGenCommon.cpp
|
||||||
Statistics.cpp
|
Statistics.cpp
|
||||||
TextureCacheBase.cpp
|
TextureCacheBase.cpp
|
||||||
TextureConfig.cpp
|
TextureConfig.cpp
|
||||||
|
|
|
@ -18,10 +18,12 @@ static const char* primitives_ogl[] = {"points", "lines", "triangles"};
|
||||||
|
|
||||||
static const char* primitives_d3d[] = {"point", "line", "triangle"};
|
static const char* primitives_d3d[] = {"point", "line", "triangle"};
|
||||||
|
|
||||||
template <class T>
|
bool geometry_shader_uid_data::IsPassthrough() const
|
||||||
static void EmitVertex(T& out, const char* vertex, APIType ApiType, bool first_vertex = false);
|
{
|
||||||
template <class T>
|
const bool stereo = g_ActiveConfig.iStereoMode > 0;
|
||||||
static void EndPrimitive(T& out, APIType ApiType);
|
const bool wireframe = g_ActiveConfig.bWireFrame;
|
||||||
|
return primitive_type == PRIMITIVE_TRIANGLES && !stereo && !wireframe;
|
||||||
|
}
|
||||||
|
|
||||||
GeometryShaderUid GetGeometryShaderUid(u32 primitive_type)
|
GeometryShaderUid GetGeometryShaderUid(u32 primitive_type)
|
||||||
{
|
{
|
||||||
|
@ -30,48 +32,51 @@ GeometryShaderUid GetGeometryShaderUid(u32 primitive_type)
|
||||||
memset(uid_data, 0, sizeof(geometry_shader_uid_data));
|
memset(uid_data, 0, sizeof(geometry_shader_uid_data));
|
||||||
|
|
||||||
uid_data->primitive_type = primitive_type;
|
uid_data->primitive_type = primitive_type;
|
||||||
uid_data->wireframe = g_ActiveConfig.bWireFrame;
|
|
||||||
uid_data->msaa = g_ActiveConfig.iMultisamples > 1;
|
|
||||||
uid_data->ssaa = g_ActiveConfig.iMultisamples > 1 && g_ActiveConfig.bSSAA;
|
|
||||||
uid_data->stereo = g_ActiveConfig.iStereoMode > 0;
|
|
||||||
uid_data->numTexGens = xfmem.numTexGen.numTexGens;
|
uid_data->numTexGens = xfmem.numTexGen.numTexGens;
|
||||||
uid_data->pixel_lighting = g_ActiveConfig.bEnablePixelLighting;
|
|
||||||
|
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void EmitVertex(ShaderCode& out, const geometry_shader_uid_data* uid_data,
|
static void EmitVertex(ShaderCode& out, const ShaderHostConfig& host_config,
|
||||||
const char* vertex, APIType ApiType, bool first_vertex = false);
|
const geometry_shader_uid_data* uid_data, const char* vertex,
|
||||||
static void EndPrimitive(ShaderCode& out, const geometry_shader_uid_data* uid_data,
|
APIType ApiType, bool wireframe, bool pixel_lighting,
|
||||||
APIType ApiType);
|
bool first_vertex = false);
|
||||||
|
static void EndPrimitive(ShaderCode& out, const ShaderHostConfig& host_config,
|
||||||
|
const geometry_shader_uid_data* uid_data, APIType ApiType, bool wireframe,
|
||||||
|
bool pixel_lighting);
|
||||||
|
|
||||||
ShaderCode GenerateGeometryShaderCode(APIType ApiType, const geometry_shader_uid_data* uid_data)
|
ShaderCode GenerateGeometryShaderCode(APIType ApiType, const ShaderHostConfig& host_config,
|
||||||
|
const geometry_shader_uid_data* uid_data)
|
||||||
{
|
{
|
||||||
ShaderCode out;
|
ShaderCode out;
|
||||||
// Non-uid template parameters will write to the dummy data (=> gets optimized out)
|
// Non-uid template parameters will write to the dummy data (=> gets optimized out)
|
||||||
|
|
||||||
|
const bool wireframe = host_config.wireframe;
|
||||||
|
const bool pixel_lighting = g_ActiveConfig.bEnablePixelLighting;
|
||||||
|
const bool msaa = host_config.msaa;
|
||||||
|
const bool ssaa = host_config.ssaa;
|
||||||
|
const bool stereo = host_config.stereo;
|
||||||
const unsigned int vertex_in = uid_data->primitive_type + 1;
|
const unsigned int vertex_in = uid_data->primitive_type + 1;
|
||||||
unsigned int vertex_out = uid_data->primitive_type == PRIMITIVE_TRIANGLES ? 3 : 4;
|
unsigned int vertex_out = uid_data->primitive_type == PRIMITIVE_TRIANGLES ? 3 : 4;
|
||||||
|
|
||||||
if (uid_data->wireframe)
|
if (wireframe)
|
||||||
vertex_out++;
|
vertex_out++;
|
||||||
|
|
||||||
if (ApiType == APIType::OpenGL || ApiType == APIType::Vulkan)
|
if (ApiType == APIType::OpenGL || ApiType == APIType::Vulkan)
|
||||||
{
|
{
|
||||||
// Insert layout parameters
|
// Insert layout parameters
|
||||||
if (g_ActiveConfig.backend_info.bSupportsGSInstancing)
|
if (host_config.backend_gs_instancing)
|
||||||
{
|
{
|
||||||
out.Write("layout(%s, invocations = %d) in;\n", primitives_ogl[uid_data->primitive_type],
|
out.Write("layout(%s, invocations = %d) in;\n", primitives_ogl[uid_data->primitive_type],
|
||||||
uid_data->stereo ? 2 : 1);
|
stereo ? 2 : 1);
|
||||||
out.Write("layout(%s_strip, max_vertices = %d) out;\n",
|
out.Write("layout(%s_strip, max_vertices = %d) out;\n", wireframe ? "line" : "triangle",
|
||||||
uid_data->wireframe ? "line" : "triangle", vertex_out);
|
vertex_out);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
out.Write("layout(%s) in;\n", primitives_ogl[uid_data->primitive_type]);
|
out.Write("layout(%s) in;\n", primitives_ogl[uid_data->primitive_type]);
|
||||||
out.Write("layout(%s_strip, max_vertices = %d) out;\n",
|
out.Write("layout(%s_strip, max_vertices = %d) out;\n", wireframe ? "line" : "triangle",
|
||||||
uid_data->wireframe ? "line" : "triangle",
|
stereo ? vertex_out * 2 : vertex_out);
|
||||||
uid_data->stereo ? vertex_out * 2 : vertex_out);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -89,27 +94,24 @@ ShaderCode GenerateGeometryShaderCode(APIType ApiType, const geometry_shader_uid
|
||||||
"};\n");
|
"};\n");
|
||||||
|
|
||||||
out.Write("struct VS_OUTPUT {\n");
|
out.Write("struct VS_OUTPUT {\n");
|
||||||
GenerateVSOutputMembers<ShaderCode>(out, ApiType, uid_data->numTexGens, uid_data->pixel_lighting,
|
GenerateVSOutputMembers<ShaderCode>(out, ApiType, uid_data->numTexGens, pixel_lighting, "");
|
||||||
"");
|
|
||||||
out.Write("};\n");
|
out.Write("};\n");
|
||||||
|
|
||||||
if (ApiType == APIType::OpenGL || ApiType == APIType::Vulkan)
|
if (ApiType == APIType::OpenGL || ApiType == APIType::Vulkan)
|
||||||
{
|
{
|
||||||
if (g_ActiveConfig.backend_info.bSupportsGSInstancing)
|
if (host_config.backend_gs_instancing)
|
||||||
out.Write("#define InstanceID gl_InvocationID\n");
|
out.Write("#define InstanceID gl_InvocationID\n");
|
||||||
|
|
||||||
out.Write("VARYING_LOCATION(0) in VertexData {\n");
|
out.Write("VARYING_LOCATION(0) in VertexData {\n");
|
||||||
GenerateVSOutputMembers<ShaderCode>(
|
GenerateVSOutputMembers<ShaderCode>(out, ApiType, uid_data->numTexGens, pixel_lighting,
|
||||||
out, ApiType, uid_data->numTexGens, uid_data->pixel_lighting,
|
GetInterpolationQualifier(msaa, ssaa, true, true));
|
||||||
GetInterpolationQualifier(uid_data->msaa, uid_data->ssaa, true, true));
|
|
||||||
out.Write("} vs[%d];\n", vertex_in);
|
out.Write("} vs[%d];\n", vertex_in);
|
||||||
|
|
||||||
out.Write("VARYING_LOCATION(0) out VertexData {\n");
|
out.Write("VARYING_LOCATION(0) out VertexData {\n");
|
||||||
GenerateVSOutputMembers<ShaderCode>(
|
GenerateVSOutputMembers<ShaderCode>(out, ApiType, uid_data->numTexGens, pixel_lighting,
|
||||||
out, ApiType, uid_data->numTexGens, uid_data->pixel_lighting,
|
GetInterpolationQualifier(msaa, ssaa, true, false));
|
||||||
GetInterpolationQualifier(uid_data->msaa, uid_data->ssaa, true, false));
|
|
||||||
|
|
||||||
if (uid_data->stereo)
|
if (stereo)
|
||||||
out.Write("\tflat int layer;\n");
|
out.Write("\tflat int layer;\n");
|
||||||
|
|
||||||
out.Write("} ps;\n");
|
out.Write("} ps;\n");
|
||||||
|
@ -121,25 +123,25 @@ ShaderCode GenerateGeometryShaderCode(APIType ApiType, const geometry_shader_uid
|
||||||
out.Write("struct VertexData {\n");
|
out.Write("struct VertexData {\n");
|
||||||
out.Write("\tVS_OUTPUT o;\n");
|
out.Write("\tVS_OUTPUT o;\n");
|
||||||
|
|
||||||
if (uid_data->stereo)
|
if (stereo)
|
||||||
out.Write("\tuint layer : SV_RenderTargetArrayIndex;\n");
|
out.Write("\tuint layer : SV_RenderTargetArrayIndex;\n");
|
||||||
|
|
||||||
out.Write("};\n");
|
out.Write("};\n");
|
||||||
|
|
||||||
if (g_ActiveConfig.backend_info.bSupportsGSInstancing)
|
if (host_config.backend_gs_instancing)
|
||||||
{
|
{
|
||||||
out.Write("[maxvertexcount(%d)]\n[instance(%d)]\n", vertex_out, uid_data->stereo ? 2 : 1);
|
out.Write("[maxvertexcount(%d)]\n[instance(%d)]\n", vertex_out, stereo ? 2 : 1);
|
||||||
out.Write("void main(%s VS_OUTPUT o[%d], inout %sStream<VertexData> output, in uint "
|
out.Write("void main(%s VS_OUTPUT o[%d], inout %sStream<VertexData> output, in uint "
|
||||||
"InstanceID : SV_GSInstanceID)\n{\n",
|
"InstanceID : SV_GSInstanceID)\n{\n",
|
||||||
primitives_d3d[uid_data->primitive_type], vertex_in,
|
primitives_d3d[uid_data->primitive_type], vertex_in,
|
||||||
uid_data->wireframe ? "Line" : "Triangle");
|
wireframe ? "Line" : "Triangle");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
out.Write("[maxvertexcount(%d)]\n", uid_data->stereo ? vertex_out * 2 : vertex_out);
|
out.Write("[maxvertexcount(%d)]\n", stereo ? vertex_out * 2 : vertex_out);
|
||||||
out.Write("void main(%s VS_OUTPUT o[%d], inout %sStream<VertexData> output)\n{\n",
|
out.Write("void main(%s VS_OUTPUT o[%d], inout %sStream<VertexData> output)\n{\n",
|
||||||
primitives_d3d[uid_data->primitive_type], vertex_in,
|
primitives_d3d[uid_data->primitive_type], vertex_in,
|
||||||
uid_data->wireframe ? "Line" : "Triangle");
|
wireframe ? "Line" : "Triangle");
|
||||||
}
|
}
|
||||||
|
|
||||||
out.Write("\tVertexData ps;\n");
|
out.Write("\tVertexData ps;\n");
|
||||||
|
@ -150,8 +152,8 @@ ShaderCode GenerateGeometryShaderCode(APIType ApiType, const geometry_shader_uid
|
||||||
if (ApiType == APIType::OpenGL || ApiType == APIType::Vulkan)
|
if (ApiType == APIType::OpenGL || ApiType == APIType::Vulkan)
|
||||||
{
|
{
|
||||||
out.Write("\tVS_OUTPUT start, end;\n");
|
out.Write("\tVS_OUTPUT start, end;\n");
|
||||||
AssignVSOutputMembers(out, "start", "vs[0]", uid_data->numTexGens, uid_data->pixel_lighting);
|
AssignVSOutputMembers(out, "start", "vs[0]", uid_data->numTexGens, pixel_lighting);
|
||||||
AssignVSOutputMembers(out, "end", "vs[1]", uid_data->numTexGens, uid_data->pixel_lighting);
|
AssignVSOutputMembers(out, "end", "vs[1]", uid_data->numTexGens, pixel_lighting);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -181,7 +183,7 @@ ShaderCode GenerateGeometryShaderCode(APIType ApiType, const geometry_shader_uid
|
||||||
if (ApiType == APIType::OpenGL || ApiType == APIType::Vulkan)
|
if (ApiType == APIType::OpenGL || ApiType == APIType::Vulkan)
|
||||||
{
|
{
|
||||||
out.Write("\tVS_OUTPUT center;\n");
|
out.Write("\tVS_OUTPUT center;\n");
|
||||||
AssignVSOutputMembers(out, "center", "vs[0]", uid_data->numTexGens, uid_data->pixel_lighting);
|
AssignVSOutputMembers(out, "center", "vs[0]", uid_data->numTexGens, pixel_lighting);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -194,17 +196,17 @@ ShaderCode GenerateGeometryShaderCode(APIType ApiType, const geometry_shader_uid
|
||||||
".x, -" I_LINEPTPARAMS ".w / " I_LINEPTPARAMS ".y) * center.pos.w;\n");
|
".x, -" I_LINEPTPARAMS ".w / " I_LINEPTPARAMS ".y) * center.pos.w;\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (uid_data->stereo)
|
if (stereo)
|
||||||
{
|
{
|
||||||
// If the GPU supports invocation we don't need a for loop and can simply use the
|
// 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.
|
// invocation identifier to determine which layer we're rendering.
|
||||||
if (g_ActiveConfig.backend_info.bSupportsGSInstancing)
|
if (host_config.backend_gs_instancing)
|
||||||
out.Write("\tint eye = InstanceID;\n");
|
out.Write("\tint eye = InstanceID;\n");
|
||||||
else
|
else
|
||||||
out.Write("\tfor (int eye = 0; eye < 2; ++eye) {\n");
|
out.Write("\tfor (int eye = 0; eye < 2; ++eye) {\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (uid_data->wireframe)
|
if (wireframe)
|
||||||
out.Write("\tVS_OUTPUT first;\n");
|
out.Write("\tVS_OUTPUT first;\n");
|
||||||
|
|
||||||
out.Write("\tfor (int i = 0; i < %d; ++i) {\n", vertex_in);
|
out.Write("\tfor (int i = 0; i < %d; ++i) {\n", vertex_in);
|
||||||
|
@ -212,9 +214,9 @@ ShaderCode GenerateGeometryShaderCode(APIType ApiType, const geometry_shader_uid
|
||||||
if (ApiType == APIType::OpenGL || ApiType == APIType::Vulkan)
|
if (ApiType == APIType::OpenGL || ApiType == APIType::Vulkan)
|
||||||
{
|
{
|
||||||
out.Write("\tVS_OUTPUT f;\n");
|
out.Write("\tVS_OUTPUT f;\n");
|
||||||
AssignVSOutputMembers(out, "f", "vs[i]", uid_data->numTexGens, uid_data->pixel_lighting);
|
AssignVSOutputMembers(out, "f", "vs[i]", uid_data->numTexGens, pixel_lighting);
|
||||||
|
|
||||||
if (g_ActiveConfig.backend_info.bSupportsDepthClamp &&
|
if (host_config.backend_depth_clamp &&
|
||||||
DriverDetails::HasBug(DriverDetails::BUG_BROKEN_CLIP_DISTANCE))
|
DriverDetails::HasBug(DriverDetails::BUG_BROKEN_CLIP_DISTANCE))
|
||||||
{
|
{
|
||||||
// On certain GPUs we have to consume the clip distance from the vertex shader
|
// On certain GPUs we have to consume the clip distance from the vertex shader
|
||||||
|
@ -228,7 +230,7 @@ ShaderCode GenerateGeometryShaderCode(APIType ApiType, const geometry_shader_uid
|
||||||
out.Write("\tVS_OUTPUT f = o[i];\n");
|
out.Write("\tVS_OUTPUT f = o[i];\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (uid_data->stereo)
|
if (stereo)
|
||||||
{
|
{
|
||||||
// Select the output layer
|
// Select the output layer
|
||||||
out.Write("\tps.layer = eye;\n");
|
out.Write("\tps.layer = eye;\n");
|
||||||
|
@ -264,8 +266,8 @@ ShaderCode GenerateGeometryShaderCode(APIType ApiType, const geometry_shader_uid
|
||||||
}
|
}
|
||||||
out.Write("\t}\n");
|
out.Write("\t}\n");
|
||||||
|
|
||||||
EmitVertex(out, uid_data, "l", ApiType, true);
|
EmitVertex(out, host_config, uid_data, "l", ApiType, wireframe, pixel_lighting, true);
|
||||||
EmitVertex(out, uid_data, "r", ApiType);
|
EmitVertex(out, host_config, uid_data, "r", ApiType, wireframe, pixel_lighting);
|
||||||
}
|
}
|
||||||
else if (uid_data->primitive_type == PRIMITIVE_POINTS)
|
else if (uid_data->primitive_type == PRIMITIVE_POINTS)
|
||||||
{
|
{
|
||||||
|
@ -293,21 +295,21 @@ ShaderCode GenerateGeometryShaderCode(APIType ApiType, const geometry_shader_uid
|
||||||
}
|
}
|
||||||
out.Write("\t}\n");
|
out.Write("\t}\n");
|
||||||
|
|
||||||
EmitVertex(out, uid_data, "ll", ApiType, true);
|
EmitVertex(out, host_config, uid_data, "ll", ApiType, wireframe, pixel_lighting, true);
|
||||||
EmitVertex(out, uid_data, "lr", ApiType);
|
EmitVertex(out, host_config, uid_data, "lr", ApiType, wireframe, pixel_lighting);
|
||||||
EmitVertex(out, uid_data, "ul", ApiType);
|
EmitVertex(out, host_config, uid_data, "ul", ApiType, wireframe, pixel_lighting);
|
||||||
EmitVertex(out, uid_data, "ur", ApiType);
|
EmitVertex(out, host_config, uid_data, "ur", ApiType, wireframe, pixel_lighting);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
EmitVertex(out, uid_data, "f", ApiType, true);
|
EmitVertex(out, host_config, uid_data, "f", ApiType, wireframe, pixel_lighting, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
out.Write("\t}\n");
|
out.Write("\t}\n");
|
||||||
|
|
||||||
EndPrimitive(out, uid_data, ApiType);
|
EndPrimitive(out, host_config, uid_data, ApiType, wireframe, pixel_lighting);
|
||||||
|
|
||||||
if (uid_data->stereo && !g_ActiveConfig.backend_info.bSupportsGSInstancing)
|
if (stereo && !host_config.backend_gs_instancing)
|
||||||
out.Write("\t}\n");
|
out.Write("\t}\n");
|
||||||
|
|
||||||
out.Write("}\n");
|
out.Write("}\n");
|
||||||
|
@ -315,28 +317,29 @@ ShaderCode GenerateGeometryShaderCode(APIType ApiType, const geometry_shader_uid
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void EmitVertex(ShaderCode& out, const geometry_shader_uid_data* uid_data,
|
static void EmitVertex(ShaderCode& out, const ShaderHostConfig& host_config,
|
||||||
const char* vertex, APIType ApiType, bool first_vertex)
|
const geometry_shader_uid_data* uid_data, const char* vertex,
|
||||||
|
APIType ApiType, bool wireframe, bool pixel_lighting, bool first_vertex)
|
||||||
{
|
{
|
||||||
if (uid_data->wireframe && first_vertex)
|
if (wireframe && first_vertex)
|
||||||
out.Write("\tif (i == 0) first = %s;\n", vertex);
|
out.Write("\tif (i == 0) first = %s;\n", vertex);
|
||||||
|
|
||||||
if (ApiType == APIType::OpenGL)
|
if (ApiType == APIType::OpenGL)
|
||||||
{
|
{
|
||||||
out.Write("\tgl_Position = %s.pos;\n", vertex);
|
out.Write("\tgl_Position = %s.pos;\n", vertex);
|
||||||
if (g_ActiveConfig.backend_info.bSupportsDepthClamp)
|
if (host_config.backend_depth_clamp)
|
||||||
{
|
{
|
||||||
out.Write("\tgl_ClipDistance[0] = %s.clipDist0;\n", vertex);
|
out.Write("\tgl_ClipDistance[0] = %s.clipDist0;\n", vertex);
|
||||||
out.Write("\tgl_ClipDistance[1] = %s.clipDist1;\n", vertex);
|
out.Write("\tgl_ClipDistance[1] = %s.clipDist1;\n", vertex);
|
||||||
}
|
}
|
||||||
AssignVSOutputMembers(out, "ps", vertex, uid_data->numTexGens, uid_data->pixel_lighting);
|
AssignVSOutputMembers(out, "ps", vertex, uid_data->numTexGens, pixel_lighting);
|
||||||
}
|
}
|
||||||
else if (ApiType == APIType::Vulkan)
|
else if (ApiType == APIType::Vulkan)
|
||||||
{
|
{
|
||||||
// Vulkan NDC space has Y pointing down (right-handed NDC space).
|
// Vulkan NDC space has Y pointing down (right-handed NDC space).
|
||||||
out.Write("\tgl_Position = %s.pos;\n", vertex);
|
out.Write("\tgl_Position = %s.pos;\n", vertex);
|
||||||
out.Write("\tgl_Position.y = -gl_Position.y;\n");
|
out.Write("\tgl_Position.y = -gl_Position.y;\n");
|
||||||
AssignVSOutputMembers(out, "ps", vertex, uid_data->numTexGens, uid_data->pixel_lighting);
|
AssignVSOutputMembers(out, "ps", vertex, uid_data->numTexGens, pixel_lighting);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -349,10 +352,12 @@ static void EmitVertex(ShaderCode& out, const geometry_shader_uid_data* uid_data
|
||||||
out.Write("\toutput.Append(ps);\n");
|
out.Write("\toutput.Append(ps);\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
static void EndPrimitive(ShaderCode& out, const geometry_shader_uid_data* uid_data, APIType ApiType)
|
static void EndPrimitive(ShaderCode& out, const ShaderHostConfig& host_config,
|
||||||
|
const geometry_shader_uid_data* uid_data, APIType ApiType, bool wireframe,
|
||||||
|
bool pixel_lighting)
|
||||||
{
|
{
|
||||||
if (uid_data->wireframe)
|
if (wireframe)
|
||||||
EmitVertex(out, uid_data, "first", ApiType);
|
EmitVertex(out, host_config, uid_data, "first", ApiType, wireframe, pixel_lighting);
|
||||||
|
|
||||||
if (ApiType == APIType::OpenGL || ApiType == APIType::Vulkan)
|
if (ApiType == APIType::OpenGL || ApiType == APIType::Vulkan)
|
||||||
out.Write("\tEndPrimitive();\n");
|
out.Write("\tEndPrimitive();\n");
|
||||||
|
|
|
@ -15,23 +15,16 @@ enum class APIType;
|
||||||
struct geometry_shader_uid_data
|
struct geometry_shader_uid_data
|
||||||
{
|
{
|
||||||
u32 NumValues() const { return sizeof(geometry_shader_uid_data); }
|
u32 NumValues() const { return sizeof(geometry_shader_uid_data); }
|
||||||
bool IsPassthrough() const
|
bool IsPassthrough() const;
|
||||||
{
|
|
||||||
return primitive_type == PRIMITIVE_TRIANGLES && !stereo && !wireframe;
|
|
||||||
}
|
|
||||||
|
|
||||||
u32 stereo : 1;
|
|
||||||
u32 numTexGens : 4;
|
u32 numTexGens : 4;
|
||||||
u32 pixel_lighting : 1;
|
|
||||||
u32 primitive_type : 2;
|
u32 primitive_type : 2;
|
||||||
u32 wireframe : 1;
|
|
||||||
u32 msaa : 1;
|
|
||||||
u32 ssaa : 1;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#pragma pack()
|
#pragma pack()
|
||||||
|
|
||||||
typedef ShaderUid<geometry_shader_uid_data> GeometryShaderUid;
|
typedef ShaderUid<geometry_shader_uid_data> GeometryShaderUid;
|
||||||
|
|
||||||
ShaderCode GenerateGeometryShaderCode(APIType ApiType, const geometry_shader_uid_data* uid_data);
|
ShaderCode GenerateGeometryShaderCode(APIType ApiType, const ShaderHostConfig& host_config,
|
||||||
|
const geometry_shader_uid_data* uid_data);
|
||||||
GeometryShaderUid GetGeometryShaderUid(u32 primitive_type);
|
GeometryShaderUid GetGeometryShaderUid(u32 primitive_type);
|
||||||
|
|
|
@ -170,7 +170,6 @@ PixelShaderUid GetPixelShaderUid()
|
||||||
uid_data->genMode_numindstages = bpmem.genMode.numindstages;
|
uid_data->genMode_numindstages = bpmem.genMode.numindstages;
|
||||||
uid_data->genMode_numtevstages = bpmem.genMode.numtevstages;
|
uid_data->genMode_numtevstages = bpmem.genMode.numtevstages;
|
||||||
uid_data->genMode_numtexgens = bpmem.genMode.numtexgens;
|
uid_data->genMode_numtexgens = bpmem.genMode.numtexgens;
|
||||||
uid_data->per_pixel_lighting = g_ActiveConfig.bEnablePixelLighting;
|
|
||||||
uid_data->bounding_box = g_ActiveConfig.BBoxUseFragmentShaderImplementation() &&
|
uid_data->bounding_box = g_ActiveConfig.BBoxUseFragmentShaderImplementation() &&
|
||||||
g_ActiveConfig.bBBoxEnable && BoundingBox::active;
|
g_ActiveConfig.bBBoxEnable && BoundingBox::active;
|
||||||
uid_data->rgba6_format =
|
uid_data->rgba6_format =
|
||||||
|
@ -192,13 +191,9 @@ PixelShaderUid GetPixelShaderUid()
|
||||||
|
|
||||||
uid_data->per_pixel_depth = per_pixel_depth;
|
uid_data->per_pixel_depth = per_pixel_depth;
|
||||||
uid_data->forced_early_z = forced_early_z;
|
uid_data->forced_early_z = forced_early_z;
|
||||||
uid_data->fast_depth_calc = g_ActiveConfig.bFastDepthCalc;
|
|
||||||
uid_data->msaa = g_ActiveConfig.iMultisamples > 1;
|
|
||||||
uid_data->ssaa = g_ActiveConfig.iMultisamples > 1 && g_ActiveConfig.bSSAA;
|
|
||||||
uid_data->stereo = g_ActiveConfig.iStereoMode > 0;
|
|
||||||
|
|
||||||
if (!uid_data->forced_early_z && bpmem.UseEarlyDepthTest() &&
|
if (!uid_data->forced_early_z && bpmem.UseEarlyDepthTest() &&
|
||||||
(!uid_data->fast_depth_calc || bpmem.alpha_test.TestResult() == AlphaTest::UNDETERMINED))
|
(!g_ActiveConfig.bFastDepthCalc || bpmem.alpha_test.TestResult() == AlphaTest::UNDETERMINED))
|
||||||
{
|
{
|
||||||
static bool warn_once = true;
|
static bool warn_once = true;
|
||||||
if (warn_once)
|
if (warn_once)
|
||||||
|
@ -209,7 +204,7 @@ PixelShaderUid GetPixelShaderUid()
|
||||||
warn_once = false;
|
warn_once = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (uid_data->per_pixel_lighting)
|
if (g_ActiveConfig.bEnablePixelLighting)
|
||||||
{
|
{
|
||||||
// The lighting shader only needs the two color bits of the 23bit component bit array.
|
// The lighting shader only needs the two color bits of the 23bit component bit array.
|
||||||
uid_data->components =
|
uid_data->components =
|
||||||
|
@ -297,7 +292,7 @@ PixelShaderUid GetPixelShaderUid()
|
||||||
}
|
}
|
||||||
|
|
||||||
#define MY_STRUCT_OFFSET(str, elem) ((u32)((u64) & (str).elem - (u64) & (str)))
|
#define MY_STRUCT_OFFSET(str, elem) ((u32)((u64) & (str).elem - (u64) & (str)))
|
||||||
uid_data->num_values = (uid_data->per_pixel_lighting) ?
|
uid_data->num_values = (g_ActiveConfig.bEnablePixelLighting) ?
|
||||||
sizeof(*uid_data) :
|
sizeof(*uid_data) :
|
||||||
MY_STRUCT_OFFSET(*uid_data, stagehash[numStages]);
|
MY_STRUCT_OFFSET(*uid_data, stagehash[numStages]);
|
||||||
|
|
||||||
|
@ -339,7 +334,7 @@ PixelShaderUid GetPixelShaderUid()
|
||||||
}
|
}
|
||||||
|
|
||||||
static void WriteStage(ShaderCode& out, const pixel_shader_uid_data* uid_data, int n,
|
static void WriteStage(ShaderCode& out, const pixel_shader_uid_data* uid_data, int n,
|
||||||
APIType ApiType);
|
APIType ApiType, bool stereo);
|
||||||
static void WriteTevRegular(ShaderCode& out, const char* components, int bias, int op, int clamp,
|
static void WriteTevRegular(ShaderCode& out, const char* components, int bias, int op, int clamp,
|
||||||
int shift, bool alpha);
|
int shift, bool alpha);
|
||||||
static void SampleTexture(ShaderCode& out, const char* texcoords, const char* texswap, int texmap,
|
static void SampleTexture(ShaderCode& out, const char* texcoords, const char* texswap, int texmap,
|
||||||
|
@ -350,11 +345,16 @@ static void WriteFog(ShaderCode& out, const pixel_shader_uid_data* uid_data);
|
||||||
static void WriteColor(ShaderCode& out, const pixel_shader_uid_data* uid_data,
|
static void WriteColor(ShaderCode& out, const pixel_shader_uid_data* uid_data,
|
||||||
bool use_dual_source);
|
bool use_dual_source);
|
||||||
|
|
||||||
ShaderCode GeneratePixelShaderCode(APIType ApiType, const pixel_shader_uid_data* uid_data)
|
ShaderCode GeneratePixelShaderCode(APIType ApiType, const ShaderHostConfig& host_config,
|
||||||
|
const pixel_shader_uid_data* uid_data)
|
||||||
{
|
{
|
||||||
ShaderCode out;
|
ShaderCode out;
|
||||||
|
|
||||||
u32 numStages = uid_data->genMode_numtevstages + 1;
|
const bool per_pixel_lighting = g_ActiveConfig.bEnablePixelLighting;
|
||||||
|
const bool msaa = host_config.msaa;
|
||||||
|
const bool ssaa = host_config.ssaa;
|
||||||
|
const bool stereo = host_config.stereo;
|
||||||
|
const u32 numStages = uid_data->genMode_numtevstages + 1;
|
||||||
|
|
||||||
out.Write("//Pixel Shader for TEV stages\n");
|
out.Write("//Pixel Shader for TEV stages\n");
|
||||||
out.Write("//%i TEV stages, %i texgens, %i IND stages\n", numStages, uid_data->genMode_numtexgens,
|
out.Write("//%i TEV stages, %i texgens, %i IND stages\n", numStages, uid_data->genMode_numtexgens,
|
||||||
|
@ -422,7 +422,7 @@ ShaderCode GeneratePixelShaderCode(APIType ApiType, const pixel_shader_uid_data*
|
||||||
"\tfloat4 " I_EFBSCALE ";\n"
|
"\tfloat4 " I_EFBSCALE ";\n"
|
||||||
"};\n");
|
"};\n");
|
||||||
|
|
||||||
if (uid_data->per_pixel_lighting)
|
if (per_pixel_lighting)
|
||||||
{
|
{
|
||||||
out.Write("%s", s_lighting_struct);
|
out.Write("%s", s_lighting_struct);
|
||||||
|
|
||||||
|
@ -450,8 +450,7 @@ ShaderCode GeneratePixelShaderCode(APIType ApiType, const pixel_shader_uid_data*
|
||||||
}
|
}
|
||||||
|
|
||||||
out.Write("struct VS_OUTPUT {\n");
|
out.Write("struct VS_OUTPUT {\n");
|
||||||
GenerateVSOutputMembers(out, ApiType, uid_data->genMode_numtexgens, uid_data->per_pixel_lighting,
|
GenerateVSOutputMembers(out, ApiType, uid_data->genMode_numtexgens, per_pixel_lighting, "");
|
||||||
"");
|
|
||||||
out.Write("};\n");
|
out.Write("};\n");
|
||||||
|
|
||||||
if (uid_data->forced_early_z)
|
if (uid_data->forced_early_z)
|
||||||
|
@ -503,7 +502,7 @@ ShaderCode GeneratePixelShaderCode(APIType ApiType, const pixel_shader_uid_data*
|
||||||
|
|
||||||
// Only use dual-source blending when required on drivers that don't support it very well.
|
// Only use dual-source blending when required on drivers that don't support it very well.
|
||||||
const bool use_dual_source =
|
const bool use_dual_source =
|
||||||
g_ActiveConfig.backend_info.bSupportsDualSourceBlend &&
|
host_config.backend_dual_source_blend &&
|
||||||
(!DriverDetails::HasBug(DriverDetails::BUG_BROKEN_DUAL_SOURCE_BLENDING) ||
|
(!DriverDetails::HasBug(DriverDetails::BUG_BROKEN_DUAL_SOURCE_BLENDING) ||
|
||||||
uid_data->useDstAlpha);
|
uid_data->useDstAlpha);
|
||||||
|
|
||||||
|
@ -531,45 +530,38 @@ ShaderCode GeneratePixelShaderCode(APIType ApiType, const pixel_shader_uid_data*
|
||||||
out.Write("#define depth gl_FragDepth\n");
|
out.Write("#define depth gl_FragDepth\n");
|
||||||
|
|
||||||
// We need to always use output blocks for Vulkan, but geometry shaders are also optional.
|
// We need to always use output blocks for Vulkan, but geometry shaders are also optional.
|
||||||
if (g_ActiveConfig.backend_info.bSupportsGeometryShaders || ApiType == APIType::Vulkan)
|
if (host_config.backend_geometry_shaders || ApiType == APIType::Vulkan)
|
||||||
{
|
{
|
||||||
out.Write("VARYING_LOCATION(0) in VertexData {\n");
|
out.Write("VARYING_LOCATION(0) in VertexData {\n");
|
||||||
GenerateVSOutputMembers(
|
GenerateVSOutputMembers(out, ApiType, uid_data->genMode_numtexgens, per_pixel_lighting,
|
||||||
out, ApiType, uid_data->genMode_numtexgens, uid_data->per_pixel_lighting,
|
GetInterpolationQualifier(msaa, ssaa, true, true));
|
||||||
GetInterpolationQualifier(uid_data->msaa, uid_data->ssaa, true, true));
|
|
||||||
|
|
||||||
if (uid_data->stereo)
|
if (stereo)
|
||||||
out.Write("\tflat int layer;\n");
|
out.Write("\tflat int layer;\n");
|
||||||
|
|
||||||
out.Write("};\n");
|
out.Write("};\n");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
out.Write("%s in float4 colors_0;\n",
|
out.Write("%s in float4 colors_0;\n", GetInterpolationQualifier(msaa, ssaa));
|
||||||
GetInterpolationQualifier(uid_data->msaa, uid_data->ssaa));
|
out.Write("%s in float4 colors_1;\n", GetInterpolationQualifier(msaa, ssaa));
|
||||||
out.Write("%s in float4 colors_1;\n",
|
|
||||||
GetInterpolationQualifier(uid_data->msaa, uid_data->ssaa));
|
|
||||||
// compute window position if needed because binding semantic WPOS is not widely supported
|
// compute window position if needed because binding semantic WPOS is not widely supported
|
||||||
// Let's set up attributes
|
// Let's set up attributes
|
||||||
for (unsigned int i = 0; i < uid_data->genMode_numtexgens; ++i)
|
for (unsigned int i = 0; i < uid_data->genMode_numtexgens; ++i)
|
||||||
{
|
{
|
||||||
out.Write("%s in float3 uv%d;\n", GetInterpolationQualifier(uid_data->msaa, uid_data->ssaa),
|
out.Write("%s in float3 uv%d;\n", GetInterpolationQualifier(msaa, ssaa), i);
|
||||||
i);
|
|
||||||
}
|
}
|
||||||
out.Write("%s in float4 clipPos;\n",
|
out.Write("%s in float4 clipPos;\n", GetInterpolationQualifier(msaa, ssaa));
|
||||||
GetInterpolationQualifier(uid_data->msaa, uid_data->ssaa));
|
if (per_pixel_lighting)
|
||||||
if (uid_data->per_pixel_lighting)
|
|
||||||
{
|
{
|
||||||
out.Write("%s in float3 Normal;\n",
|
out.Write("%s in float3 Normal;\n", GetInterpolationQualifier(msaa, ssaa));
|
||||||
GetInterpolationQualifier(uid_data->msaa, uid_data->ssaa));
|
out.Write("%s in float3 WorldPos;\n", GetInterpolationQualifier(msaa, ssaa));
|
||||||
out.Write("%s in float3 WorldPos;\n",
|
|
||||||
GetInterpolationQualifier(uid_data->msaa, uid_data->ssaa));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
out.Write("void main()\n{\n");
|
out.Write("void main()\n{\n");
|
||||||
|
|
||||||
if (g_ActiveConfig.backend_info.bSupportsGeometryShaders || ApiType == APIType::Vulkan)
|
if (host_config.backend_geometry_shaders || ApiType == APIType::Vulkan)
|
||||||
{
|
{
|
||||||
for (unsigned int i = 0; i < uid_data->genMode_numtexgens; ++i)
|
for (unsigned int i = 0; i < uid_data->genMode_numtexgens; ++i)
|
||||||
out.Write("\tfloat3 uv%d = tex%d;\n", i, i);
|
out.Write("\tfloat3 uv%d = tex%d;\n", i, i);
|
||||||
|
@ -585,30 +577,24 @@ ShaderCode GeneratePixelShaderCode(APIType ApiType, const pixel_shader_uid_data*
|
||||||
" in float4 rawpos : SV_Position,\n",
|
" in float4 rawpos : SV_Position,\n",
|
||||||
uid_data->per_pixel_depth ? " out float depth : SV_Depth,\n" : "");
|
uid_data->per_pixel_depth ? " out float depth : SV_Depth,\n" : "");
|
||||||
|
|
||||||
out.Write(" in %s float4 colors_0 : COLOR0,\n",
|
out.Write(" in %s float4 colors_0 : COLOR0,\n", GetInterpolationQualifier(msaa, ssaa));
|
||||||
GetInterpolationQualifier(uid_data->msaa, uid_data->ssaa));
|
out.Write(" in %s float4 colors_1 : COLOR1\n", GetInterpolationQualifier(msaa, ssaa));
|
||||||
out.Write(" in %s float4 colors_1 : COLOR1\n",
|
|
||||||
GetInterpolationQualifier(uid_data->msaa, uid_data->ssaa));
|
|
||||||
|
|
||||||
// compute window position if needed because binding semantic WPOS is not widely supported
|
// compute window position if needed because binding semantic WPOS is not widely supported
|
||||||
for (unsigned int i = 0; i < uid_data->genMode_numtexgens; ++i)
|
for (unsigned int i = 0; i < uid_data->genMode_numtexgens; ++i)
|
||||||
out.Write(",\n in %s float3 uv%d : TEXCOORD%d",
|
out.Write(",\n in %s float3 uv%d : TEXCOORD%d", GetInterpolationQualifier(msaa, ssaa), i, i);
|
||||||
GetInterpolationQualifier(uid_data->msaa, uid_data->ssaa), i, i);
|
out.Write(",\n in %s float4 clipPos : TEXCOORD%d", GetInterpolationQualifier(msaa, ssaa),
|
||||||
out.Write(",\n in %s float4 clipPos : TEXCOORD%d",
|
|
||||||
GetInterpolationQualifier(uid_data->msaa, uid_data->ssaa),
|
|
||||||
uid_data->genMode_numtexgens);
|
uid_data->genMode_numtexgens);
|
||||||
if (uid_data->per_pixel_lighting)
|
if (per_pixel_lighting)
|
||||||
{
|
{
|
||||||
out.Write(",\n in %s float3 Normal : TEXCOORD%d",
|
out.Write(",\n in %s float3 Normal : TEXCOORD%d", GetInterpolationQualifier(msaa, ssaa),
|
||||||
GetInterpolationQualifier(uid_data->msaa, uid_data->ssaa),
|
|
||||||
uid_data->genMode_numtexgens + 1);
|
uid_data->genMode_numtexgens + 1);
|
||||||
out.Write(",\n in %s float3 WorldPos : TEXCOORD%d",
|
out.Write(",\n in %s float3 WorldPos : TEXCOORD%d", GetInterpolationQualifier(msaa, ssaa),
|
||||||
GetInterpolationQualifier(uid_data->msaa, uid_data->ssaa),
|
|
||||||
uid_data->genMode_numtexgens + 2);
|
uid_data->genMode_numtexgens + 2);
|
||||||
}
|
}
|
||||||
out.Write(",\n in float clipDist0 : SV_ClipDistance0\n");
|
out.Write(",\n in float clipDist0 : SV_ClipDistance0\n");
|
||||||
out.Write(",\n in float clipDist1 : SV_ClipDistance1\n");
|
out.Write(",\n in float clipDist1 : SV_ClipDistance1\n");
|
||||||
if (uid_data->stereo)
|
if (stereo)
|
||||||
out.Write(",\n in uint layer : SV_RenderTargetArrayIndex\n");
|
out.Write(",\n in uint layer : SV_RenderTargetArrayIndex\n");
|
||||||
out.Write(" ) {\n");
|
out.Write(" ) {\n");
|
||||||
}
|
}
|
||||||
|
@ -630,7 +616,7 @@ ShaderCode GeneratePixelShaderCode(APIType ApiType, const pixel_shader_uid_data*
|
||||||
out.Write("\tfloat4 col0 = colors_0;\n");
|
out.Write("\tfloat4 col0 = colors_0;\n");
|
||||||
out.Write("\tfloat4 col1 = colors_1;\n");
|
out.Write("\tfloat4 col1 = colors_1;\n");
|
||||||
|
|
||||||
if (uid_data->per_pixel_lighting)
|
if (per_pixel_lighting)
|
||||||
{
|
{
|
||||||
out.Write("\tfloat3 _norm0 = normalize(Normal.xyz);\n\n");
|
out.Write("\tfloat3 _norm0 = normalize(Normal.xyz);\n\n");
|
||||||
out.Write("\tfloat3 pos = WorldPos;\n");
|
out.Write("\tfloat3 pos = WorldPos;\n");
|
||||||
|
@ -682,12 +668,12 @@ ShaderCode GeneratePixelShaderCode(APIType ApiType, const pixel_shader_uid_data*
|
||||||
out.Write("\ttempcoord = int2(0, 0);\n");
|
out.Write("\ttempcoord = int2(0, 0);\n");
|
||||||
|
|
||||||
out.Write("\tint3 iindtex%d = ", i);
|
out.Write("\tint3 iindtex%d = ", i);
|
||||||
SampleTexture(out, "float2(tempcoord)", "abg", texmap, uid_data->stereo, ApiType);
|
SampleTexture(out, "float2(tempcoord)", "abg", texmap, stereo, ApiType);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (unsigned int i = 0; i < numStages; i++)
|
for (unsigned int i = 0; i < numStages; i++)
|
||||||
WriteStage(out, uid_data, i, ApiType); // build the equation for this stage
|
WriteStage(out, uid_data, i, ApiType, stereo); // build the equation for this stage
|
||||||
|
|
||||||
{
|
{
|
||||||
// The results of the last texenv stage are put onto the screen,
|
// The results of the last texenv stage are put onto the screen,
|
||||||
|
@ -728,7 +714,7 @@ ShaderCode GeneratePixelShaderCode(APIType ApiType, const pixel_shader_uid_data*
|
||||||
out.Write("\tint zCoord = int(" I_ZSLOPE ".z + " I_ZSLOPE ".x * screenpos.x + " I_ZSLOPE
|
out.Write("\tint zCoord = int(" I_ZSLOPE ".z + " I_ZSLOPE ".x * screenpos.x + " I_ZSLOPE
|
||||||
".y * screenpos.y);\n");
|
".y * screenpos.y);\n");
|
||||||
}
|
}
|
||||||
else if (!uid_data->fast_depth_calc)
|
else if (!host_config.fast_depth_calc)
|
||||||
{
|
{
|
||||||
// FastDepth means to trust the depth generated in perspective division.
|
// FastDepth means to trust the depth generated in perspective division.
|
||||||
// It should be correct, but it seems not to be as accurate as required. TODO: Find out why!
|
// It should be correct, but it seems not to be as accurate as required. TODO: Find out why!
|
||||||
|
@ -814,7 +800,7 @@ ShaderCode GeneratePixelShaderCode(APIType ApiType, const pixel_shader_uid_data*
|
||||||
}
|
}
|
||||||
|
|
||||||
static void WriteStage(ShaderCode& out, const pixel_shader_uid_data* uid_data, int n,
|
static void WriteStage(ShaderCode& out, const pixel_shader_uid_data* uid_data, int n,
|
||||||
APIType ApiType)
|
APIType ApiType, bool stereo)
|
||||||
{
|
{
|
||||||
auto& stage = uid_data->stagehash[n];
|
auto& stage = uid_data->stagehash[n];
|
||||||
out.Write("\n\t// TEV stage %d\n", n);
|
out.Write("\n\t// TEV stage %d\n", n);
|
||||||
|
@ -1013,8 +999,7 @@ static void WriteStage(ShaderCode& out, const pixel_shader_uid_data* uid_data, i
|
||||||
out.Write("\ttevcoord.xy = int2(0, 0);\n");
|
out.Write("\ttevcoord.xy = int2(0, 0);\n");
|
||||||
}
|
}
|
||||||
out.Write("\ttextemp = ");
|
out.Write("\ttextemp = ");
|
||||||
SampleTexture(out, "float2(tevcoord.xy)", texswap, stage.tevorders_texmap, uid_data->stereo,
|
SampleTexture(out, "float2(tevcoord.xy)", texswap, stage.tevorders_texmap, stereo, ApiType);
|
||||||
ApiType);
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
|
@ -18,11 +18,10 @@ struct pixel_shader_uid_data
|
||||||
u32 num_values; // TODO: Shouldn't be a u32
|
u32 num_values; // TODO: Shouldn't be a u32
|
||||||
u32 NumValues() const { return num_values; }
|
u32 NumValues() const { return num_values; }
|
||||||
u32 components : 2;
|
u32 components : 2;
|
||||||
u32 pad0 : 1;
|
u32 pad0 : 2;
|
||||||
u32 useDstAlpha : 1;
|
u32 useDstAlpha : 1;
|
||||||
u32 Pretest : 2;
|
u32 Pretest : 2;
|
||||||
u32 nIndirectStagesUsed : 4;
|
u32 nIndirectStagesUsed : 4;
|
||||||
u32 stereo : 1;
|
|
||||||
u32 genMode_numtexgens : 4;
|
u32 genMode_numtexgens : 4;
|
||||||
u32 genMode_numtevstages : 4;
|
u32 genMode_numtevstages : 4;
|
||||||
u32 genMode_numindstages : 3;
|
u32 genMode_numindstages : 3;
|
||||||
|
@ -35,20 +34,16 @@ struct pixel_shader_uid_data
|
||||||
u32 fog_fsel : 3;
|
u32 fog_fsel : 3;
|
||||||
u32 fog_RangeBaseEnabled : 1;
|
u32 fog_RangeBaseEnabled : 1;
|
||||||
u32 ztex_op : 2;
|
u32 ztex_op : 2;
|
||||||
u32 fast_depth_calc : 1;
|
|
||||||
u32 per_pixel_depth : 1;
|
u32 per_pixel_depth : 1;
|
||||||
u32 per_pixel_lighting : 1;
|
|
||||||
u32 forced_early_z : 1;
|
u32 forced_early_z : 1;
|
||||||
u32 early_ztest : 1;
|
u32 early_ztest : 1;
|
||||||
u32 late_ztest : 1;
|
u32 late_ztest : 1;
|
||||||
u32 bounding_box : 1;
|
u32 bounding_box : 1;
|
||||||
u32 zfreeze : 1;
|
u32 zfreeze : 1;
|
||||||
u32 msaa : 1;
|
|
||||||
u32 ssaa : 1;
|
|
||||||
u32 numColorChans : 2;
|
u32 numColorChans : 2;
|
||||||
u32 rgba6_format : 1;
|
u32 rgba6_format : 1;
|
||||||
u32 dither : 1;
|
u32 dither : 1;
|
||||||
u32 pad : 12;
|
u32 pad : 16;
|
||||||
|
|
||||||
u32 texMtxInfo_n_projection : 8; // 8x1 bit
|
u32 texMtxInfo_n_projection : 8; // 8x1 bit
|
||||||
u32 tevindref_bi0 : 3;
|
u32 tevindref_bi0 : 3;
|
||||||
|
@ -162,5 +157,6 @@ struct pixel_shader_uid_data
|
||||||
|
|
||||||
typedef ShaderUid<pixel_shader_uid_data> PixelShaderUid;
|
typedef ShaderUid<pixel_shader_uid_data> PixelShaderUid;
|
||||||
|
|
||||||
ShaderCode GeneratePixelShaderCode(APIType ApiType, const pixel_shader_uid_data* uid_data);
|
ShaderCode GeneratePixelShaderCode(APIType ApiType, const ShaderHostConfig& host_config,
|
||||||
|
const pixel_shader_uid_data* uid_data);
|
||||||
PixelShaderUid GetPixelShaderUid();
|
PixelShaderUid GetPixelShaderUid();
|
||||||
|
|
|
@ -52,6 +52,7 @@
|
||||||
#include "VideoCommon/OnScreenDisplay.h"
|
#include "VideoCommon/OnScreenDisplay.h"
|
||||||
#include "VideoCommon/PixelShaderManager.h"
|
#include "VideoCommon/PixelShaderManager.h"
|
||||||
#include "VideoCommon/PostProcessing.h"
|
#include "VideoCommon/PostProcessing.h"
|
||||||
|
#include "VideoCommon/ShaderGenCommon.h"
|
||||||
#include "VideoCommon/Statistics.h"
|
#include "VideoCommon/Statistics.h"
|
||||||
#include "VideoCommon/TextureCacheBase.h"
|
#include "VideoCommon/TextureCacheBase.h"
|
||||||
#include "VideoCommon/TextureDecoder.h"
|
#include "VideoCommon/TextureDecoder.h"
|
||||||
|
@ -96,6 +97,8 @@ Renderer::Renderer(int backbuffer_width, int backbuffer_height)
|
||||||
{
|
{
|
||||||
m_aspect_wide = SConfig::GetInstance().m_wii_aspect_ratio != 0;
|
m_aspect_wide = SConfig::GetInstance().m_wii_aspect_ratio != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
m_last_host_config_bits = ShaderHostConfig::GetCurrent().bits;
|
||||||
}
|
}
|
||||||
|
|
||||||
Renderer::~Renderer()
|
Renderer::~Renderer()
|
||||||
|
@ -315,6 +318,17 @@ void Renderer::SaveScreenshot(const std::string& filename, bool wait_for_complet
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Renderer::CheckForHostConfigChanges()
|
||||||
|
{
|
||||||
|
ShaderHostConfig new_host_config = ShaderHostConfig::GetCurrent();
|
||||||
|
if (new_host_config.bits == m_last_host_config_bits)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
OSD::AddMessage("Video config changed, reloading shaders.", OSD::Duration::NORMAL);
|
||||||
|
m_last_host_config_bits = new_host_config.bits;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
// Create On-Screen-Messages
|
// Create On-Screen-Messages
|
||||||
void Renderer::DrawDebugText()
|
void Renderer::DrawDebugText()
|
||||||
{
|
{
|
||||||
|
|
|
@ -147,6 +147,8 @@ protected:
|
||||||
std::tuple<int, int> CalculateTargetScale(int x, int y) const;
|
std::tuple<int, int> CalculateTargetScale(int x, int y) const;
|
||||||
bool CalculateTargetSize();
|
bool CalculateTargetSize();
|
||||||
|
|
||||||
|
bool CheckForHostConfigChanges();
|
||||||
|
|
||||||
void CheckFifoRecording();
|
void CheckFifoRecording();
|
||||||
void RecordVideoMemory();
|
void RecordVideoMemory();
|
||||||
|
|
||||||
|
@ -182,6 +184,8 @@ protected:
|
||||||
Common::Event m_surface_changed;
|
Common::Event m_surface_changed;
|
||||||
void* m_new_surface_handle = nullptr;
|
void* m_new_surface_handle = nullptr;
|
||||||
|
|
||||||
|
u32 m_last_host_config_bits = 0;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void RunFrameDumps();
|
void RunFrameDumps();
|
||||||
void ShutdownFrameDumping();
|
void ShutdownFrameDumping();
|
||||||
|
|
|
@ -0,0 +1,75 @@
|
||||||
|
// Copyright 2017 Dolphin Emulator Project
|
||||||
|
// Licensed under GPLv2+
|
||||||
|
// Refer to the license.txt file included.
|
||||||
|
|
||||||
|
#include "VideoCommon/ShaderGenCommon.h"
|
||||||
|
#include "Common/CommonPaths.h"
|
||||||
|
#include "Common/FileUtil.h"
|
||||||
|
#include "Core/ConfigManager.h"
|
||||||
|
|
||||||
|
ShaderHostConfig ShaderHostConfig::GetCurrent()
|
||||||
|
{
|
||||||
|
ShaderHostConfig bits = {};
|
||||||
|
bits.msaa = g_ActiveConfig.iMultisamples > 1;
|
||||||
|
bits.ssaa = g_ActiveConfig.iMultisamples > 1 && g_ActiveConfig.bSSAA &&
|
||||||
|
g_ActiveConfig.backend_info.bSupportsSSAA;
|
||||||
|
bits.stereo = g_ActiveConfig.iStereoMode > 0;
|
||||||
|
bits.wireframe = g_ActiveConfig.bWireFrame;
|
||||||
|
bits.per_pixel_lighting = g_ActiveConfig.bEnablePixelLighting;
|
||||||
|
bits.vertex_rounding = g_ActiveConfig.UseVertexRounding();
|
||||||
|
bits.fast_depth_calc = g_ActiveConfig.bFastDepthCalc;
|
||||||
|
bits.bounding_box = g_ActiveConfig.bBBoxEnable;
|
||||||
|
bits.backend_dual_source_blend = g_ActiveConfig.backend_info.bSupportsDualSourceBlend;
|
||||||
|
bits.backend_geometry_shaders = g_ActiveConfig.backend_info.bSupportsGeometryShaders;
|
||||||
|
bits.backend_early_z = g_ActiveConfig.backend_info.bSupportsEarlyZ;
|
||||||
|
bits.backend_bbox = g_ActiveConfig.backend_info.bSupportsBBox;
|
||||||
|
bits.backend_gs_instancing = g_ActiveConfig.backend_info.bSupportsGSInstancing;
|
||||||
|
bits.backend_clip_control = g_ActiveConfig.backend_info.bSupportsClipControl;
|
||||||
|
bits.backend_ssaa = g_ActiveConfig.backend_info.bSupportsSSAA;
|
||||||
|
bits.backend_atomics = g_ActiveConfig.backend_info.bSupportsFragmentStoresAndAtomics;
|
||||||
|
bits.backend_depth_clamp = g_ActiveConfig.backend_info.bSupportsDepthClamp;
|
||||||
|
bits.backend_reversed_depth_range = g_ActiveConfig.backend_info.bSupportsReversedDepthRange;
|
||||||
|
return bits;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string GetDiskShaderCacheFileName(APIType api_type, const char* type, bool include_gameid,
|
||||||
|
bool include_host_config)
|
||||||
|
{
|
||||||
|
if (!File::Exists(File::GetUserPath(D_SHADERCACHE_IDX)))
|
||||||
|
File::CreateDir(File::GetUserPath(D_SHADERCACHE_IDX));
|
||||||
|
|
||||||
|
std::string filename = File::GetUserPath(D_SHADERCACHE_IDX);
|
||||||
|
switch (api_type)
|
||||||
|
{
|
||||||
|
case APIType::D3D:
|
||||||
|
filename += "D3D";
|
||||||
|
break;
|
||||||
|
case APIType::OpenGL:
|
||||||
|
filename += "OpenGL";
|
||||||
|
break;
|
||||||
|
case APIType::Vulkan:
|
||||||
|
filename += "Vulkan";
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
filename += '-';
|
||||||
|
filename += type;
|
||||||
|
|
||||||
|
if (include_gameid)
|
||||||
|
{
|
||||||
|
filename += '-';
|
||||||
|
filename += SConfig::GetInstance().GetGameID();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (include_host_config)
|
||||||
|
{
|
||||||
|
// We're using 18 bits, so 5 hex characters.
|
||||||
|
ShaderHostConfig host_config = ShaderHostConfig::GetCurrent();
|
||||||
|
filename += StringFromFormat("-%05X", host_config.bits);
|
||||||
|
}
|
||||||
|
|
||||||
|
filename += ".cache";
|
||||||
|
return filename;
|
||||||
|
}
|
|
@ -151,6 +151,41 @@ private:
|
||||||
std::vector<bool> constant_usage; // TODO: Is vector<bool> appropriate here?
|
std::vector<bool> constant_usage; // TODO: Is vector<bool> appropriate here?
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Host config contains the settings which can influence generated shaders.
|
||||||
|
union ShaderHostConfig
|
||||||
|
{
|
||||||
|
u32 bits;
|
||||||
|
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
u32 msaa : 1;
|
||||||
|
u32 ssaa : 1;
|
||||||
|
u32 stereo : 1;
|
||||||
|
u32 wireframe : 1;
|
||||||
|
u32 per_pixel_lighting : 1;
|
||||||
|
u32 vertex_rounding : 1;
|
||||||
|
u32 fast_depth_calc : 1;
|
||||||
|
u32 bounding_box : 1;
|
||||||
|
u32 backend_dual_source_blend : 1;
|
||||||
|
u32 backend_geometry_shaders : 1;
|
||||||
|
u32 backend_early_z : 1;
|
||||||
|
u32 backend_bbox : 1;
|
||||||
|
u32 backend_gs_instancing : 1;
|
||||||
|
u32 backend_clip_control : 1;
|
||||||
|
u32 backend_ssaa : 1;
|
||||||
|
u32 backend_atomics : 1;
|
||||||
|
u32 backend_depth_clamp : 1;
|
||||||
|
u32 backend_reversed_depth_range : 1;
|
||||||
|
u32 pad : 14;
|
||||||
|
};
|
||||||
|
|
||||||
|
static ShaderHostConfig GetCurrent();
|
||||||
|
};
|
||||||
|
|
||||||
|
// Gets the filename of the specified type of cache object (e.g. vertex shader, pipeline).
|
||||||
|
std::string GetDiskShaderCacheFileName(APIType api_type, const char* type, bool include_gameid,
|
||||||
|
bool include_host_config);
|
||||||
|
|
||||||
template <class T>
|
template <class T>
|
||||||
inline void DefineOutputMember(T& object, APIType api_type, const char* qualifier, const char* type,
|
inline void DefineOutputMember(T& object, APIType api_type, const char* qualifier, const char* type,
|
||||||
const char* name, int var_index, const char* semantic = "",
|
const char* name, int var_index, const char* semantic = "",
|
||||||
|
|
|
@ -26,11 +26,6 @@ VertexShaderUid GetVertexShaderUid()
|
||||||
|
|
||||||
uid_data->numTexGens = xfmem.numTexGen.numTexGens;
|
uid_data->numTexGens = xfmem.numTexGen.numTexGens;
|
||||||
uid_data->components = VertexLoaderManager::g_current_components;
|
uid_data->components = VertexLoaderManager::g_current_components;
|
||||||
uid_data->pixel_lighting = g_ActiveConfig.bEnablePixelLighting;
|
|
||||||
uid_data->vertex_rounding =
|
|
||||||
g_ActiveConfig.bVertexRounding && g_ActiveConfig.iEFBScale != SCALE_1X;
|
|
||||||
uid_data->msaa = g_ActiveConfig.iMultisamples > 1;
|
|
||||||
uid_data->ssaa = g_ActiveConfig.iMultisamples > 1 && g_ActiveConfig.bSSAA;
|
|
||||||
uid_data->numColorChans = xfmem.numChan.numColorChans;
|
uid_data->numColorChans = xfmem.numChan.numColorChans;
|
||||||
|
|
||||||
GetLightingShaderUid(uid_data->lighting);
|
GetLightingShaderUid(uid_data->lighting);
|
||||||
|
@ -81,9 +76,16 @@ VertexShaderUid GetVertexShaderUid()
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
ShaderCode GenerateVertexShaderCode(APIType api_type, const vertex_shader_uid_data* uid_data)
|
ShaderCode GenerateVertexShaderCode(APIType api_type, const ShaderHostConfig& host_config,
|
||||||
|
const vertex_shader_uid_data* uid_data)
|
||||||
{
|
{
|
||||||
ShaderCode out;
|
ShaderCode out;
|
||||||
|
|
||||||
|
const bool per_pixel_lighting = g_ActiveConfig.bEnablePixelLighting;
|
||||||
|
const bool msaa = host_config.msaa;
|
||||||
|
const bool ssaa = host_config.ssaa;
|
||||||
|
const bool vertex_rounding = host_config.vertex_rounding;
|
||||||
|
|
||||||
out.Write("%s", s_lighting_struct);
|
out.Write("%s", s_lighting_struct);
|
||||||
|
|
||||||
// uniforms
|
// uniforms
|
||||||
|
@ -96,7 +98,7 @@ ShaderCode GenerateVertexShaderCode(APIType api_type, const vertex_shader_uid_da
|
||||||
out.Write("};\n");
|
out.Write("};\n");
|
||||||
|
|
||||||
out.Write("struct VS_OUTPUT {\n");
|
out.Write("struct VS_OUTPUT {\n");
|
||||||
GenerateVSOutputMembers(out, api_type, uid_data->numTexGens, uid_data->pixel_lighting, "");
|
GenerateVSOutputMembers(out, api_type, uid_data->numTexGens, per_pixel_lighting, "");
|
||||||
out.Write("};\n");
|
out.Write("};\n");
|
||||||
|
|
||||||
if (api_type == APIType::OpenGL || api_type == APIType::Vulkan)
|
if (api_type == APIType::OpenGL || api_type == APIType::Vulkan)
|
||||||
|
@ -127,12 +129,11 @@ ShaderCode GenerateVertexShaderCode(APIType api_type, const vertex_shader_uid_da
|
||||||
}
|
}
|
||||||
|
|
||||||
// We need to always use output blocks for Vulkan, but geometry shaders are also optional.
|
// We need to always use output blocks for Vulkan, but geometry shaders are also optional.
|
||||||
if (g_ActiveConfig.backend_info.bSupportsGeometryShaders || api_type == APIType::Vulkan)
|
if (host_config.backend_geometry_shaders || api_type == APIType::Vulkan)
|
||||||
{
|
{
|
||||||
out.Write("VARYING_LOCATION(0) out VertexData {\n");
|
out.Write("VARYING_LOCATION(0) out VertexData {\n");
|
||||||
GenerateVSOutputMembers(
|
GenerateVSOutputMembers(out, api_type, uid_data->numTexGens, per_pixel_lighting,
|
||||||
out, api_type, uid_data->numTexGens, uid_data->pixel_lighting,
|
GetInterpolationQualifier(msaa, ssaa, true, false));
|
||||||
GetInterpolationQualifier(uid_data->msaa, uid_data->ssaa, true, false));
|
|
||||||
out.Write("} vs;\n");
|
out.Write("} vs;\n");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -142,23 +143,17 @@ ShaderCode GenerateVertexShaderCode(APIType api_type, const vertex_shader_uid_da
|
||||||
{
|
{
|
||||||
if (i < uid_data->numTexGens)
|
if (i < uid_data->numTexGens)
|
||||||
{
|
{
|
||||||
out.Write("%s out float3 uv%u;\n",
|
out.Write("%s out float3 uv%u;\n", GetInterpolationQualifier(msaa, ssaa), i);
|
||||||
GetInterpolationQualifier(uid_data->msaa, uid_data->ssaa), i);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
out.Write("%s out float4 clipPos;\n",
|
out.Write("%s out float4 clipPos;\n", GetInterpolationQualifier(msaa, ssaa));
|
||||||
GetInterpolationQualifier(uid_data->msaa, uid_data->ssaa));
|
if (per_pixel_lighting)
|
||||||
if (uid_data->pixel_lighting)
|
|
||||||
{
|
{
|
||||||
out.Write("%s out float3 Normal;\n",
|
out.Write("%s out float3 Normal;\n", GetInterpolationQualifier(msaa, ssaa));
|
||||||
GetInterpolationQualifier(uid_data->msaa, uid_data->ssaa));
|
out.Write("%s out float3 WorldPos;\n", GetInterpolationQualifier(msaa, ssaa));
|
||||||
out.Write("%s out float3 WorldPos;\n",
|
|
||||||
GetInterpolationQualifier(uid_data->msaa, uid_data->ssaa));
|
|
||||||
}
|
}
|
||||||
out.Write("%s out float4 colors_0;\n",
|
out.Write("%s out float4 colors_0;\n", GetInterpolationQualifier(msaa, ssaa));
|
||||||
GetInterpolationQualifier(uid_data->msaa, uid_data->ssaa));
|
out.Write("%s out float4 colors_1;\n", GetInterpolationQualifier(msaa, ssaa));
|
||||||
out.Write("%s out float4 colors_1;\n",
|
|
||||||
GetInterpolationQualifier(uid_data->msaa, uid_data->ssaa));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
out.Write("void main()\n{\n");
|
out.Write("void main()\n{\n");
|
||||||
|
@ -406,7 +401,7 @@ ShaderCode GenerateVertexShaderCode(APIType api_type, const vertex_shader_uid_da
|
||||||
// clipPos/w needs to be done in pixel shader, not here
|
// clipPos/w needs to be done in pixel shader, not here
|
||||||
out.Write("o.clipPos = o.pos;\n");
|
out.Write("o.clipPos = o.pos;\n");
|
||||||
|
|
||||||
if (uid_data->pixel_lighting)
|
if (per_pixel_lighting)
|
||||||
{
|
{
|
||||||
out.Write("o.Normal = _norm0;\n");
|
out.Write("o.Normal = _norm0;\n");
|
||||||
out.Write("o.WorldPos = pos.xyz;\n");
|
out.Write("o.WorldPos = pos.xyz;\n");
|
||||||
|
@ -421,7 +416,7 @@ ShaderCode GenerateVertexShaderCode(APIType api_type, const vertex_shader_uid_da
|
||||||
// If we can disable the incorrect depth clipping planes using depth clamping, then we can do
|
// If we can disable the incorrect depth clipping planes using depth clamping, then we can do
|
||||||
// our own depth clipping and calculate the depth range before the perspective divide if
|
// our own depth clipping and calculate the depth range before the perspective divide if
|
||||||
// necessary.
|
// necessary.
|
||||||
if (g_ActiveConfig.backend_info.bSupportsDepthClamp)
|
if (host_config.backend_depth_clamp)
|
||||||
{
|
{
|
||||||
// Since we're adjusting z for the depth range before the perspective divide, we have to do our
|
// Since we're adjusting z for the depth range before the perspective divide, we have to do our
|
||||||
// own clipping. We want to clip so that -w <= z <= 0, which matches the console -1..0 range.
|
// own clipping. We want to clip so that -w <= z <= 0, which matches the console -1..0 range.
|
||||||
|
@ -446,7 +441,7 @@ ShaderCode GenerateVertexShaderCode(APIType api_type, const vertex_shader_uid_da
|
||||||
out.Write("o.pos.z = o.pos.w * " I_PIXELCENTERCORRECTION ".w - "
|
out.Write("o.pos.z = o.pos.w * " I_PIXELCENTERCORRECTION ".w - "
|
||||||
"o.pos.z * " I_PIXELCENTERCORRECTION ".z;\n");
|
"o.pos.z * " I_PIXELCENTERCORRECTION ".z;\n");
|
||||||
|
|
||||||
if (!g_ActiveConfig.backend_info.bSupportsClipControl)
|
if (!host_config.backend_clip_control)
|
||||||
{
|
{
|
||||||
// If the graphics API doesn't support a depth range of 0..1, then we need to map z to
|
// If the graphics API doesn't support a depth range of 0..1, then we need to map z to
|
||||||
// the -1..1 range. Unfortunately we have to use a substraction, which is a lossy floating-point
|
// the -1..1 range. Unfortunately we have to use a substraction, which is a lossy floating-point
|
||||||
|
@ -466,7 +461,7 @@ ShaderCode GenerateVertexShaderCode(APIType api_type, const vertex_shader_uid_da
|
||||||
// get rasterized correctly.
|
// get rasterized correctly.
|
||||||
out.Write("o.pos.xy = o.pos.xy - o.pos.w * " I_PIXELCENTERCORRECTION ".xy;\n");
|
out.Write("o.pos.xy = o.pos.xy - o.pos.w * " I_PIXELCENTERCORRECTION ".xy;\n");
|
||||||
|
|
||||||
if (uid_data->vertex_rounding)
|
if (vertex_rounding)
|
||||||
{
|
{
|
||||||
// By now our position is in clip space
|
// By now our position is in clip space
|
||||||
// however, higher resolutions than the Wii outputs
|
// however, higher resolutions than the Wii outputs
|
||||||
|
@ -491,9 +486,9 @@ ShaderCode GenerateVertexShaderCode(APIType api_type, const vertex_shader_uid_da
|
||||||
|
|
||||||
if (api_type == APIType::OpenGL || api_type == APIType::Vulkan)
|
if (api_type == APIType::OpenGL || api_type == APIType::Vulkan)
|
||||||
{
|
{
|
||||||
if (g_ActiveConfig.backend_info.bSupportsGeometryShaders || api_type == APIType::Vulkan)
|
if (host_config.backend_geometry_shaders || api_type == APIType::Vulkan)
|
||||||
{
|
{
|
||||||
AssignVSOutputMembers(out, "vs", "o", uid_data->numTexGens, uid_data->pixel_lighting);
|
AssignVSOutputMembers(out, "vs", "o", uid_data->numTexGens, per_pixel_lighting);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -502,7 +497,7 @@ ShaderCode GenerateVertexShaderCode(APIType api_type, const vertex_shader_uid_da
|
||||||
for (unsigned int i = 0; i < uid_data->numTexGens; ++i)
|
for (unsigned int i = 0; i < uid_data->numTexGens; ++i)
|
||||||
out.Write("uv%d.xyz = o.tex%d;\n", i, i);
|
out.Write("uv%d.xyz = o.tex%d;\n", i, i);
|
||||||
out.Write("clipPos = o.clipPos;\n");
|
out.Write("clipPos = o.clipPos;\n");
|
||||||
if (uid_data->pixel_lighting)
|
if (per_pixel_lighting)
|
||||||
{
|
{
|
||||||
out.Write("Normal = o.Normal;\n");
|
out.Write("Normal = o.Normal;\n");
|
||||||
out.Write("WorldPos = o.WorldPos;\n");
|
out.Write("WorldPos = o.WorldPos;\n");
|
||||||
|
@ -511,7 +506,7 @@ ShaderCode GenerateVertexShaderCode(APIType api_type, const vertex_shader_uid_da
|
||||||
out.Write("colors_1 = o.colors_1;\n");
|
out.Write("colors_1 = o.colors_1;\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (g_ActiveConfig.backend_info.bSupportsDepthClamp)
|
if (host_config.backend_depth_clamp)
|
||||||
{
|
{
|
||||||
out.Write("gl_ClipDistance[0] = o.clipDist0;\n");
|
out.Write("gl_ClipDistance[0] = o.clipDist0;\n");
|
||||||
out.Write("gl_ClipDistance[1] = o.clipDist1;\n");
|
out.Write("gl_ClipDistance[1] = o.clipDist1;\n");
|
||||||
|
|
|
@ -37,14 +37,10 @@ struct vertex_shader_uid_data
|
||||||
u32 numTexGens : 4;
|
u32 numTexGens : 4;
|
||||||
u32 numColorChans : 2;
|
u32 numColorChans : 2;
|
||||||
u32 dualTexTrans_enabled : 1;
|
u32 dualTexTrans_enabled : 1;
|
||||||
u32 pixel_lighting : 1;
|
|
||||||
u32 msaa : 1;
|
|
||||||
|
|
||||||
u32 texMtxInfo_n_projection : 16; // Stored separately to guarantee that the texMtxInfo struct is
|
u32 texMtxInfo_n_projection : 16; // Stored separately to guarantee that the texMtxInfo struct is
|
||||||
// 8 bits wide
|
// 8 bits wide
|
||||||
u32 ssaa : 1;
|
u32 pad : 18;
|
||||||
u32 vertex_rounding : 1;
|
|
||||||
u32 pad : 14;
|
|
||||||
|
|
||||||
struct
|
struct
|
||||||
{
|
{
|
||||||
|
@ -69,4 +65,5 @@ struct vertex_shader_uid_data
|
||||||
typedef ShaderUid<vertex_shader_uid_data> VertexShaderUid;
|
typedef ShaderUid<vertex_shader_uid_data> VertexShaderUid;
|
||||||
|
|
||||||
VertexShaderUid GetVertexShaderUid();
|
VertexShaderUid GetVertexShaderUid();
|
||||||
ShaderCode GenerateVertexShaderCode(APIType api_type, const vertex_shader_uid_data* uid_data);
|
ShaderCode GenerateVertexShaderCode(APIType api_type, const ShaderHostConfig& host_config,
|
||||||
|
const vertex_shader_uid_data* uid_data);
|
||||||
|
|
|
@ -65,6 +65,7 @@
|
||||||
<ClCompile Include="RenderBase.cpp" />
|
<ClCompile Include="RenderBase.cpp" />
|
||||||
<ClCompile Include="RenderState.cpp" />
|
<ClCompile Include="RenderState.cpp" />
|
||||||
<ClCompile Include="LightingShaderGen.cpp" />
|
<ClCompile Include="LightingShaderGen.cpp" />
|
||||||
|
<ClCompile Include="ShaderGenCommon.cpp" />
|
||||||
<ClCompile Include="Statistics.cpp" />
|
<ClCompile Include="Statistics.cpp" />
|
||||||
<ClCompile Include="GeometryShaderGen.cpp" />
|
<ClCompile Include="GeometryShaderGen.cpp" />
|
||||||
<ClCompile Include="GeometryShaderManager.cpp" />
|
<ClCompile Include="GeometryShaderManager.cpp" />
|
||||||
|
|
|
@ -173,6 +173,9 @@
|
||||||
<ClCompile Include="AbstractTexture.cpp">
|
<ClCompile Include="AbstractTexture.cpp">
|
||||||
<Filter>Base</Filter>
|
<Filter>Base</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
<ClCompile Include="ShaderGenCommon.cpp">
|
||||||
|
<Filter>Shader Generators</Filter>
|
||||||
|
</ClCompile>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClInclude Include="CommandProcessor.h" />
|
<ClInclude Include="CommandProcessor.h" />
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
|
||||||
#include "Common/CommonTypes.h"
|
#include "Common/CommonTypes.h"
|
||||||
|
#include "Common/StringUtil.h"
|
||||||
#include "Core/Config/GraphicsSettings.h"
|
#include "Core/Config/GraphicsSettings.h"
|
||||||
#include "Core/Core.h"
|
#include "Core/Core.h"
|
||||||
#include "Core/Movie.h"
|
#include "Core/Movie.h"
|
||||||
|
|
|
@ -223,6 +223,7 @@ struct VideoConfig final
|
||||||
{
|
{
|
||||||
return backend_info.bSupportsGPUTextureDecoding && bEnableGPUTextureDecoding;
|
return backend_info.bSupportsGPUTextureDecoding && bEnableGPUTextureDecoding;
|
||||||
}
|
}
|
||||||
|
bool UseVertexRounding() const { return bVertexRounding && iEFBScale != SCALE_1X; }
|
||||||
};
|
};
|
||||||
|
|
||||||
extern VideoConfig g_Config;
|
extern VideoConfig g_Config;
|
||||||
|
|
Loading…
Reference in New Issue