Merge pull request #5679 from stenzek/no-host-state-in-uids

ShaderGen: Decouple host state from shader UIDs
This commit is contained in:
Stenzek
2017-07-27 13:30:38 +10:00
committed by GitHub
33 changed files with 580 additions and 346 deletions
@@ -158,18 +158,23 @@ void GeometryShaderCache::Init()
Clear();
if (g_ActiveConfig.bShaderCache)
{
if (!File::Exists(File::GetUserPath(D_SHADERCACHE_IDX)))
File::CreateDir(File::GetUserPath(D_SHADERCACHE_IDX));
LoadShaderCache();
}
std::string cache_filename =
StringFromFormat("%sdx11-%s-gs.cache", File::GetUserPath(D_SHADERCACHE_IDX).c_str(),
SConfig::GetInstance().GetGameID().c_str());
GeometryShaderCacheInserter inserter;
g_gs_disk_cache.OpenAndRead(cache_filename, inserter);
}
void GeometryShaderCache::LoadShaderCache()
{
GeometryShaderCacheInserter inserter;
g_gs_disk_cache.OpenAndRead(GetDiskShaderCacheFileName(APIType::D3D, "GS", true, true), 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.
@@ -180,6 +185,7 @@ void GeometryShaderCache::Clear()
GeometryShaders.clear();
last_entry = nullptr;
last_uid = {};
}
void GeometryShaderCache::Shutdown()
@@ -230,7 +236,8 @@ bool GeometryShaderCache::SetShader(u32 primitive_type)
}
// Need to compile a new shader
ShaderCode code = GenerateGeometryShaderCode(APIType::D3D, uid.GetUidData());
ShaderCode code =
GenerateGeometryShaderCode(APIType::D3D, ShaderHostConfig::GetCurrent(), uid.GetUidData());
D3DBlob* pbytecode;
if (!D3D::CompileGeometryShader(code.GetBuffer(), &pbytecode))
@@ -15,6 +15,7 @@ class GeometryShaderCache
{
public:
static void Init();
static void Reload();
static void Clear();
static void Shutdown();
static bool SetShader(u32 primitive_type); // TODO: Should be renamed to LoadShader
@@ -38,6 +39,8 @@ private:
typedef std::map<GeometryShaderUid, GSCacheEntry> GSCache;
static void LoadShaderCache();
static GSCache GeometryShaders;
static const GSCacheEntry* last_entry;
static GeometryShaderUid last_uid;
@@ -498,18 +498,23 @@ void PixelShaderCache::Init()
SETSTAT(stats.numPixelShadersAlive, 0);
if (g_ActiveConfig.bShaderCache)
{
if (!File::Exists(File::GetUserPath(D_SHADERCACHE_IDX)))
File::CreateDir(File::GetUserPath(D_SHADERCACHE_IDX));
LoadShaderCache();
}
std::string cache_filename =
StringFromFormat("%sdx11-%s-ps.cache", File::GetUserPath(D_SHADERCACHE_IDX).c_str(),
SConfig::GetInstance().GetGameID().c_str());
PixelShaderCacheInserter inserter;
g_ps_disk_cache.OpenAndRead(cache_filename, inserter);
}
void PixelShaderCache::LoadShaderCache()
{
PixelShaderCacheInserter inserter;
g_ps_disk_cache.OpenAndRead(GetDiskShaderCacheFileName(APIType::D3D, "PS", true, true), 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.
@@ -520,6 +525,7 @@ void PixelShaderCache::Clear()
PixelShaders.clear();
last_entry = nullptr;
last_uid = {};
}
// Used in Swap() when AA mode has changed
@@ -583,7 +589,8 @@ bool PixelShaderCache::SetShader()
}
// Need to compile a new shader
ShaderCode code = GeneratePixelShaderCode(APIType::D3D, uid.GetUidData());
ShaderCode code =
GeneratePixelShaderCode(APIType::D3D, ShaderHostConfig::GetCurrent(), uid.GetUidData());
D3DBlob* pbytecode;
if (!D3D::CompilePixelShader(code.GetBuffer(), &pbytecode))
@@ -15,6 +15,7 @@ class PixelShaderCache
{
public:
static void Init();
static void Reload();
static void Clear();
static void Shutdown();
static bool SetShader(); // TODO: Should be renamed to LoadShader
@@ -46,6 +47,8 @@ private:
typedef std::map<PixelShaderUid, PSCacheEntry> PSCache;
static void LoadShaderCache();
static PSCache PixelShaders;
static const PSCacheEntry* last_entry;
static PixelShaderUid last_uid;
+7
View File
@@ -894,6 +894,13 @@ void Renderer::SwapImpl(u32 xfbAddr, u32 fbWidth, u32 fbStride, u32 fbHeight,
D3D11_CLEAR_DEPTH, 0.f, 0);
}
if (CheckForHostConfigChanges())
{
VertexShaderCache::Reload();
GeometryShaderCache::Reload();
PixelShaderCache::Reload();
}
// begin next frame
RestoreAPIState();
D3D::BeginFrame();
@@ -159,18 +159,23 @@ void VertexShaderCache::Init()
SETSTAT(stats.numVertexShadersAlive, 0);
if (g_ActiveConfig.bShaderCache)
{
if (!File::Exists(File::GetUserPath(D_SHADERCACHE_IDX)))
File::CreateDir(File::GetUserPath(D_SHADERCACHE_IDX));
LoadShaderCache();
}
std::string cache_filename =
StringFromFormat("%sdx11-%s-vs.cache", File::GetUserPath(D_SHADERCACHE_IDX).c_str(),
SConfig::GetInstance().GetGameID().c_str());
VertexShaderCacheInserter inserter;
g_vs_disk_cache.OpenAndRead(cache_filename, inserter);
}
void VertexShaderCache::LoadShaderCache()
{
VertexShaderCacheInserter inserter;
g_vs_disk_cache.OpenAndRead(GetDiskShaderCacheFileName(APIType::D3D, "VS", true, true), 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()
@@ -180,6 +185,7 @@ void VertexShaderCache::Clear()
vshaders.clear();
last_entry = nullptr;
last_uid = {};
}
void VertexShaderCache::Shutdown()
@@ -222,7 +228,8 @@ bool VertexShaderCache::SetShader()
return (entry.shader != nullptr);
}
ShaderCode code = GenerateVertexShaderCode(APIType::D3D, uid.GetUidData());
ShaderCode code =
GenerateVertexShaderCode(APIType::D3D, ShaderHostConfig::GetCurrent(), uid.GetUidData());
D3DBlob* pbytecode = nullptr;
D3D::CompileVertexShader(code.GetBuffer(), &pbytecode);
@@ -17,6 +17,7 @@ class VertexShaderCache
{
public:
static void Init();
static void Reload();
static void Clear();
static void Shutdown();
static bool SetShader(); // TODO: Should be renamed to LoadShader
@@ -53,6 +54,8 @@ private:
};
typedef std::map<VertexShaderUid, VSCacheEntry> VSCache;
static void LoadShaderCache();
static VSCache vshaders;
static const VSCacheEntry* last_entry;
static VertexShaderUid last_uid;
+3 -3
View File
@@ -46,7 +46,7 @@ protected:
}
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
{
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
{
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;
newentry.in_cache = 0;
ShaderCode vcode = GenerateVertexShaderCode(APIType::OpenGL, uid.vuid.GetUidData());
ShaderCode pcode = GeneratePixelShaderCode(APIType::OpenGL, uid.puid.GetUidData());
ShaderHostConfig host_config = ShaderHostConfig::GetCurrent();
ShaderCode vcode = GenerateVertexShaderCode(APIType::OpenGL, host_config, uid.vuid.GetUidData());
ShaderCode pcode = GeneratePixelShaderCode(APIType::OpenGL, host_config, uid.puid.GetUidData());
ShaderCode gcode;
if (g_ActiveConfig.backend_info.bSupportsGeometryShaders &&
!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 (g_ActiveConfig.iLog & CONF_SAVESHADERS)
@@ -504,29 +505,7 @@ void ProgramShaderCache::Init()
// Read our shader cache, only if supported and enabled
if (g_ogl_config.bSupportsGLSLCache && g_ActiveConfig.bShaderCache)
{
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());
}
LoadProgramBinaries();
CreateHeader();
@@ -534,47 +513,93 @@ void ProgramShaderCache::Init()
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()
{
// 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
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));
continue;
}
g_program_disk_cache.Sync();
g_program_disk_cache.Close();
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();
}
void ProgramShaderCache::DestroyShaders()
{
glUseProgram(0);
for (auto& entry : pshaders)
@@ -582,8 +607,6 @@ void ProgramShaderCache::Shutdown()
entry.second.Destroy();
}
pshaders.clear();
s_buffer.reset();
}
void ProgramShaderCache::CreateHeader()
@@ -72,6 +72,7 @@ public:
static void UploadConstants();
static void Init();
static void Reload();
static void Shutdown();
static void CreateHeader();
@@ -82,6 +83,10 @@ private:
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;
static PCache pshaders;
static PCacheEntry* last_entry;
+8
View File
@@ -43,6 +43,7 @@
#include "VideoCommon/PixelEngine.h"
#include "VideoCommon/PixelShaderManager.h"
#include "VideoCommon/RenderState.h"
#include "VideoCommon/ShaderGenCommon.h"
#include "VideoCommon/VertexShaderManager.h"
#include "VideoCommon/VideoBackendBase.h"
#include "VideoCommon/VideoConfig.h"
@@ -664,6 +665,9 @@ Renderer::Renderer()
g_Config.VerifyValidity();
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,
g_ogl_config.gl_renderer, g_ogl_config.gl_version),
5000);
@@ -1469,6 +1473,10 @@ void Renderer::SwapImpl(u32 xfbAddr, u32 fbWidth, u32 fbStride, u32 fbHeight,
UpdateActiveConfig();
g_texture_cache->OnConfigChanged(g_ActiveConfig);
// Invalidate shader cache when the host config changes.
if (CheckForHostConfigChanges())
ProgramShaderCache::Reload();
// For testing zbuffer targets.
// Renderer::SetZBufferRender();
// SaveTexture("tex.png", GL_TEXTURE_2D, s_FakeZTarget,
@@ -1274,12 +1274,12 @@ bool FramebufferManager::CompilePokeShaders()
layout(triangles) in;
layout(triangle_strip, max_vertices = EFB_LAYERS * 3) out;
in VertexData
VARYING_LOCATION(0) in VertexData
{
vec4 col0;
} in_data[];
out VertexData
VARYING_LOCATION(0) out VertexData
{
vec4 col0;
} out_data;
@@ -49,9 +49,17 @@ bool ObjectCache::Initialize()
if (!CreatePipelineLayouts())
return false;
LoadShaderCaches();
if (!CreatePipelineCache(true))
return false;
if (g_ActiveConfig.bShaderCache)
{
LoadShaderCaches();
if (!LoadPipelineCache())
return false;
}
else
{
if (!CreatePipelineCache())
return false;
}
if (!CreateUtilityShaderVertexFormat())
return false;
@@ -438,12 +446,6 @@ void ObjectCache::ClearPipelineCache()
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>
{
public:
@@ -465,26 +467,47 @@ public:
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 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;
if (load_from_disk)
{
LinearDiskCache<u32, u8> disk_cache;
PipelineCacheReadCallback read_callback(&disk_data);
if (disk_cache.OpenAndRead(m_pipeline_cache_filename, read_callback) != 1)
disk_data.clear();
}
LinearDiskCache<u32, u8> disk_cache;
PipelineCacheReadCallback read_callback(&disk_data);
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()))
{
// 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);
disk_data.clear();
return CreatePipelineCache();
}
VkPipelineCacheCreateInfo info = {
@@ -492,7 +515,7 @@ bool ObjectCache::CreatePipelineCache(bool load_from_disk)
nullptr, // const void* pNext
0, // VkPipelineCacheCreateFlags flags
disk_data.size(), // size_t initialDataSize
!disk_data.empty() ? disk_data.data() : nullptr, // const void* pInitialData
disk_data.data() // const void* pInitialData
};
VkResult res =
@@ -502,14 +525,7 @@ bool ObjectCache::CreatePipelineCache(bool load_from_disk)
// Failed to create pipeline cache, try with it empty.
LOG_VULKAN_ERROR(res, "vkCreatePipelineCache failed, trying empty cache: ");
info.initialDataSize = 0;
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;
return CreatePipelineCache();
}
// Based on Vulkan 1.0 specification,
@@ -644,19 +660,19 @@ struct ShaderCacheReader : public LinearDiskCacheReader<Uid, u32>
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);
m_vs_cache.disk_cache.OpenAndRead(GetDiskCacheFileName("vs"), vs_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);
}
ShaderCacheReader<GeometryShaderUid> gs_reader(m_gs_cache.shader_map);
m_gs_cache.disk_cache.OpenAndRead(GetDiskShaderCacheFileName(APIType::Vulkan, "GS", true, true),
gs_reader);
}
SETSTAT(stats.numPixelShadersCreated, static_cast<int>(m_ps_cache.shader_map.size()));
@@ -668,6 +684,7 @@ void ObjectCache::LoadShaderCaches()
template <typename T>
static void DestroyShaderCache(T& cache)
{
cache.disk_cache.Sync();
cache.disk_cache.Close();
for (const auto& it : cache.shader_map)
{
@@ -684,6 +701,11 @@ void ObjectCache::DestroyShaderCaches()
if (g_vulkan_context->SupportsGeometryShaders())
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)
@@ -695,7 +717,8 @@ VkShaderModule ObjectCache::GetVertexShaderForUid(const VertexShaderUid& uid)
// Not in the cache, so compile the shader.
ShaderCompiler::SPIRVCodeVector spv;
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(),
source_code.GetBuffer().length()))
{
@@ -725,7 +748,8 @@ VkShaderModule ObjectCache::GetGeometryShaderForUid(const GeometryShaderUid& uid
// Not in the cache, so compile the shader.
ShaderCompiler::SPIRVCodeVector spv;
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(),
source_code.GetBuffer().length()))
{
@@ -750,7 +774,8 @@ VkShaderModule ObjectCache::GetPixelShaderForUid(const PixelShaderUid& uid)
// Not in the cache, so compile the shader.
ShaderCompiler::SPIRVCodeVector spv;
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(),
source_code.GetBuffer().length()))
{
@@ -804,6 +829,23 @@ void ObjectCache::RecompileSharedShaders()
PanicAlert("Failed to recompile shared shaders.");
}
void ObjectCache::ReloadShaderAndPipelineCaches()
{
SavePipelineCache();
DestroyShaderCaches();
DestroyPipelineCache();
if (g_ActiveConfig.bShaderCache)
{
LoadShaderCaches();
LoadPipelineCache();
}
else
{
CreatePipelineCache();
}
}
bool ObjectCache::CreateDescriptorSetLayouts()
{
static const VkDescriptorSetLayoutBinding ubo_set_bindings[] = {
@@ -154,16 +154,17 @@ public:
// Recompile shared shaders, call when stereo mode changes.
void RecompileSharedShaders();
// Reload pipeline cache. This will destroy all pipelines.
void ReloadShaderAndPipelineCaches();
// Shared shader accessors
VkShaderModule GetScreenQuadVertexShader() const { return m_screen_quad_vertex_shader; }
VkShaderModule GetPassthroughVertexShader() const { return m_passthrough_vertex_shader; }
VkShaderModule GetScreenQuadGeometryShader() const { return m_screen_quad_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:
bool CreatePipelineCache(bool load_from_disk);
bool CreatePipelineCache();
bool LoadPipelineCache();
bool ValidatePipelineCache(const u8* data, size_t data_length);
void DestroyPipelineCache();
void LoadShaderCaches();
+7 -16
View File
@@ -114,7 +114,7 @@ bool Renderer::Initialize()
}
// Ensure all pipelines previously used by the game have been created.
StateTracker::GetInstance()->LoadPipelineUIDCache();
StateTracker::GetInstance()->ReloadPipelineUIDCache();
// Initialize post processing.
m_post_processor = std::make_unique<VulkanPostProcessing>();
@@ -1126,13 +1126,10 @@ void Renderer::CheckForSurfaceChange()
void Renderer::CheckForConfigChanges()
{
// 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_stereo_mode = g_ActiveConfig.iStereoMode;
int old_aspect_ratio = g_ActiveConfig.iAspectRatio;
int old_efb_scale = g_ActiveConfig.iEFBScale;
bool old_force_filtering = g_ActiveConfig.bForceFiltering;
bool old_ssaa = g_ActiveConfig.bSSAA;
bool old_use_xfb = g_ActiveConfig.bUseXFB;
bool old_use_realxfb = g_ActiveConfig.bUseRealXFB;
@@ -1142,11 +1139,8 @@ void Renderer::CheckForConfigChanges()
UpdateActiveConfig();
// 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 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 aspect_changed = old_aspect_ratio != g_ActiveConfig.iAspectRatio;
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.
// 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();
FramebufferManager::GetInstance()->RecreateRenderPass();
FramebufferManager::GetInstance()->ResizeEFBTextures();
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();
FramebufferManager::GetInstance()->RecompileShaders();
g_object_cache->ReloadShaderAndPipelineCaches();
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.
@@ -115,7 +115,20 @@ bool StateTracker::Initialize()
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>
{
@@ -130,12 +143,16 @@ void StateTracker::LoadPipelineUIDCache()
StateTracker* this_ptr;
};
std::string filename = g_object_cache->GetDiskCacheFileName("pipeline-uid");
PipelineInserter inserter(this);
m_uid_cache.Sync();
m_uid_cache.Close();
// OpenAndRead calls Close() first, which will flush all data to disk when reloading.
// This assertion must hold true, otherwise data corruption will result.
m_uid_cache.OpenAndRead(filename, inserter);
// UID caches don't contain any host state, so use a single uid cache per gameid.
std::string filename = GetDiskShaderCacheFileName(APIType::Vulkan, "PipelineUID", true, false);
if (g_ActiveConfig.bShaderCache)
{
PipelineInserter inserter(this);
m_uid_cache.OpenAndRead(filename, inserter);
}
}
void StateTracker::AppendToPipelineUIDCache(const PipelineInfo& info)
@@ -873,7 +890,7 @@ VkPipeline StateTracker::GetPipelineAndCacheUID(const PipelineInfo& info)
auto result = g_object_cache->GetPipelineWithCacheResult(info);
// Add to the UID cache if it is a new pipeline.
if (!result.second)
if (!result.second && g_ActiveConfig.bShaderCache)
AppendToPipelineUIDCache(info);
return result.first;
@@ -117,7 +117,10 @@ public:
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.
void LoadPipelineUIDCache();
void ReloadPipelineUIDCache();
// Clears shader pointers, ensuring that now-deleted modules are not used.
void InvalidateShaderPointers();
private:
// Serialized version of PipelineInfo, used when loading/saving the pipeline UID cache.
+2 -1
View File
@@ -290,7 +290,8 @@ void VideoBackend::Video_Cleanup()
g_command_buffer_mgr->WaitForGPUIdle();
// 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_texture_cache.reset();
+1
View File
@@ -29,6 +29,7 @@ set(SRCS
PostProcessing.cpp
RenderBase.cpp
RenderState.cpp
ShaderGenCommon.cpp
Statistics.cpp
TextureCacheBase.cpp
TextureConfig.cpp
+70 -65
View File
@@ -18,10 +18,12 @@ static const char* primitives_ogl[] = {"points", "lines", "triangles"};
static const char* primitives_d3d[] = {"point", "line", "triangle"};
template <class T>
static void EmitVertex(T& out, const char* vertex, APIType ApiType, bool first_vertex = false);
template <class T>
static void EndPrimitive(T& out, APIType ApiType);
bool geometry_shader_uid_data::IsPassthrough() const
{
const bool stereo = g_ActiveConfig.iStereoMode > 0;
const bool wireframe = g_ActiveConfig.bWireFrame;
return primitive_type == PRIMITIVE_TRIANGLES && !stereo && !wireframe;
}
GeometryShaderUid GetGeometryShaderUid(u32 primitive_type)
{
@@ -30,48 +32,51 @@ GeometryShaderUid GetGeometryShaderUid(u32 primitive_type)
memset(uid_data, 0, sizeof(geometry_shader_uid_data));
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->pixel_lighting = g_ActiveConfig.bEnablePixelLighting;
return out;
}
static void EmitVertex(ShaderCode& out, const geometry_shader_uid_data* uid_data,
const char* vertex, APIType ApiType, bool first_vertex = false);
static void EndPrimitive(ShaderCode& out, const geometry_shader_uid_data* uid_data,
APIType ApiType);
static void EmitVertex(ShaderCode& out, const ShaderHostConfig& host_config,
const geometry_shader_uid_data* uid_data, const char* vertex,
APIType ApiType, bool wireframe, bool pixel_lighting,
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;
// 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;
unsigned int vertex_out = uid_data->primitive_type == PRIMITIVE_TRIANGLES ? 3 : 4;
if (uid_data->wireframe)
if (wireframe)
vertex_out++;
if (ApiType == APIType::OpenGL || ApiType == APIType::Vulkan)
{
// 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],
uid_data->stereo ? 2 : 1);
out.Write("layout(%s_strip, max_vertices = %d) out;\n",
uid_data->wireframe ? "line" : "triangle", vertex_out);
stereo ? 2 : 1);
out.Write("layout(%s_strip, max_vertices = %d) out;\n", wireframe ? "line" : "triangle",
vertex_out);
}
else
{
out.Write("layout(%s) in;\n", primitives_ogl[uid_data->primitive_type]);
out.Write("layout(%s_strip, max_vertices = %d) out;\n",
uid_data->wireframe ? "line" : "triangle",
uid_data->stereo ? vertex_out * 2 : vertex_out);
out.Write("layout(%s_strip, max_vertices = %d) out;\n", wireframe ? "line" : "triangle",
stereo ? vertex_out * 2 : vertex_out);
}
}
@@ -89,27 +94,24 @@ ShaderCode GenerateGeometryShaderCode(APIType ApiType, const geometry_shader_uid
"};\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");
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("VARYING_LOCATION(0) in VertexData {\n");
GenerateVSOutputMembers<ShaderCode>(
out, ApiType, uid_data->numTexGens, uid_data->pixel_lighting,
GetInterpolationQualifier(uid_data->msaa, uid_data->ssaa, true, true));
GenerateVSOutputMembers<ShaderCode>(out, ApiType, uid_data->numTexGens, pixel_lighting,
GetInterpolationQualifier(msaa, ssaa, true, true));
out.Write("} vs[%d];\n", vertex_in);
out.Write("VARYING_LOCATION(0) out VertexData {\n");
GenerateVSOutputMembers<ShaderCode>(
out, ApiType, uid_data->numTexGens, uid_data->pixel_lighting,
GetInterpolationQualifier(uid_data->msaa, uid_data->ssaa, true, false));
GenerateVSOutputMembers<ShaderCode>(out, ApiType, uid_data->numTexGens, pixel_lighting,
GetInterpolationQualifier(msaa, ssaa, true, false));
if (uid_data->stereo)
if (stereo)
out.Write("\tflat int layer;\n");
out.Write("} ps;\n");
@@ -121,25 +123,25 @@ ShaderCode GenerateGeometryShaderCode(APIType ApiType, const geometry_shader_uid
out.Write("struct VertexData {\n");
out.Write("\tVS_OUTPUT o;\n");
if (uid_data->stereo)
if (stereo)
out.Write("\tuint layer : SV_RenderTargetArrayIndex;\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 "
"InstanceID : SV_GSInstanceID)\n{\n",
primitives_d3d[uid_data->primitive_type], vertex_in,
uid_data->wireframe ? "Line" : "Triangle");
wireframe ? "Line" : "Triangle");
}
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",
primitives_d3d[uid_data->primitive_type], vertex_in,
uid_data->wireframe ? "Line" : "Triangle");
wireframe ? "Line" : "Triangle");
}
out.Write("\tVertexData ps;\n");
@@ -150,8 +152,8 @@ ShaderCode GenerateGeometryShaderCode(APIType ApiType, const geometry_shader_uid
if (ApiType == APIType::OpenGL || ApiType == APIType::Vulkan)
{
out.Write("\tVS_OUTPUT start, end;\n");
AssignVSOutputMembers(out, "start", "vs[0]", uid_data->numTexGens, uid_data->pixel_lighting);
AssignVSOutputMembers(out, "end", "vs[1]", 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, pixel_lighting);
}
else
{
@@ -181,7 +183,7 @@ ShaderCode GenerateGeometryShaderCode(APIType ApiType, const geometry_shader_uid
if (ApiType == APIType::OpenGL || ApiType == APIType::Vulkan)
{
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
{
@@ -194,17 +196,17 @@ ShaderCode GenerateGeometryShaderCode(APIType ApiType, const geometry_shader_uid
".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
// 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");
else
out.Write("\tfor (int eye = 0; eye < 2; ++eye) {\n");
}
if (uid_data->wireframe)
if (wireframe)
out.Write("\tVS_OUTPUT first;\n");
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)
{
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))
{
// 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");
}
if (uid_data->stereo)
if (stereo)
{
// Select the output layer
out.Write("\tps.layer = eye;\n");
@@ -264,8 +266,8 @@ ShaderCode GenerateGeometryShaderCode(APIType ApiType, const geometry_shader_uid
}
out.Write("\t}\n");
EmitVertex(out, uid_data, "l", ApiType, true);
EmitVertex(out, uid_data, "r", ApiType);
EmitVertex(out, host_config, uid_data, "l", ApiType, wireframe, pixel_lighting, true);
EmitVertex(out, host_config, uid_data, "r", ApiType, wireframe, pixel_lighting);
}
else if (uid_data->primitive_type == PRIMITIVE_POINTS)
{
@@ -293,21 +295,21 @@ ShaderCode GenerateGeometryShaderCode(APIType ApiType, const geometry_shader_uid
}
out.Write("\t}\n");
EmitVertex(out, uid_data, "ll", ApiType, true);
EmitVertex(out, uid_data, "lr", ApiType);
EmitVertex(out, uid_data, "ul", ApiType);
EmitVertex(out, uid_data, "ur", ApiType);
EmitVertex(out, host_config, uid_data, "ll", ApiType, wireframe, pixel_lighting, true);
EmitVertex(out, host_config, uid_data, "lr", ApiType, wireframe, pixel_lighting);
EmitVertex(out, host_config, uid_data, "ul", ApiType, wireframe, pixel_lighting);
EmitVertex(out, host_config, uid_data, "ur", ApiType, wireframe, pixel_lighting);
}
else
{
EmitVertex(out, uid_data, "f", ApiType, true);
EmitVertex(out, host_config, uid_data, "f", ApiType, wireframe, pixel_lighting, true);
}
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("}\n");
@@ -315,28 +317,29 @@ ShaderCode GenerateGeometryShaderCode(APIType ApiType, const geometry_shader_uid
return out;
}
static void EmitVertex(ShaderCode& out, const geometry_shader_uid_data* uid_data,
const char* vertex, APIType ApiType, bool first_vertex)
static void EmitVertex(ShaderCode& out, const ShaderHostConfig& host_config,
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);
if (ApiType == APIType::OpenGL)
{
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[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)
{
// Vulkan NDC space has Y pointing down (right-handed NDC space).
out.Write("\tgl_Position = %s.pos;\n", vertex);
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
{
@@ -349,10 +352,12 @@ static void EmitVertex(ShaderCode& out, const geometry_shader_uid_data* uid_data
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)
EmitVertex(out, uid_data, "first", ApiType);
if (wireframe)
EmitVertex(out, host_config, uid_data, "first", ApiType, wireframe, pixel_lighting);
if (ApiType == APIType::OpenGL || ApiType == APIType::Vulkan)
out.Write("\tEndPrimitive();\n");

Some files were not shown because too many files have changed in this diff Show More