Merge pull request #3513 from phire/make_hdkr_happy

Get shadergen ready for Multithreadded generation of shaders.
This commit is contained in:
Scott Mansell 2016-06-26 21:55:22 +12:00 committed by GitHub
commit ee9e3432cb
22 changed files with 724 additions and 845 deletions

View file

@ -26,7 +26,6 @@ namespace DX11
GeometryShaderCache::GSCache GeometryShaderCache::GeometryShaders;
const GeometryShaderCache::GSCacheEntry* GeometryShaderCache::last_entry;
GeometryShaderUid GeometryShaderCache::last_uid;
UidChecker<GeometryShaderUid, ShaderCode> GeometryShaderCache::geometry_uid_checker;
const GeometryShaderCache::GSCacheEntry GeometryShaderCache::pass_entry;
ID3D11GeometryShader* ClearGeometryShader = nullptr;
@ -165,9 +164,6 @@ void GeometryShaderCache::Init()
GeometryShaderCacheInserter inserter;
g_gs_disk_cache.OpenAndRead(cache_filename, inserter);
if (g_Config.bEnableShaderDebugging)
Clear();
last_entry = nullptr;
}
@ -177,7 +173,6 @@ void GeometryShaderCache::Clear()
for (auto& iter : GeometryShaders)
iter.second.Destroy();
GeometryShaders.clear();
geometry_uid_checker.Invalidate();
last_entry = nullptr;
}
@ -196,12 +191,7 @@ void GeometryShaderCache::Shutdown()
bool GeometryShaderCache::SetShader(u32 primitive_type)
{
GeometryShaderUid uid = GetGeometryShaderUid(primitive_type, API_D3D);
if (g_ActiveConfig.bEnableShaderDebugging)
{
ShaderCode code = GenerateGeometryShaderCode(primitive_type, API_D3D);
geometry_uid_checker.AddToIndexAndCheck(code, uid, "Geometry", "g");
}
GeometryShaderUid uid = GetGeometryShaderUid(primitive_type);
// Check if the shader is already set
if (last_entry)
@ -235,7 +225,7 @@ bool GeometryShaderCache::SetShader(u32 primitive_type)
}
// Need to compile a new shader
ShaderCode code = GenerateGeometryShaderCode(primitive_type, API_D3D);
ShaderCode code = GenerateGeometryShaderCode(API_D3D, uid.GetUidData());
D3DBlob* pbytecode;
if (!D3D::CompileGeometryShader(code.GetBuffer(), &pbytecode))
@ -250,11 +240,6 @@ bool GeometryShaderCache::SetShader(u32 primitive_type)
bool success = InsertByteCode(uid, pbytecode->Data(), pbytecode->Size());
pbytecode->Release();
if (g_ActiveConfig.bEnableShaderDebugging && success)
{
GeometryShaders[uid].code = code.GetBuffer();
}
return success;
}

View file

@ -32,8 +32,6 @@ private:
{
ID3D11GeometryShader* shader;
std::string code;
GSCacheEntry() : shader(nullptr) {}
void Destroy() { SAFE_RELEASE(shader); }
};
@ -44,8 +42,6 @@ private:
static const GSCacheEntry* last_entry;
static GeometryShaderUid last_uid;
static const GSCacheEntry pass_entry;
static UidChecker<GeometryShaderUid, ShaderCode> geometry_uid_checker;
};
} // namespace DX11

View file

@ -26,7 +26,6 @@ namespace DX11
PixelShaderCache::PSCache PixelShaderCache::PixelShaders;
const PixelShaderCache::PSCacheEntry* PixelShaderCache::last_entry;
PixelShaderUid PixelShaderCache::last_uid;
UidChecker<PixelShaderUid, ShaderCode> PixelShaderCache::pixel_uid_checker;
LinearDiskCache<PixelShaderUid, u8> g_ps_disk_cache;
@ -505,9 +504,6 @@ void PixelShaderCache::Init()
PixelShaderCacheInserter inserter;
g_ps_disk_cache.OpenAndRead(cache_filename, inserter);
if (g_Config.bEnableShaderDebugging)
Clear();
last_entry = nullptr;
}
@ -517,7 +513,6 @@ void PixelShaderCache::Clear()
for (auto& iter : PixelShaders)
iter.second.Destroy();
PixelShaders.clear();
pixel_uid_checker.Invalidate();
last_entry = nullptr;
}
@ -556,12 +551,7 @@ void PixelShaderCache::Shutdown()
bool PixelShaderCache::SetShader(DSTALPHA_MODE dstAlphaMode)
{
PixelShaderUid uid = GetPixelShaderUid(dstAlphaMode, API_D3D);
if (g_ActiveConfig.bEnableShaderDebugging)
{
ShaderCode code = GeneratePixelShaderCode(dstAlphaMode, API_D3D);
pixel_uid_checker.AddToIndexAndCheck(code, uid, "Pixel", "p");
}
PixelShaderUid uid = GetPixelShaderUid(dstAlphaMode);
// Check if the shader is already set
if (last_entry)
@ -588,7 +578,7 @@ bool PixelShaderCache::SetShader(DSTALPHA_MODE dstAlphaMode)
}
// Need to compile a new shader
ShaderCode code = GeneratePixelShaderCode(dstAlphaMode, API_D3D);
ShaderCode code = GeneratePixelShaderCode(dstAlphaMode, API_D3D, uid.GetUidData());
D3DBlob* pbytecode;
if (!D3D::CompilePixelShader(code.GetBuffer(), &pbytecode))
@ -603,11 +593,6 @@ bool PixelShaderCache::SetShader(DSTALPHA_MODE dstAlphaMode)
bool success = InsertByteCode(uid, pbytecode->Data(), pbytecode->Size());
pbytecode->Release();
if (g_ActiveConfig.bEnableShaderDebugging && success)
{
PixelShaders[uid].code = code.GetBuffer();
}
GFX_DEBUGGER_PAUSE_AT(NEXT_PIXEL_SHADER_CHANGE, true);
return success;
}

View file

@ -42,8 +42,6 @@ private:
{
ID3D11PixelShader* shader;
std::string code;
PSCacheEntry() : shader(nullptr) {}
void Destroy() { SAFE_RELEASE(shader); }
};
@ -53,8 +51,6 @@ private:
static PSCache PixelShaders;
static const PSCacheEntry* last_entry;
static PixelShaderUid last_uid;
static UidChecker<PixelShaderUid, ShaderCode> pixel_uid_checker;
};
} // namespace DX11

View file

@ -24,7 +24,6 @@ namespace DX11
VertexShaderCache::VSCache VertexShaderCache::vshaders;
const VertexShaderCache::VSCacheEntry* VertexShaderCache::last_entry;
VertexShaderUid VertexShaderCache::last_uid;
UidChecker<VertexShaderUid, ShaderCode> VertexShaderCache::vertex_uid_checker;
static ID3D11VertexShader* SimpleVertexShader = nullptr;
static ID3D11VertexShader* ClearVertexShader = nullptr;
@ -166,9 +165,6 @@ void VertexShaderCache::Init()
VertexShaderCacheInserter inserter;
g_vs_disk_cache.OpenAndRead(cache_filename, inserter);
if (g_Config.bEnableShaderDebugging)
Clear();
last_entry = nullptr;
}
@ -177,7 +173,6 @@ void VertexShaderCache::Clear()
for (auto& iter : vshaders)
iter.second.Destroy();
vshaders.clear();
vertex_uid_checker.Invalidate();
last_entry = nullptr;
}
@ -199,12 +194,7 @@ void VertexShaderCache::Shutdown()
bool VertexShaderCache::SetShader()
{
VertexShaderUid uid = GetVertexShaderUid(API_D3D);
if (g_ActiveConfig.bEnableShaderDebugging)
{
ShaderCode code = GenerateVertexShaderCode(API_D3D);
vertex_uid_checker.AddToIndexAndCheck(code, uid, "Vertex", "v");
}
VertexShaderUid uid = GetVertexShaderUid();
if (last_entry)
{
@ -227,7 +217,7 @@ bool VertexShaderCache::SetShader()
return (entry.shader != nullptr);
}
ShaderCode code = GenerateVertexShaderCode(API_D3D);
ShaderCode code = GenerateVertexShaderCode(API_D3D, uid.GetUidData());
D3DBlob* pbytecode = nullptr;
D3D::CompileVertexShader(code.GetBuffer(), &pbytecode);
@ -242,11 +232,6 @@ bool VertexShaderCache::SetShader()
bool success = InsertByteCode(uid, pbytecode);
pbytecode->Release();
if (g_ActiveConfig.bEnableShaderDebugging && success)
{
vshaders[uid].code = code.GetBuffer();
}
GFX_DEBUGGER_PAUSE_AT(NEXT_VERTEX_SHADER_CHANGE, true);
return success;
}

View file

@ -38,8 +38,6 @@ private:
ID3D11VertexShader* shader;
D3DBlob* bytecode; // needed to initialize the input layout
std::string code;
VSCacheEntry() : shader(nullptr), bytecode(nullptr) {}
void SetByteCode(D3DBlob* blob)
{
@ -58,8 +56,6 @@ private:
static VSCache vshaders;
static const VSCacheEntry* last_entry;
static VertexShaderUid last_uid;
static UidChecker<VertexShaderUid, ShaderCode> vertex_uid_checker;
};
} // namespace DX11

View file

@ -30,22 +30,10 @@ VsBytecodeCache s_vs_bytecode_cache;
// Used to keep track of blobs to release at Shutdown time.
static std::vector<ID3DBlob*> s_shader_blob_list;
// Only used for shader debugging..
using GsHlslCache = std::map<GeometryShaderUid, std::string>;
using PsHlslCache = std::map<PixelShaderUid, std::string>;
using VsHlslCache = std::map<VertexShaderUid, std::string>;
static GsHlslCache s_gs_hlsl_cache;
static PsHlslCache s_ps_hlsl_cache;
static VsHlslCache s_vs_hlsl_cache;
static LinearDiskCache<GeometryShaderUid, u8> s_gs_disk_cache;
static LinearDiskCache<PixelShaderUid, u8> s_ps_disk_cache;
static LinearDiskCache<VertexShaderUid, u8> s_vs_disk_cache;
static UidChecker<GeometryShaderUid, ShaderCode> s_geometry_uid_checker;
static UidChecker<PixelShaderUid, ShaderCode> s_pixel_uid_checker;
static UidChecker<VertexShaderUid, ShaderCode> s_vertex_uid_checker;
static D3D12_SHADER_BYTECODE s_last_geometry_shader_bytecode;
static D3D12_SHADER_BYTECODE s_last_pixel_shader_bytecode;
static D3D12_SHADER_BYTECODE s_last_vertex_shader_bytecode;
@ -104,10 +92,6 @@ void ShaderCache::Init()
ShaderCacheInserter<VertexShaderUid, VsBytecodeCache, &s_vs_bytecode_cache> vs_inserter;
s_vs_disk_cache.OpenAndRead(vs_cache_filename, vs_inserter);
// Clear out cache when debugging shaders to ensure stale ones don't stick around..
if (g_Config.bEnableShaderDebugging)
Clear();
SETSTAT(stats.numPixelShadersAlive, static_cast<int>(s_ps_bytecode_cache.size()));
SETSTAT(stats.numPixelShadersCreated, static_cast<int>(s_ps_bytecode_cache.size()));
SETSTAT(stats.numVertexShadersAlive, static_cast<int>(s_vs_bytecode_cache.size()));
@ -145,26 +129,15 @@ void ShaderCache::Shutdown()
s_ps_disk_cache.Close();
s_vs_disk_cache.Sync();
s_vs_disk_cache.Close();
if (g_Config.bEnableShaderDebugging)
{
s_gs_hlsl_cache.clear();
s_ps_hlsl_cache.clear();
s_vs_hlsl_cache.clear();
}
s_geometry_uid_checker.Invalidate();
s_pixel_uid_checker.Invalidate();
s_vertex_uid_checker.Invalidate();
}
void ShaderCache::LoadAndSetActiveShaders(DSTALPHA_MODE ps_dst_alpha_mode, u32 gs_primitive_type)
{
SetCurrentPrimitiveTopology(gs_primitive_type);
GeometryShaderUid gs_uid = GetGeometryShaderUid(gs_primitive_type, API_D3D);
PixelShaderUid ps_uid = GetPixelShaderUid(ps_dst_alpha_mode, API_D3D);
VertexShaderUid vs_uid = GetVertexShaderUid(API_D3D);
GeometryShaderUid gs_uid = GetGeometryShaderUid(gs_primitive_type);
PixelShaderUid ps_uid = GetPixelShaderUid(ps_dst_alpha_mode);
VertexShaderUid vs_uid = GetVertexShaderUid();
bool gs_changed = gs_uid != s_last_geometry_shader_uid;
bool ps_changed = ps_uid != s_last_pixel_shader_uid;
@ -217,12 +190,6 @@ void ShaderCache::HandleGSUIDChange(GeometryShaderUid gs_uid, u32 gs_primitive_t
{
s_last_geometry_shader_uid = gs_uid;
if (g_ActiveConfig.bEnableShaderDebugging)
{
ShaderCode code = GenerateGeometryShaderCode(gs_primitive_type, API_D3D);
s_geometry_uid_checker.AddToIndexAndCheck(code, gs_uid, "Geometry", "g");
}
if (gs_uid.GetUidData()->IsPassthrough())
{
s_last_geometry_shader_bytecode = {};
@ -236,7 +203,7 @@ void ShaderCache::HandleGSUIDChange(GeometryShaderUid gs_uid, u32 gs_primitive_t
}
else
{
ShaderCode gs_code = GenerateGeometryShaderCode(gs_primitive_type, API_D3D);
ShaderCode gs_code = GenerateGeometryShaderCode(API_D3D, gs_uid.GetUidData());
ID3DBlob* gs_bytecode = nullptr;
if (!D3D::CompileGeometryShader(gs_code.GetBuffer(), &gs_bytecode))
@ -248,11 +215,6 @@ void ShaderCache::HandleGSUIDChange(GeometryShaderUid gs_uid, u32 gs_primitive_t
s_last_geometry_shader_bytecode = InsertByteCode(gs_uid, &s_gs_bytecode_cache, gs_bytecode);
s_gs_disk_cache.Append(gs_uid, reinterpret_cast<u8*>(gs_bytecode->GetBufferPointer()),
static_cast<u32>(gs_bytecode->GetBufferSize()));
if (g_ActiveConfig.bEnableShaderDebugging)
{
s_gs_hlsl_cache[gs_uid] = gs_code.GetBuffer();
}
}
}
@ -260,12 +222,6 @@ void ShaderCache::HandlePSUIDChange(PixelShaderUid ps_uid, DSTALPHA_MODE ps_dst_
{
s_last_pixel_shader_uid = ps_uid;
if (g_ActiveConfig.bEnableShaderDebugging)
{
ShaderCode code = GeneratePixelShaderCode(ps_dst_alpha_mode, API_D3D);
s_pixel_uid_checker.AddToIndexAndCheck(code, ps_uid, "Pixel", "p");
}
auto ps_iterator = s_ps_bytecode_cache.find(ps_uid);
if (ps_iterator != s_ps_bytecode_cache.end())
{
@ -274,7 +230,7 @@ void ShaderCache::HandlePSUIDChange(PixelShaderUid ps_uid, DSTALPHA_MODE ps_dst_
}
else
{
ShaderCode ps_code = GeneratePixelShaderCode(ps_dst_alpha_mode, API_D3D);
ShaderCode ps_code = GeneratePixelShaderCode(ps_dst_alpha_mode, API_D3D, ps_uid.GetUidData());
ID3DBlob* ps_bytecode = nullptr;
if (!D3D::CompilePixelShader(ps_code.GetBuffer(), &ps_bytecode))
@ -289,11 +245,6 @@ void ShaderCache::HandlePSUIDChange(PixelShaderUid ps_uid, DSTALPHA_MODE ps_dst_
SETSTAT(stats.numPixelShadersAlive, static_cast<int>(s_ps_bytecode_cache.size()));
INCSTAT(stats.numPixelShadersCreated);
if (g_ActiveConfig.bEnableShaderDebugging)
{
s_ps_hlsl_cache[ps_uid] = ps_code.GetBuffer();
}
}
}
@ -301,12 +252,6 @@ void ShaderCache::HandleVSUIDChange(VertexShaderUid vs_uid)
{
s_last_vertex_shader_uid = vs_uid;
if (g_ActiveConfig.bEnableShaderDebugging)
{
ShaderCode code = GenerateVertexShaderCode(API_D3D);
s_vertex_uid_checker.AddToIndexAndCheck(code, vs_uid, "Vertex", "v");
}
auto vs_iterator = s_vs_bytecode_cache.find(vs_uid);
if (vs_iterator != s_vs_bytecode_cache.end())
{
@ -315,7 +260,7 @@ void ShaderCache::HandleVSUIDChange(VertexShaderUid vs_uid)
}
else
{
ShaderCode vs_code = GenerateVertexShaderCode(API_D3D);
ShaderCode vs_code = GenerateVertexShaderCode(API_D3D, vs_uid.GetUidData());
ID3DBlob* vs_bytecode = nullptr;
if (!D3D::CompileVertexShader(vs_code.GetBuffer(), &vs_bytecode))
@ -330,11 +275,6 @@ void ShaderCache::HandleVSUIDChange(VertexShaderUid vs_uid)
SETSTAT(stats.numVertexShadersAlive, static_cast<int>(s_vs_bytecode_cache.size()));
INCSTAT(stats.numVertexShadersCreated);
if (g_ActiveConfig.bEnableShaderDebugging)
{
s_vs_hlsl_cache[vs_uid] = vs_code.GetBuffer();
}
}
}

View file

@ -59,7 +59,7 @@ bool ShaderCache<Uid>::SetShader(DSTALPHA_MODE dst_alpha_mode, u32 primitive_typ
}
// Need to compile a new shader
ShaderCode code = GenerateCode(dst_alpha_mode, primitive_type, API_OPENGL);
ShaderCode code = GenerateCode(dst_alpha_mode, API_OPENGL, uid);
m_shaders.emplace(uid, code.GetBuffer());
GFX_DEBUGGER_PAUSE_AT(NEXT_PIXEL_SHADER_CHANGE, true);

View file

@ -26,14 +26,12 @@ public:
protected:
virtual Uid GetUid(DSTALPHA_MODE dst_alpha_mode, u32 primitive_type, API_TYPE api_type) = 0;
virtual ShaderCode GenerateCode(DSTALPHA_MODE dst_alpha_mode, u32 primitive_type,
API_TYPE api_type) = 0;
virtual ShaderCode GenerateCode(DSTALPHA_MODE dst_alpha_mode, API_TYPE api_type, Uid uid) = 0;
private:
std::map<Uid, std::string> m_shaders;
const std::string* m_last_entry = nullptr;
Uid m_last_uid;
UidChecker<Uid, ShaderCode> m_uid_checker;
};
class VertexShaderCache : public ShaderCache<VertexShaderUid>
@ -45,12 +43,12 @@ protected:
VertexShaderUid GetUid(DSTALPHA_MODE dst_alpha_mode, u32 primitive_type,
API_TYPE api_type) override
{
return GetVertexShaderUid(api_type);
return GetVertexShaderUid();
}
ShaderCode GenerateCode(DSTALPHA_MODE dst_alpha_mode, u32 primitive_type,
API_TYPE api_type) override
ShaderCode GenerateCode(DSTALPHA_MODE dst_alpha_mode, API_TYPE api_type,
VertexShaderUid uid) override
{
return GenerateVertexShaderCode(api_type);
return GenerateVertexShaderCode(api_type, uid.GetUidData());
}
};
@ -63,12 +61,12 @@ protected:
GeometryShaderUid GetUid(DSTALPHA_MODE dst_alpha_mode, u32 primitive_type,
API_TYPE api_type) override
{
return GetGeometryShaderUid(primitive_type, api_type);
return GetGeometryShaderUid(primitive_type);
}
ShaderCode GenerateCode(DSTALPHA_MODE dst_alpha_mode, u32 primitive_type,
API_TYPE api_type) override
ShaderCode GenerateCode(DSTALPHA_MODE dst_alpha_mode, API_TYPE api_type,
GeometryShaderUid uid) override
{
return GenerateGeometryShaderCode(primitive_type, api_type);
return GenerateGeometryShaderCode(api_type, uid.GetUidData());
}
};
@ -81,12 +79,12 @@ protected:
PixelShaderUid GetUid(DSTALPHA_MODE dst_alpha_mode, u32 primitive_type,
API_TYPE api_type) override
{
return GetPixelShaderUid(dst_alpha_mode, api_type);
return GetPixelShaderUid(dst_alpha_mode);
}
ShaderCode GenerateCode(DSTALPHA_MODE dst_alpha_mode, u32 primitive_type,
API_TYPE api_type) override
ShaderCode GenerateCode(DSTALPHA_MODE dst_alpha_mode, API_TYPE api_type,
PixelShaderUid uid) override
{
return GeneratePixelShaderCode(dst_alpha_mode, api_type);
return GeneratePixelShaderCode(dst_alpha_mode, api_type, uid.GetUidData());
}
};

View file

@ -36,9 +36,6 @@ static GLuint CurrentProgram = 0;
ProgramShaderCache::PCache ProgramShaderCache::pshaders;
ProgramShaderCache::PCacheEntry* ProgramShaderCache::last_entry;
SHADERUID ProgramShaderCache::last_uid;
UidChecker<PixelShaderUid, ShaderCode> ProgramShaderCache::pixel_uid_checker;
UidChecker<VertexShaderUid, ShaderCode> ProgramShaderCache::vertex_uid_checker;
UidChecker<GeometryShaderUid, ShaderCode> ProgramShaderCache::geometry_uid_checker;
static std::string s_glsl_header = "";
@ -209,19 +206,12 @@ SHADER* ProgramShaderCache::SetShader(DSTALPHA_MODE dstAlphaMode, u32 primitive_
last_entry = &newentry;
newentry.in_cache = 0;
ShaderCode vcode = GenerateVertexShaderCode(API_OPENGL);
ShaderCode pcode = GeneratePixelShaderCode(dstAlphaMode, API_OPENGL);
ShaderCode vcode = GenerateVertexShaderCode(API_OPENGL, uid.vuid.GetUidData());
ShaderCode pcode = GeneratePixelShaderCode(dstAlphaMode, API_OPENGL, uid.puid.GetUidData());
ShaderCode gcode;
if (g_ActiveConfig.backend_info.bSupportsGeometryShaders &&
!uid.guid.GetUidData()->IsPassthrough())
gcode = GenerateGeometryShaderCode(primitive_type, API_OPENGL);
if (g_ActiveConfig.bEnableShaderDebugging)
{
newentry.shader.strvprog = vcode.GetBuffer();
newentry.shader.strpprog = pcode.GetBuffer();
newentry.shader.strgprog = gcode.GetBuffer();
}
gcode = GenerateGeometryShaderCode(API_OPENGL, uid.guid.GetUidData());
#if defined(_DEBUG) || defined(DEBUGFAST)
if (g_ActiveConfig.iLog & CONF_SAVESHADERS)
@ -397,21 +387,9 @@ GLuint ProgramShaderCache::CompileSingleShader(GLuint type, const std::string& c
void ProgramShaderCache::GetShaderId(SHADERUID* uid, DSTALPHA_MODE dstAlphaMode, u32 primitive_type)
{
uid->puid = GetPixelShaderUid(dstAlphaMode, API_OPENGL);
uid->vuid = GetVertexShaderUid(API_OPENGL);
uid->guid = GetGeometryShaderUid(primitive_type, API_OPENGL);
if (g_ActiveConfig.bEnableShaderDebugging)
{
ShaderCode pcode = GeneratePixelShaderCode(dstAlphaMode, API_OPENGL);
pixel_uid_checker.AddToIndexAndCheck(pcode, uid->puid, "Pixel", "p");
ShaderCode vcode = GenerateVertexShaderCode(API_OPENGL);
vertex_uid_checker.AddToIndexAndCheck(vcode, uid->vuid, "Vertex", "v");
ShaderCode gcode = GenerateGeometryShaderCode(primitive_type, API_OPENGL);
geometry_uid_checker.AddToIndexAndCheck(gcode, uid->guid, "Geometry", "g");
}
uid->puid = GetPixelShaderUid(dstAlphaMode);
uid->vuid = GetVertexShaderUid();
uid->guid = GetGeometryShaderUid(primitive_type);
}
ProgramShaderCache::PCacheEntry ProgramShaderCache::GetShaderProgram()
@ -436,7 +414,7 @@ void ProgramShaderCache::Init()
s_buffer = StreamBuffer::Create(GL_UNIFORM_BUFFER, UBO_LENGTH);
// Read our shader cache, only if supported
if (g_ogl_config.bSupportsGLSLCache && !g_Config.bEnableShaderDebugging)
if (g_ogl_config.bSupportsGLSLCache)
{
GLint Supported;
glGetIntegerv(GL_NUM_PROGRAM_BINARY_FORMATS, &Supported);
@ -470,7 +448,7 @@ void ProgramShaderCache::Init()
void ProgramShaderCache::Shutdown()
{
// store all shaders in cache on disk
if (g_ogl_config.bSupportsGLSLCache && !g_Config.bEnableShaderDebugging)
if (g_ogl_config.bSupportsGLSLCache)
{
for (auto& entry : pshaders)
{
@ -516,9 +494,6 @@ void ProgramShaderCache::Shutdown()
}
pshaders.clear();
pixel_uid_checker.Invalidate();
vertex_uid_checker.Invalidate();
s_buffer.reset();
}

View file

@ -88,10 +88,6 @@ private:
static PCacheEntry* last_entry;
static SHADERUID last_uid;
static UidChecker<PixelShaderUid, ShaderCode> pixel_uid_checker;
static UidChecker<VertexShaderUid, ShaderCode> vertex_uid_checker;
static UidChecker<GeometryShaderUid, ShaderCode> geometry_uid_checker;
static u32 s_ubo_buffer_size;
static s32 s_ubo_align;
};

View file

@ -20,43 +20,55 @@ static void EmitVertex(T& out, const char* vertex, API_TYPE ApiType, bool first_
template <class T>
static void EndPrimitive(T& out, API_TYPE ApiType);
template <class T>
static T GenerateGeometryShader(u32 primitive_type, API_TYPE ApiType)
GeometryShaderUid GetGeometryShaderUid(u32 primitive_type)
{
T out;
// Non-uid template parameters will write to the dummy data (=> gets optimized out)
geometry_shader_uid_data dummy_data;
geometry_shader_uid_data* uid_data = out.template GetUidData<geometry_shader_uid_data>();
if (uid_data != nullptr)
memset(uid_data, 0, sizeof(*uid_data));
else
uid_data = &dummy_data;
ShaderUid<geometry_shader_uid_data> out;
geometry_shader_uid_data* uid_data = out.GetUidData<geometry_shader_uid_data>();
memset(uid_data, 0, sizeof(geometry_shader_uid_data));
uid_data->primitive_type = primitive_type;
const unsigned int vertex_in = primitive_type + 1;
unsigned int vertex_out = primitive_type == PRIMITIVE_TRIANGLES ? 3 : 4;
uid_data->wireframe = g_ActiveConfig.bWireFrame;
if (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, API_TYPE ApiType, bool first_vertex = false);
static void EndPrimitive(ShaderCode& out, const geometry_shader_uid_data* uid_data,
API_TYPE ApiType);
ShaderCode GenerateGeometryShaderCode(API_TYPE ApiType, const geometry_shader_uid_data* uid_data)
{
ShaderCode out;
// Non-uid template parameters will write to the dummy data (=> gets optimized out)
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)
vertex_out++;
uid_data->stereo = g_ActiveConfig.iStereoMode > 0;
if (ApiType == API_OPENGL)
{
// Insert layout parameters
if (g_ActiveConfig.backend_info.bSupportsGSInstancing)
{
out.Write("layout(%s, invocations = %d) in;\n", primitives_ogl[primitive_type],
g_ActiveConfig.iStereoMode > 0 ? 2 : 1);
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",
g_ActiveConfig.bWireFrame ? "line" : "triangle", vertex_out);
uid_data->wireframe ? "line" : "triangle", vertex_out);
}
else
{
out.Write("layout(%s) in;\n", primitives_ogl[primitive_type]);
out.Write("layout(%s) in;\n", primitives_ogl[uid_data->primitive_type]);
out.Write("layout(%s_strip, max_vertices = %d) out;\n",
g_ActiveConfig.bWireFrame ? "line" : "triangle",
g_ActiveConfig.iStereoMode > 0 ? vertex_out * 2 : vertex_out);
uid_data->wireframe ? "line" : "triangle",
uid_data->stereo ? vertex_out * 2 : vertex_out);
}
}
@ -73,11 +85,9 @@ static T GenerateGeometryShader(u32 primitive_type, API_TYPE ApiType)
"\tint4 " I_TEXOFFSET ";\n"
"};\n");
uid_data->numTexGens = xfmem.numTexGen.numTexGens;
uid_data->pixel_lighting = g_ActiveConfig.bEnablePixelLighting;
out.Write("struct VS_OUTPUT {\n");
GenerateVSOutputMembers<T>(out, ApiType, "");
GenerateVSOutputMembers<ShaderCode>(out, ApiType, uid_data->numTexGens, uid_data->pixel_lighting,
"");
out.Write("};\n");
if (ApiType == API_OPENGL)
@ -86,13 +96,17 @@ static T GenerateGeometryShader(u32 primitive_type, API_TYPE ApiType)
out.Write("#define InstanceID gl_InvocationID\n");
out.Write("in VertexData {\n");
GenerateVSOutputMembers<T>(out, ApiType, GetInterpolationQualifier(true, true));
GenerateVSOutputMembers<ShaderCode>(
out, ApiType, uid_data->numTexGens, uid_data->pixel_lighting,
GetInterpolationQualifier(uid_data->msaa, uid_data->ssaa, true, true));
out.Write("} vs[%d];\n", vertex_in);
out.Write("out VertexData {\n");
GenerateVSOutputMembers<T>(out, ApiType, GetInterpolationQualifier(true, false));
GenerateVSOutputMembers<ShaderCode>(
out, ApiType, uid_data->numTexGens, uid_data->pixel_lighting,
GetInterpolationQualifier(uid_data->msaa, uid_data->ssaa, false, true));
if (g_ActiveConfig.iStereoMode > 0)
if (uid_data->stereo)
out.Write("\tflat int layer;\n");
out.Write("} ps;\n");
@ -104,39 +118,37 @@ static T GenerateGeometryShader(u32 primitive_type, API_TYPE ApiType)
out.Write("struct VertexData {\n");
out.Write("\tVS_OUTPUT o;\n");
if (g_ActiveConfig.iStereoMode > 0)
if (uid_data->stereo)
out.Write("\tuint layer : SV_RenderTargetArrayIndex;\n");
out.Write("};\n");
if (g_ActiveConfig.backend_info.bSupportsGSInstancing)
{
out.Write("[maxvertexcount(%d)]\n[instance(%d)]\n", vertex_out,
g_ActiveConfig.iStereoMode > 0 ? 2 : 1);
out.Write("[maxvertexcount(%d)]\n[instance(%d)]\n", vertex_out, uid_data->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[primitive_type], vertex_in,
g_ActiveConfig.bWireFrame ? "Line" : "Triangle");
primitives_d3d[uid_data->primitive_type], vertex_in,
uid_data->wireframe ? "Line" : "Triangle");
}
else
{
out.Write("[maxvertexcount(%d)]\n",
g_ActiveConfig.iStereoMode > 0 ? vertex_out * 2 : vertex_out);
out.Write("[maxvertexcount(%d)]\n", uid_data->stereo ? vertex_out * 2 : vertex_out);
out.Write("void main(%s VS_OUTPUT o[%d], inout %sStream<VertexData> output)\n{\n",
primitives_d3d[primitive_type], vertex_in,
g_ActiveConfig.bWireFrame ? "Line" : "Triangle");
primitives_d3d[uid_data->primitive_type], vertex_in,
uid_data->wireframe ? "Line" : "Triangle");
}
out.Write("\tVertexData ps;\n");
}
if (primitive_type == PRIMITIVE_LINES)
if (uid_data->primitive_type == PRIMITIVE_LINES)
{
if (ApiType == API_OPENGL)
{
out.Write("\tVS_OUTPUT start, end;\n");
AssignVSOutputMembers(out, "start", "vs[0]");
AssignVSOutputMembers(out, "end", "vs[1]");
AssignVSOutputMembers(out, "start", "vs[0]", uid_data->numTexGens, uid_data->pixel_lighting);
AssignVSOutputMembers(out, "end", "vs[1]", uid_data->numTexGens, uid_data->pixel_lighting);
}
else
{
@ -161,16 +173,16 @@ static T GenerateGeometryShader(u32 primitive_type, API_TYPE ApiType)
"\t\toffset = float2(0, -" I_LINEPTPARAMS ".z / " I_LINEPTPARAMS ".y);\n"
"\t}\n");
}
else if (primitive_type == PRIMITIVE_POINTS)
else if (uid_data->primitive_type == PRIMITIVE_POINTS)
{
if (ApiType == API_OPENGL)
{
out.Write("\tVS_OUTPUT center;\n");
AssignVSOutputMembers(out, "center", "vs[0]");
AssignVSOutputMembers(out, "center", "vs[0]", uid_data->numTexGens, uid_data->pixel_lighting);
}
else
{
out.Write("\tVS_OUTPUT center = o[0];\n");
out.Write("\tVS_OUTPUT center = o[0];\n", uid_data->numTexGens, uid_data->pixel_lighting);
}
// Offset from center to upper right vertex
@ -179,7 +191,7 @@ static T GenerateGeometryShader(u32 primitive_type, API_TYPE ApiType)
".x, -" I_LINEPTPARAMS ".w / " I_LINEPTPARAMS ".y) * center.pos.w;\n");
}
if (g_ActiveConfig.iStereoMode > 0)
if (uid_data->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.
@ -189,7 +201,7 @@ static T GenerateGeometryShader(u32 primitive_type, API_TYPE ApiType)
out.Write("\tfor (int eye = 0; eye < 2; ++eye) {\n");
}
if (g_ActiveConfig.bWireFrame)
if (uid_data->wireframe)
out.Write("\tVS_OUTPUT first;\n");
out.Write("\tfor (int i = 0; i < %d; ++i) {\n", vertex_in);
@ -197,14 +209,14 @@ static T GenerateGeometryShader(u32 primitive_type, API_TYPE ApiType)
if (ApiType == API_OPENGL)
{
out.Write("\tVS_OUTPUT f;\n");
AssignVSOutputMembers(out, "f", "vs[i]");
AssignVSOutputMembers(out, "f", "vs[i]", uid_data->numTexGens, uid_data->pixel_lighting);
}
else
{
out.Write("\tVS_OUTPUT f = o[i];\n");
}
if (g_ActiveConfig.iStereoMode > 0)
if (uid_data->stereo)
{
// Select the output layer
out.Write("\tps.layer = eye;\n");
@ -221,7 +233,7 @@ static T GenerateGeometryShader(u32 primitive_type, API_TYPE ApiType)
out.Write("\tf.pos.x += " I_STEREOPARAMS "[eye] * (f.pos.w - " I_STEREOPARAMS "[2]);\n");
}
if (primitive_type == PRIMITIVE_LINES)
if (uid_data->primitive_type == PRIMITIVE_LINES)
{
out.Write("\tVS_OUTPUT l = f;\n"
"\tVS_OUTPUT r = f;\n");
@ -232,17 +244,17 @@ static T GenerateGeometryShader(u32 primitive_type, API_TYPE ApiType)
out.Write("\tif (" I_TEXOFFSET "[2] != 0) {\n");
out.Write("\tfloat texOffset = 1.0 / float(" I_TEXOFFSET "[2]);\n");
for (unsigned int i = 0; i < xfmem.numTexGen.numTexGens; ++i)
for (unsigned int i = 0; i < uid_data->numTexGens; ++i)
{
out.Write("\tif (((" I_TEXOFFSET "[0] >> %d) & 0x1) != 0)\n", i);
out.Write("\t\tr.tex%d.x += texOffset;\n", i);
}
out.Write("\t}\n");
EmitVertex<T>(out, "l", ApiType, true);
EmitVertex<T>(out, "r", ApiType);
EmitVertex(out, uid_data, "l", ApiType, true);
EmitVertex(out, uid_data, "r", ApiType);
}
else if (primitive_type == PRIMITIVE_POINTS)
else if (uid_data->primitive_type == PRIMITIVE_POINTS)
{
out.Write("\tVS_OUTPUT ll = f;\n"
"\tVS_OUTPUT lr = f;\n"
@ -258,7 +270,7 @@ static T GenerateGeometryShader(u32 primitive_type, API_TYPE ApiType)
out.Write("\tfloat2 texOffset = float2(1.0 / float(" I_TEXOFFSET
"[3]), 1.0 / float(" I_TEXOFFSET "[3]));\n");
for (unsigned int i = 0; i < xfmem.numTexGen.numTexGens; ++i)
for (unsigned int i = 0; i < uid_data->numTexGens; ++i)
{
out.Write("\tif (((" I_TEXOFFSET "[1] >> %d) & 0x1) != 0) {\n", i);
out.Write("\t\tll.tex%d.xy += float2(0,1) * texOffset;\n", i);
@ -268,21 +280,21 @@ static T GenerateGeometryShader(u32 primitive_type, API_TYPE ApiType)
}
out.Write("\t}\n");
EmitVertex<T>(out, "ll", ApiType, true);
EmitVertex<T>(out, "lr", ApiType);
EmitVertex<T>(out, "ul", ApiType);
EmitVertex<T>(out, "ur", ApiType);
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);
}
else
{
EmitVertex<T>(out, "f", ApiType, true);
EmitVertex(out, uid_data, "f", ApiType, true);
}
out.Write("\t}\n");
EndPrimitive<T>(out, ApiType);
EndPrimitive(out, uid_data, ApiType);
if (g_ActiveConfig.iStereoMode > 0 && !g_ActiveConfig.backend_info.bSupportsGSInstancing)
if (uid_data->stereo && !g_ActiveConfig.backend_info.bSupportsGSInstancing)
out.Write("\t}\n");
out.Write("}\n");
@ -290,16 +302,16 @@ static T GenerateGeometryShader(u32 primitive_type, API_TYPE ApiType)
return out;
}
template <class T>
static void EmitVertex(T& out, const char* vertex, API_TYPE ApiType, bool first_vertex)
static void EmitVertex(ShaderCode& out, const geometry_shader_uid_data* uid_data,
const char* vertex, API_TYPE ApiType, bool first_vertex)
{
if (g_ActiveConfig.bWireFrame && first_vertex)
if (uid_data->wireframe && first_vertex)
out.Write("\tif (i == 0) first = %s;\n", vertex);
if (ApiType == API_OPENGL)
{
out.Write("\tgl_Position = %s.pos;\n", vertex);
AssignVSOutputMembers(out, "ps", vertex);
AssignVSOutputMembers(out, "ps", vertex, uid_data->numTexGens, uid_data->pixel_lighting);
}
else
{
@ -311,24 +323,15 @@ static void EmitVertex(T& out, const char* vertex, API_TYPE ApiType, bool first_
else
out.Write("\toutput.Append(ps);\n");
}
template <class T>
static void EndPrimitive(T& out, API_TYPE ApiType)
static void EndPrimitive(ShaderCode& out, const geometry_shader_uid_data* uid_data,
API_TYPE ApiType)
{
if (g_ActiveConfig.bWireFrame)
EmitVertex<T>(out, "first", ApiType);
if (uid_data->wireframe)
EmitVertex(out, uid_data, "first", ApiType);
if (ApiType == API_OPENGL)
out.Write("\tEndPrimitive();\n");
else
out.Write("\toutput.RestartStrip();\n");
}
GeometryShaderUid GetGeometryShaderUid(u32 primitive_type, API_TYPE ApiType)
{
return GenerateGeometryShader<GeometryShaderUid>(primitive_type, ApiType);
}
ShaderCode GenerateGeometryShaderCode(u32 primitive_type, API_TYPE ApiType)
{
return GenerateGeometryShader<ShaderCode>(primitive_type, ApiType);
}

View file

@ -23,11 +23,13 @@ struct geometry_shader_uid_data
u32 pixel_lighting : 1;
u32 primitive_type : 2;
u32 wireframe : 1;
u32 msaa : 1;
u32 ssaa : 1;
};
#pragma pack()
typedef ShaderUid<geometry_shader_uid_data> GeometryShaderUid;
ShaderCode GenerateGeometryShaderCode(u32 primitive_type, API_TYPE ApiType);
GeometryShaderUid GetGeometryShaderUid(u32 primitive_type, API_TYPE ApiType);
ShaderCode GenerateGeometryShaderCode(API_TYPE ApiType, const geometry_shader_uid_data* uid_data);
GeometryShaderUid GetGeometryShaderUid(u32 primitive_type);

View file

@ -46,19 +46,16 @@ static const char s_lighting_struct[] = "struct Light {\n"
"\tfloat4 dir;\n"
"};\n";
template <class T>
static void GenerateLightShader(T& object, LightingUidData& uid_data, int index, int litchan_index,
int coloralpha)
static void GenerateLightShader(ShaderCode& object, const LightingUidData& uid_data, int index,
int litchan_index, bool alpha)
{
const LitChannel& chan =
(litchan_index > 1) ? xfmem.alpha[litchan_index - 2] : xfmem.color[litchan_index];
const char* swizzle = (coloralpha == 1) ? "xyz" : (coloralpha == 2) ? "w" : "xyzw";
const char* swizzle_components = (coloralpha == 1) ? "3" : (coloralpha == 2) ? "" : "4";
const char* swizzle = alpha ? "a" : "rgb";
const char* swizzle_components = (alpha) ? "" : "3";
uid_data.attnfunc |= chan.attnfunc << (2 * litchan_index);
uid_data.diffusefunc |= chan.diffusefunc << (2 * litchan_index);
int attnfunc = (uid_data.attnfunc >> (2 * litchan_index)) & 0x3;
int diffusefunc = (uid_data.diffusefunc >> (2 * litchan_index)) & 0x3;
switch (chan.attnfunc)
switch (attnfunc)
{
case LIGHTATTN_NONE:
case LIGHTATTN_DIR:
@ -73,8 +70,7 @@ static void GenerateLightShader(T& object, LightingUidData& uid_data, int index,
LIGHT_DIR_PARAMS(index));
object.Write("cosAttn = " LIGHT_COSATT ".xyz;\n", LIGHT_COSATT_PARAMS(index));
object.Write("distAttn = %s(" LIGHT_DISTATT ".xyz);\n",
(chan.diffusefunc == LIGHTDIF_NONE) ? "" : "normalize",
LIGHT_DISTATT_PARAMS(index));
(diffusefunc == LIGHTDIF_NONE) ? "" : "normalize", LIGHT_DISTATT_PARAMS(index));
object.Write("attn = max(0.0f, dot(cosAttn, float3(1.0, attn, attn*attn))) / dot(distAttn, "
"float3(1.0, attn, attn*attn));\n");
break;
@ -91,11 +87,9 @@ static void GenerateLightShader(T& object, LightingUidData& uid_data, int index,
LIGHT_COSATT_PARAMS(index), LIGHT_COSATT_PARAMS(index), LIGHT_COSATT_PARAMS(index),
LIGHT_DISTATT_PARAMS(index));
break;
default:
_assert_(0);
}
switch (chan.diffusefunc)
switch (diffusefunc)
{
case LIGHTDIF_NONE:
object.Write("lacc.%s += int%s(round(attn * float%s(" LIGHT_COL ")));\n", swizzle,
@ -104,7 +98,7 @@ static void GenerateLightShader(T& object, LightingUidData& uid_data, int index,
case LIGHTDIF_SIGN:
case LIGHTDIF_CLAMP:
object.Write("lacc.%s += int%s(round(attn * %sdot(ldir, _norm0)) * float%s(" LIGHT_COL ")));\n",
swizzle, swizzle_components, chan.diffusefunc != LIGHTDIF_SIGN ? "max(0.0," : "(",
swizzle, swizzle_components, diffusefunc != LIGHTDIF_SIGN ? "max(0.0," : "(",
swizzle_components, LIGHT_COL_PARAMS(index, swizzle));
break;
default:
@ -119,19 +113,15 @@ static void GenerateLightShader(T& object, LightingUidData& uid_data, int index,
// materials name is I_MATERIALS in vs and I_PMATERIALS in ps
// inColorName is color in vs and colors_ in ps
// dest is o.colors_ in vs and colors_ in ps
template <class T>
static void GenerateLightingShader(T& object, LightingUidData& uid_data, int components,
const char* inColorName, const char* dest)
static void GenerateLightingShaderCode(ShaderCode& object, const LightingUidData& uid_data,
int components, const char* inColorName, const char* dest)
{
for (unsigned int j = 0; j < xfmem.numChan.numColorChans; j++)
{
const LitChannel& color = xfmem.color[j];
const LitChannel& alpha = xfmem.alpha[j];
object.Write("{\n");
uid_data.matsource |= xfmem.color[j].matsource << j;
if (color.matsource) // from vertex
bool colormatsource = !!(uid_data.matsource & (1 << j));
if (colormatsource) // from vertex
{
if (components & (VB_HAS_COL0 << j))
object.Write("int4 mat = int4(round(%s%d * 255.0));\n", inColorName, j);
@ -145,11 +135,9 @@ static void GenerateLightingShader(T& object, LightingUidData& uid_data, int com
object.Write("int4 mat = %s[%d];\n", I_MATERIALS, j + 2);
}
uid_data.enablelighting |= xfmem.color[j].enablelighting << j;
if (color.enablelighting)
if (uid_data.enablelighting & (1 << j))
{
uid_data.ambsource |= xfmem.color[j].ambsource << j;
if (color.ambsource) // from vertex
if (uid_data.ambsource & (1 << j)) // from vertex
{
if (components & (VB_HAS_COL0 << j))
object.Write("lacc = int4(round(%s%d * 255.0));\n", inColorName, j);
@ -158,7 +146,7 @@ static void GenerateLightingShader(T& object, LightingUidData& uid_data, int com
else
// TODO: this isn't verified. Here we want to read the ambient from the vertex,
// but the vertex itself has no color. So we don't know which value to read.
// Returing 1.0 is the same as disabled lightning, so this could be fine
// Returning 1.0 is the same as disabled lightning, so this could be fine
object.Write("lacc = int4(255, 255, 255, 255);\n");
}
else // from color
@ -172,10 +160,10 @@ static void GenerateLightingShader(T& object, LightingUidData& uid_data, int com
}
// check if alpha is different
uid_data.matsource |= xfmem.alpha[j].matsource << (j + 2);
if (alpha.matsource != color.matsource)
bool alphamatsource = !!(uid_data.matsource & (1 << (j + 2)));
if (alphamatsource != colormatsource)
{
if (alpha.matsource) // from vertex
if (alphamatsource) // from vertex
{
if (components & (VB_HAS_COL0 << j))
object.Write("mat.w = int(round(%s%d.w * 255.0));\n", inColorName, j);
@ -190,11 +178,9 @@ static void GenerateLightingShader(T& object, LightingUidData& uid_data, int com
}
}
uid_data.enablelighting |= xfmem.alpha[j].enablelighting << (j + 2);
if (alpha.enablelighting)
if (uid_data.enablelighting & (1 << (j + 2)))
{
uid_data.ambsource |= xfmem.alpha[j].ambsource << (j + 2);
if (alpha.ambsource) // from vertex
if (uid_data.ambsource & (1 << (j + 2))) // from vertex
{
if (components & (VB_HAS_COL0 << j))
object.Write("lacc.w = int(round(%s%d.w * 255.0));\n", inColorName, j);
@ -214,56 +200,46 @@ static void GenerateLightingShader(T& object, LightingUidData& uid_data, int com
object.Write("lacc.w = 255;\n");
}
if (color.enablelighting && alpha.enablelighting)
if (uid_data.enablelighting & (1 << j)) // Color lights
{
// both have lighting, test if they use the same lights
int mask = 0;
uid_data.attnfunc |= color.attnfunc << (2 * j);
uid_data.attnfunc |= alpha.attnfunc << (2 * (j + 2));
uid_data.diffusefunc |= color.diffusefunc << (2 * j);
uid_data.diffusefunc |= alpha.diffusefunc << (2 * (j + 2));
uid_data.light_mask |= color.GetFullLightMask() << (8 * j);
uid_data.light_mask |= alpha.GetFullLightMask() << (8 * (j + 2));
if (color.lightparams == alpha.lightparams)
{
mask = color.GetFullLightMask() & alpha.GetFullLightMask();
if (mask)
{
for (int i = 0; i < 8; ++i)
{
if (mask & (1 << i))
{
GenerateLightShader<T>(object, uid_data, i, j, 3);
}
}
}
}
// no shared lights
for (int i = 0; i < 8; ++i)
{
if (!(mask & (1 << i)) && (color.GetFullLightMask() & (1 << i)))
GenerateLightShader<T>(object, uid_data, i, j, 1);
if (!(mask & (1 << i)) && (alpha.GetFullLightMask() & (1 << i)))
GenerateLightShader<T>(object, uid_data, i, j + 2, 2);
}
if (uid_data.light_mask & (1 << (i + 8 * j)))
GenerateLightShader(object, uid_data, i, j, false);
}
else if (color.enablelighting || alpha.enablelighting)
if (uid_data.enablelighting & (1 << (j + 2))) // Alpha lights
{
// lights are disabled on one channel so process only the active ones
const LitChannel& workingchannel = color.enablelighting ? color : alpha;
const int lit_index = color.enablelighting ? j : (j + 2);
int coloralpha = color.enablelighting ? 1 : 2;
uid_data.light_mask |= workingchannel.GetFullLightMask() << (8 * lit_index);
for (int i = 0; i < 8; ++i)
{
if (workingchannel.GetFullLightMask() & (1 << i))
GenerateLightShader<T>(object, uid_data, i, lit_index, coloralpha);
}
if (uid_data.light_mask & (1 << (i + 8 * (j + 2))))
GenerateLightShader(object, uid_data, i, j + 2, true);
}
object.Write("lacc = clamp(lacc, 0, 255);\n");
object.Write("%s%d = float4((mat * (lacc + (lacc >> 7))) >> 8) / 255.0;\n", dest, j);
object.Write("}\n");
}
}
static void GetLightingShaderUid(LightingUidData& uid_data)
{
for (unsigned int j = 0; j < xfmem.numChan.numColorChans; j++)
{
uid_data.matsource |= xfmem.color[j].matsource << j;
uid_data.matsource |= xfmem.alpha[j].matsource << (j + 2);
uid_data.enablelighting |= xfmem.color[j].enablelighting << j;
uid_data.enablelighting |= xfmem.alpha[j].enablelighting << (j + 2);
if (uid_data.enablelighting & (1 << j)) // Color lights
{
uid_data.ambsource |= xfmem.color[j].ambsource << j;
uid_data.attnfunc |= xfmem.color[j].attnfunc << (2 * j);
uid_data.diffusefunc |= xfmem.color[j].diffusefunc << (2 * j);
uid_data.light_mask |= xfmem.color[j].GetFullLightMask() << (8 * j);
}
if (uid_data.enablelighting & (1 << (j + 2))) // Alpha lights
{
uid_data.ambsource |= xfmem.alpha[j].ambsource << (j + 2);
uid_data.attnfunc |= xfmem.alpha[j].attnfunc << (2 * (j + 2));
uid_data.diffusefunc |= xfmem.alpha[j].diffusefunc << (2 * (j + 2));
uid_data.light_mask |= xfmem.alpha[j].GetFullLightMask() << (8 * (j + 2));
}
}
}

View file

@ -31,6 +31,7 @@ enum
VB_HAS_NRM2 = (1 << 12),
VB_HAS_NRMALL = (7 << 10),
VB_COL_SHIFT = 13,
VB_HAS_COL0 = (1 << 13),
VB_HAS_COL1 = (1 << 14),

File diff suppressed because it is too large Load diff

View file

@ -24,12 +24,11 @@ struct pixel_shader_uid_data
u32 num_values; // TODO: Shouldn't be a u32
u32 NumValues() const { return num_values; }
u32 components : 23;
u32 components : 2;
u32 dstAlphaMode : 2;
u32 Pretest : 2;
u32 nIndirectStagesUsed : 4;
u32 stereo : 1;
u32 genMode_numtexgens : 4;
u32 genMode_numtevstages : 4;
u32 genMode_numindstages : 3;
@ -38,20 +37,21 @@ struct pixel_shader_uid_data
u32 alpha_test_logic : 2;
u32 alpha_test_use_zcomploc_hack : 1;
u32 fog_proj : 1;
u32 fog_fsel : 3;
u32 fog_RangeBaseEnabled : 1;
u32 ztex_op : 2;
u32 fast_depth_calc : 1;
u32 per_pixel_depth : 1;
u32 per_pixel_lighting : 1;
u32 forced_early_z : 1;
u32 early_ztest : 1;
u32 late_ztest : 1;
u32 bounding_box : 1;
// TODO: 29 bits of padding is a waste. Can we free up some bits elseware?
u32 zfreeze : 1;
u32 msaa : 1;
u32 ssaa : 1;
u32 pad : 29;
u32 pad : 16;
u32 texMtxInfo_n_projection : 8; // 8x1 bit
u32 tevindref_bi0 : 3;
@ -63,7 +63,7 @@ struct pixel_shader_uid_data
u32 tevindref_bi4 : 3;
u32 tevindref_bc4 : 3;
inline void SetTevindrefValues(int index, u32 texcoord, u32 texmap)
void SetTevindrefValues(int index, u32 texcoord, u32 texmap)
{
if (index == 0)
{
@ -86,31 +86,54 @@ struct pixel_shader_uid_data
tevindref_bi4 = texmap;
}
}
inline void SetTevindrefTexmap(int index, u32 texmap)
u32 GetTevindirefCoord(int index) const
{
if (index == 0)
{
tevindref_bi0 = texmap;
return tevindref_bc0;
}
else if (index == 1)
{
tevindref_bi1 = texmap;
return tevindref_bc1;
}
else if (index == 2)
{
tevindref_bi2 = texmap;
return tevindref_bc3;
}
else if (index == 3)
{
tevindref_bi4 = texmap;
return tevindref_bc4;
}
return 0;
}
u32 GetTevindirefMap(int index) const
{
if (index == 0)
{
return tevindref_bi0;
}
else if (index == 1)
{
return tevindref_bi1;
}
else if (index == 2)
{
return tevindref_bi2;
}
else if (index == 3)
{
return tevindref_bi4;
}
return 0;
}
struct
{
// TODO: Can save a lot space by removing the padding bits
u32 cc : 24;
u32 ac : 24;
u32 ac : 24; // tswap and rswap are left blank (encoded into the tevksel fields below)
u32 tevorders_texmap : 3;
u32 tevorders_texcoord : 3;
@ -136,13 +159,12 @@ struct pixel_shader_uid_data
u32 pad3 : 14;
} stagehash[16];
// TODO: I think we're fine without an enablePixelLighting field, should probably double check,
// though..
LightingUidData lighting;
};
#pragma pack()
typedef ShaderUid<pixel_shader_uid_data> PixelShaderUid;
ShaderCode GeneratePixelShaderCode(DSTALPHA_MODE dstAlphaMode, API_TYPE ApiType);
PixelShaderUid GetPixelShaderUid(DSTALPHA_MODE dstAlphaMode, API_TYPE ApiType);
ShaderCode GeneratePixelShaderCode(DSTALPHA_MODE dstAlphaMode, API_TYPE ApiType,
const pixel_shader_uid_data* uid_data);
PixelShaderUid GetPixelShaderUid(DSTALPHA_MODE dstAlphaMode);

View file

@ -154,74 +154,6 @@ public:
private:
std::vector<bool> constant_usage; // TODO: Is vector<bool> appropriate here?
};
/**
* Checks if there has been
*/
template <class UidT, class CodeT>
class UidChecker
{
public:
void Invalidate()
{
m_shaders.clear();
m_uids.clear();
}
void AddToIndexAndCheck(CodeT& new_code, const UidT& new_uid, const char* shader_type,
const char* dump_prefix)
{
bool uid_is_indexed = std::find(m_uids.begin(), m_uids.end(), new_uid) != m_uids.end();
if (!uid_is_indexed)
{
m_uids.push_back(new_uid);
m_shaders[new_uid] = new_code.GetBuffer();
}
else
{
// uid is already in the index => check if there's a shader with the same uid but different
// code
auto& old_code = m_shaders[new_uid];
if (old_code != new_code.GetBuffer())
{
static int num_failures = 0;
std::string temp =
StringFromFormat("%s%ssuid_mismatch_%04i.txt", File::GetUserPath(D_DUMP_IDX).c_str(),
dump_prefix, ++num_failures);
// TODO: Should also dump uids
std::ofstream file;
OpenFStream(file, temp, std::ios_base::out);
file << "Old shader code:\n" << old_code;
file << "\n\nNew shader code:\n" << new_code.GetBuffer();
file << "\n\nShader uid:\n";
for (unsigned int i = 0; i < new_uid.GetUidDataSize(); ++i)
{
u8 value = new_uid.GetUidDataRaw()[i];
if ((i % 4) == 0)
{
auto last_value =
(i + 3 < new_uid.GetUidDataSize() - 1) ? i + 3 : new_uid.GetUidDataSize();
file << std::setfill(' ') << std::dec;
file << "Values " << std::setw(2) << i << " - " << last_value << ": ";
}
file << std::setw(2) << std::setfill('0') << std::hex << value << std::setw(1);
if ((i % 4) < 3)
file << ' ';
else
file << std::endl;
}
ERROR_LOG(VIDEO, "%s shader uid mismatch! See %s for details", shader_type, temp.c_str());
}
}
}
private:
std::map<UidT, std::string> m_shaders;
std::vector<UidT> m_uids;
};
template <class T>
inline void DefineOutputMember(T& object, API_TYPE api_type, const char* qualifier,
@ -245,40 +177,41 @@ inline void DefineOutputMember(T& object, API_TYPE api_type, const char* qualifi
}
template <class T>
inline void GenerateVSOutputMembers(T& object, API_TYPE api_type, const char* qualifier)
inline void GenerateVSOutputMembers(T& object, API_TYPE api_type, u32 texgens,
bool per_pixel_lighting, const char* qualifier)
{
DefineOutputMember(object, api_type, qualifier, "float4", "pos", -1, "POSITION");
DefineOutputMember(object, api_type, qualifier, "float4", "colors_", 0, "COLOR", 0);
DefineOutputMember(object, api_type, qualifier, "float4", "colors_", 1, "COLOR", 1);
for (unsigned int i = 0; i < xfmem.numTexGen.numTexGens; ++i)
for (unsigned int i = 0; i < texgens; ++i)
DefineOutputMember(object, api_type, qualifier, "float3", "tex", i, "TEXCOORD", i);
DefineOutputMember(object, api_type, qualifier, "float4", "clipPos", -1, "TEXCOORD",
xfmem.numTexGen.numTexGens);
DefineOutputMember(object, api_type, qualifier, "float4", "clipPos", -1, "TEXCOORD", texgens);
if (g_ActiveConfig.bEnablePixelLighting)
if (per_pixel_lighting)
{
DefineOutputMember(object, api_type, qualifier, "float3", "Normal", -1, "TEXCOORD",
xfmem.numTexGen.numTexGens + 1);
texgens + 1);
DefineOutputMember(object, api_type, qualifier, "float3", "WorldPos", -1, "TEXCOORD",
xfmem.numTexGen.numTexGens + 2);
texgens + 2);
}
}
template <class T>
inline void AssignVSOutputMembers(T& object, const char* a, const char* b)
inline void AssignVSOutputMembers(T& object, const char* a, const char* b, u32 texgens,
bool per_pixel_lighting)
{
object.Write("\t%s.pos = %s.pos;\n", a, b);
object.Write("\t%s.colors_0 = %s.colors_0;\n", a, b);
object.Write("\t%s.colors_1 = %s.colors_1;\n", a, b);
for (unsigned int i = 0; i < xfmem.numTexGen.numTexGens; ++i)
for (unsigned int i = 0; i < texgens; ++i)
object.Write("\t%s.tex%d = %s.tex%d;\n", a, i, b, i);
object.Write("\t%s.clipPos = %s.clipPos;\n", a, b);
if (g_ActiveConfig.bEnablePixelLighting)
if (per_pixel_lighting)
{
object.Write("\t%s.Normal = %s.Normal;\n", a, b);
object.Write("\t%s.WorldPos = %s.WorldPos;\n", a, b);
@ -293,23 +226,24 @@ inline void AssignVSOutputMembers(T& object, const char* a, const char* b)
// As a workaround, we interpolate at the centroid of the coveraged pixel, which
// is always inside the primitive.
// Without MSAA, this flag is defined to have no effect.
inline const char* GetInterpolationQualifier(bool in_glsl_interface_block = false, bool in = false)
inline const char* GetInterpolationQualifier(bool msaa, bool ssaa,
bool in_glsl_interface_block = false, bool in = false)
{
if (g_ActiveConfig.iMultisamples <= 1)
if (!msaa)
return "";
// Without GL_ARB_shading_language_420pack support, the interpolation qualifier must be
// "centroid in" and not "centroid", even within an interface block.
if (in_glsl_interface_block && !g_ActiveConfig.backend_info.bSupportsBindingLayout)
{
if (!g_ActiveConfig.bSSAA)
if (!ssaa)
return in ? "centroid in" : "centroid out";
else
return in ? "sample in" : "sample out";
}
else
{
if (!g_ActiveConfig.bSSAA)
if (!ssaa)
return "centroid";
else
return "sample";

View file

@ -14,22 +14,73 @@
#include "VideoCommon/VertexShaderGen.h"
#include "VideoCommon/VideoConfig.h"
template <class T>
static T GenerateVertexShader(API_TYPE api_type)
VertexShaderUid GetVertexShaderUid()
{
T out;
const u32 components = VertexLoaderManager::g_current_components;
// Non-uid template parameters will write to the dummy data (=> gets optimized out)
vertex_shader_uid_data dummy_data;
vertex_shader_uid_data* uid_data = out.template GetUidData<vertex_shader_uid_data>();
if (uid_data != nullptr)
memset(uid_data, 0, sizeof(*uid_data));
else
uid_data = &dummy_data;
VertexShaderUid out;
vertex_shader_uid_data* uid_data = out.GetUidData<vertex_shader_uid_data>();
memset(uid_data, 0, sizeof(*uid_data));
_assert_(bpmem.genMode.numtexgens == xfmem.numTexGen.numTexGens);
_assert_(bpmem.genMode.numcolchans == xfmem.numChan.numColorChans);
uid_data->numTexGens = xfmem.numTexGen.numTexGens;
uid_data->components = VertexLoaderManager::g_current_components;
uid_data->pixel_lighting = g_ActiveConfig.bEnablePixelLighting;
uid_data->msaa = g_ActiveConfig.iMultisamples > 1;
uid_data->ssaa = g_ActiveConfig.iMultisamples > 1 && g_ActiveConfig.bSSAA;
uid_data->numColorChans = xfmem.numChan.numColorChans;
GetLightingShaderUid(uid_data->lighting);
// transform texcoords
for (unsigned int i = 0; i < uid_data->numTexGens; ++i)
{
auto& texinfo = uid_data->texMtxInfo[i];
texinfo.sourcerow = xfmem.texMtxInfo[i].sourcerow;
texinfo.texgentype = xfmem.texMtxInfo[i].texgentype;
texinfo.inputform = xfmem.texMtxInfo[i].inputform;
// first transformation
switch (texinfo.texgentype)
{
case XF_TEXGEN_EMBOSS_MAP: // calculate tex coords into bump map
if (uid_data->components & (VB_HAS_NRM1 | VB_HAS_NRM2))
{
// transform the light dir into tangent space
texinfo.embosslightshift = xfmem.texMtxInfo[i].embosslightshift;
texinfo.embosssourceshift = xfmem.texMtxInfo[i].embosssourceshift;
}
else
{
texinfo.embosssourceshift = xfmem.texMtxInfo[i].embosssourceshift;
}
break;
case XF_TEXGEN_COLOR_STRGBC0:
case XF_TEXGEN_COLOR_STRGBC1:
break;
case XF_TEXGEN_REGULAR:
default:
uid_data->texMtxInfo_n_projection |= xfmem.texMtxInfo[i].projection << i;
break;
}
uid_data->dualTexTrans_enabled = xfmem.dualTexTrans.enabled;
// CHECKME: does this only work for regular tex gen types?
if (uid_data->dualTexTrans_enabled && texinfo.texgentype == XF_TEXGEN_REGULAR)
{
auto& postInfo = uid_data->postMtxInfo[i];
postInfo.index = xfmem.postMtxInfo[i].index;
postInfo.normalize = xfmem.postMtxInfo[i].normalize;
}
}
return out;
}
ShaderCode GenerateVertexShaderCode(API_TYPE api_type, const vertex_shader_uid_data* uid_data)
{
ShaderCode out;
out.Write("%s", s_lighting_struct);
// uniforms
@ -42,34 +93,30 @@ static T GenerateVertexShader(API_TYPE api_type)
out.Write("};\n");
out.Write("struct VS_OUTPUT {\n");
GenerateVSOutputMembers<T>(out, api_type, "");
GenerateVSOutputMembers(out, api_type, uid_data->numTexGens, uid_data->pixel_lighting, "");
out.Write("};\n");
uid_data->numTexGens = xfmem.numTexGen.numTexGens;
uid_data->components = components;
uid_data->pixel_lighting = g_ActiveConfig.bEnablePixelLighting;
if (api_type == API_OPENGL)
{
out.Write("in float4 rawpos; // ATTR%d,\n", SHADER_POSITION_ATTRIB);
if (components & VB_HAS_POSMTXIDX)
if (uid_data->components & VB_HAS_POSMTXIDX)
out.Write("in int posmtx; // ATTR%d,\n", SHADER_POSMTX_ATTRIB);
if (components & VB_HAS_NRM0)
if (uid_data->components & VB_HAS_NRM0)
out.Write("in float3 rawnorm0; // ATTR%d,\n", SHADER_NORM0_ATTRIB);
if (components & VB_HAS_NRM1)
if (uid_data->components & VB_HAS_NRM1)
out.Write("in float3 rawnorm1; // ATTR%d,\n", SHADER_NORM1_ATTRIB);
if (components & VB_HAS_NRM2)
if (uid_data->components & VB_HAS_NRM2)
out.Write("in float3 rawnorm2; // ATTR%d,\n", SHADER_NORM2_ATTRIB);
if (components & VB_HAS_COL0)
if (uid_data->components & VB_HAS_COL0)
out.Write("in float4 color0; // ATTR%d,\n", SHADER_COLOR0_ATTRIB);
if (components & VB_HAS_COL1)
if (uid_data->components & VB_HAS_COL1)
out.Write("in float4 color1; // ATTR%d,\n", SHADER_COLOR1_ATTRIB);
for (int i = 0; i < 8; ++i)
{
u32 hastexmtx = (components & (VB_HAS_TEXMTXIDX0 << i));
if ((components & (VB_HAS_UV0 << i)) || hastexmtx)
u32 hastexmtx = (uid_data->components & (VB_HAS_TEXMTXIDX0 << i));
if ((uid_data->components & (VB_HAS_UV0 << i)) || hastexmtx)
out.Write("in float%d tex%d; // ATTR%d,\n", hastexmtx ? 3 : 2, i,
SHADER_TEXTURE0_ATTRIB + i);
}
@ -77,7 +124,9 @@ static T GenerateVertexShader(API_TYPE api_type)
if (g_ActiveConfig.backend_info.bSupportsGeometryShaders)
{
out.Write("out VertexData {\n");
GenerateVSOutputMembers<T>(out, api_type, GetInterpolationQualifier(true, false));
GenerateVSOutputMembers(
out, api_type, uid_data->numTexGens, uid_data->pixel_lighting,
GetInterpolationQualifier(uid_data->msaa, uid_data->ssaa, false, true));
out.Write("} vs;\n");
}
else
@ -85,19 +134,25 @@ static T GenerateVertexShader(API_TYPE api_type)
// Let's set up attributes
for (u32 i = 0; i < 8; ++i)
{
if (i < xfmem.numTexGen.numTexGens)
if (i < uid_data->numTexGens)
{
out.Write("%s out float3 uv%u;\n", GetInterpolationQualifier(), i);
out.Write("%s out float3 uv%u;\n",
GetInterpolationQualifier(uid_data->msaa, uid_data->ssaa), i);
}
}
out.Write("%s out float4 clipPos;\n", GetInterpolationQualifier());
if (g_ActiveConfig.bEnablePixelLighting)
out.Write("%s out float4 clipPos;\n",
GetInterpolationQualifier(uid_data->msaa, uid_data->ssaa));
if (uid_data->pixel_lighting)
{
out.Write("%s out float3 Normal;\n", GetInterpolationQualifier());
out.Write("%s out float3 WorldPos;\n", GetInterpolationQualifier());
out.Write("%s out float3 Normal;\n",
GetInterpolationQualifier(uid_data->msaa, uid_data->ssaa));
out.Write("%s out float3 WorldPos;\n",
GetInterpolationQualifier(uid_data->msaa, uid_data->ssaa));
}
out.Write("%s out float4 colors_0;\n", GetInterpolationQualifier());
out.Write("%s out float4 colors_1;\n", GetInterpolationQualifier());
out.Write("%s out float4 colors_0;\n",
GetInterpolationQualifier(uid_data->msaa, uid_data->ssaa));
out.Write("%s out float4 colors_1;\n",
GetInterpolationQualifier(uid_data->msaa, uid_data->ssaa));
}
out.Write("void main()\n{\n");
@ -107,23 +162,23 @@ static T GenerateVertexShader(API_TYPE api_type)
out.Write("VS_OUTPUT main(\n");
// inputs
if (components & VB_HAS_NRM0)
if (uid_data->components & VB_HAS_NRM0)
out.Write(" float3 rawnorm0 : NORMAL0,\n");
if (components & VB_HAS_NRM1)
if (uid_data->components & VB_HAS_NRM1)
out.Write(" float3 rawnorm1 : NORMAL1,\n");
if (components & VB_HAS_NRM2)
if (uid_data->components & VB_HAS_NRM2)
out.Write(" float3 rawnorm2 : NORMAL2,\n");
if (components & VB_HAS_COL0)
if (uid_data->components & VB_HAS_COL0)
out.Write(" float4 color0 : COLOR0,\n");
if (components & VB_HAS_COL1)
if (uid_data->components & VB_HAS_COL1)
out.Write(" float4 color1 : COLOR1,\n");
for (int i = 0; i < 8; ++i)
{
u32 hastexmtx = (components & (VB_HAS_TEXMTXIDX0 << i));
if ((components & (VB_HAS_UV0 << i)) || hastexmtx)
u32 hastexmtx = (uid_data->components & (VB_HAS_TEXMTXIDX0 << i));
if ((uid_data->components & (VB_HAS_UV0 << i)) || hastexmtx)
out.Write(" float%d tex%d : TEXCOORD%d,\n", hastexmtx ? 3 : 2, i, i);
}
if (components & VB_HAS_POSMTXIDX)
if (uid_data->components & VB_HAS_POSMTXIDX)
out.Write(" int posmtx : BLENDINDICES,\n");
out.Write(" float4 rawpos : POSITION) {\n");
}
@ -131,26 +186,26 @@ static T GenerateVertexShader(API_TYPE api_type)
out.Write("VS_OUTPUT o;\n");
// transforms
if (components & VB_HAS_POSMTXIDX)
if (uid_data->components & VB_HAS_POSMTXIDX)
{
out.Write("float4 pos = float4(dot(" I_TRANSFORMMATRICES
"[posmtx], rawpos), dot(" I_TRANSFORMMATRICES
"[posmtx+1], rawpos), dot(" I_TRANSFORMMATRICES "[posmtx+2], rawpos), 1);\n");
if (components & VB_HAS_NRMALL)
if (uid_data->components & VB_HAS_NRMALL)
{
out.Write("int normidx = posmtx & 31;\n");
out.Write("float3 N0 = " I_NORMALMATRICES "[normidx].xyz, N1 = " I_NORMALMATRICES
"[normidx+1].xyz, N2 = " I_NORMALMATRICES "[normidx+2].xyz;\n");
}
if (components & VB_HAS_NRM0)
if (uid_data->components & VB_HAS_NRM0)
out.Write("float3 _norm0 = normalize(float3(dot(N0, rawnorm0), dot(N1, rawnorm0), dot(N2, "
"rawnorm0)));\n");
if (components & VB_HAS_NRM1)
if (uid_data->components & VB_HAS_NRM1)
out.Write(
"float3 _norm1 = float3(dot(N0, rawnorm1), dot(N1, rawnorm1), dot(N2, rawnorm1));\n");
if (components & VB_HAS_NRM2)
if (uid_data->components & VB_HAS_NRM2)
out.Write(
"float3 _norm2 = float3(dot(N0, rawnorm2), dot(N1, rawnorm2), dot(N2, rawnorm2));\n");
}
@ -158,21 +213,21 @@ static T GenerateVertexShader(API_TYPE api_type)
{
out.Write("float4 pos = float4(dot(" I_POSNORMALMATRIX "[0], rawpos), dot(" I_POSNORMALMATRIX
"[1], rawpos), dot(" I_POSNORMALMATRIX "[2], rawpos), 1.0);\n");
if (components & VB_HAS_NRM0)
if (uid_data->components & VB_HAS_NRM0)
out.Write("float3 _norm0 = normalize(float3(dot(" I_POSNORMALMATRIX
"[3].xyz, rawnorm0), dot(" I_POSNORMALMATRIX
"[4].xyz, rawnorm0), dot(" I_POSNORMALMATRIX "[5].xyz, rawnorm0)));\n");
if (components & VB_HAS_NRM1)
if (uid_data->components & VB_HAS_NRM1)
out.Write("float3 _norm1 = float3(dot(" I_POSNORMALMATRIX
"[3].xyz, rawnorm1), dot(" I_POSNORMALMATRIX
"[4].xyz, rawnorm1), dot(" I_POSNORMALMATRIX "[5].xyz, rawnorm1));\n");
if (components & VB_HAS_NRM2)
if (uid_data->components & VB_HAS_NRM2)
out.Write("float3 _norm2 = float3(dot(" I_POSNORMALMATRIX
"[3].xyz, rawnorm2), dot(" I_POSNORMALMATRIX
"[4].xyz, rawnorm2), dot(" I_POSNORMALMATRIX "[5].xyz, rawnorm2));\n");
}
if (!(components & VB_HAS_NRM0))
if (!(uid_data->components & VB_HAS_NRM0))
out.Write("float3 _norm0 = float3(0.0, 0.0, 0.0);\n");
out.Write("o.pos = float4(dot(" I_PROJECTION "[0], pos), dot(" I_PROJECTION
@ -182,20 +237,19 @@ static T GenerateVertexShader(API_TYPE api_type)
"float3 ldir, h, cosAttn, distAttn;\n"
"float dist, dist2, attn;\n");
uid_data->numColorChans = xfmem.numChan.numColorChans;
if (xfmem.numChan.numColorChans == 0)
if (uid_data->numColorChans == 0)
{
if (components & VB_HAS_COL0)
if (uid_data->components & VB_HAS_COL0)
out.Write("o.colors_0 = color0;\n");
else
out.Write("o.colors_0 = float4(1.0, 1.0, 1.0, 1.0);\n");
}
GenerateLightingShader<T>(out, uid_data->lighting, components, "color", "o.colors_");
GenerateLightingShaderCode(out, uid_data->lighting, uid_data->components, "color", "o.colors_");
if (xfmem.numChan.numColorChans < 2)
if (uid_data->numColorChans < 2)
{
if (components & VB_HAS_COL1)
if (uid_data->components & VB_HAS_COL1)
out.Write("o.colors_1 = color1;\n");
else
out.Write("o.colors_1 = o.colors_0;\n");
@ -203,20 +257,19 @@ static T GenerateVertexShader(API_TYPE api_type)
// transform texcoords
out.Write("float4 coord = float4(0.0, 0.0, 1.0, 1.0);\n");
for (unsigned int i = 0; i < xfmem.numTexGen.numTexGens; ++i)
for (unsigned int i = 0; i < uid_data->numTexGens; ++i)
{
TexMtxInfo& texinfo = xfmem.texMtxInfo[i];
auto& texinfo = uid_data->texMtxInfo[i];
out.Write("{\n");
out.Write("coord = float4(0.0, 0.0, 1.0, 1.0);\n");
uid_data->texMtxInfo[i].sourcerow = xfmem.texMtxInfo[i].sourcerow;
switch (texinfo.sourcerow)
{
case XF_SRCGEOM_INROW:
out.Write("coord.xyz = rawpos.xyz;\n");
break;
case XF_SRCNORMAL_INROW:
if (components & VB_HAS_NRM0)
if (uid_data->components & VB_HAS_NRM0)
{
out.Write("coord.xyz = rawnorm0.xyz;\n");
}
@ -226,40 +279,37 @@ static T GenerateVertexShader(API_TYPE api_type)
texinfo.texgentype == XF_TEXGEN_COLOR_STRGBC1);
break;
case XF_SRCBINORMAL_T_INROW:
if (components & VB_HAS_NRM1)
if (uid_data->components & VB_HAS_NRM1)
{
out.Write("coord.xyz = rawnorm1.xyz;\n");
}
break;
case XF_SRCBINORMAL_B_INROW:
if (components & VB_HAS_NRM2)
if (uid_data->components & VB_HAS_NRM2)
{
out.Write("coord.xyz = rawnorm2.xyz;\n");
}
break;
default:
_assert_(texinfo.sourcerow <= XF_SRCTEX7_INROW);
if (components & (VB_HAS_UV0 << (texinfo.sourcerow - XF_SRCTEX0_INROW)))
if (uid_data->components & (VB_HAS_UV0 << (texinfo.sourcerow - XF_SRCTEX0_INROW)))
out.Write("coord = float4(tex%d.x, tex%d.y, 1.0, 1.0);\n",
texinfo.sourcerow - XF_SRCTEX0_INROW, texinfo.sourcerow - XF_SRCTEX0_INROW);
break;
}
// Input form of AB11 sets z element to 1.0
uid_data->texMtxInfo[i].inputform = xfmem.texMtxInfo[i].inputform;
if (texinfo.inputform == XF_TEXINPUT_AB11)
out.Write("coord.z = 1.0;\n");
// first transformation
uid_data->texMtxInfo[i].texgentype = xfmem.texMtxInfo[i].texgentype;
switch (texinfo.texgentype)
{
case XF_TEXGEN_EMBOSS_MAP: // calculate tex coords into bump map
if (components & (VB_HAS_NRM1 | VB_HAS_NRM2))
if (uid_data->components & (VB_HAS_NRM1 | VB_HAS_NRM2))
{
// transform the light dir into tangent space
uid_data->texMtxInfo[i].embosslightshift = xfmem.texMtxInfo[i].embosslightshift;
uid_data->texMtxInfo[i].embosssourceshift = xfmem.texMtxInfo[i].embosssourceshift;
out.Write("ldir = normalize(" LIGHT_POS ".xyz - pos.xyz);\n",
LIGHT_POS_PARAMS(texinfo.embosslightshift));
out.Write(
@ -271,7 +321,6 @@ static T GenerateVertexShader(API_TYPE api_type)
// The following assert was triggered in House of the Dead Overkill and Star Wars Rogue
// Squadron 2
//_assert_(0); // should have normals
uid_data->texMtxInfo[i].embosssourceshift = xfmem.texMtxInfo[i].embosssourceshift;
out.Write("o.tex%d.xyz = o.tex%d.xyz;\n", i, texinfo.embosssourceshift);
}
@ -284,11 +333,10 @@ static T GenerateVertexShader(API_TYPE api_type)
break;
case XF_TEXGEN_REGULAR:
default:
uid_data->texMtxInfo_n_projection |= xfmem.texMtxInfo[i].projection << i;
if (components & (VB_HAS_TEXMTXIDX0 << i))
if (uid_data->components & (VB_HAS_TEXMTXIDX0 << i))
{
out.Write("int tmp = int(tex%d.z);\n", i);
if (texinfo.projection == XF_TEXPROJ_STQ)
if (((uid_data->texMtxInfo_n_projection >> i) & 1) == XF_TEXPROJ_STQ)
out.Write("o.tex%d.xyz = float3(dot(coord, " I_TRANSFORMMATRICES
"[tmp]), dot(coord, " I_TRANSFORMMATRICES
"[tmp+1]), dot(coord, " I_TRANSFORMMATRICES "[tmp+2]));\n",
@ -300,7 +348,7 @@ static T GenerateVertexShader(API_TYPE api_type)
}
else
{
if (texinfo.projection == XF_TEXPROJ_STQ)
if (((uid_data->texMtxInfo_n_projection >> i) & 1) == XF_TEXPROJ_STQ)
out.Write("o.tex%d.xyz = float3(dot(coord, " I_TEXMATRICES
"[%d]), dot(coord, " I_TEXMATRICES "[%d]), dot(coord, " I_TEXMATRICES
"[%d]));\n",
@ -313,20 +361,16 @@ static T GenerateVertexShader(API_TYPE api_type)
break;
}
uid_data->dualTexTrans_enabled = xfmem.dualTexTrans.enabled;
// CHECKME: does this only work for regular tex gen types?
if (xfmem.dualTexTrans.enabled && texinfo.texgentype == XF_TEXGEN_REGULAR)
if (uid_data->dualTexTrans_enabled && texinfo.texgentype == XF_TEXGEN_REGULAR)
{
const PostMtxInfo& postInfo = xfmem.postMtxInfo[i];
auto& postInfo = uid_data->postMtxInfo[i];
uid_data->postMtxInfo[i].index = xfmem.postMtxInfo[i].index;
int postidx = postInfo.index;
out.Write("float4 P0 = " I_POSTTRANSFORMMATRICES "[%d];\n"
"float4 P1 = " I_POSTTRANSFORMMATRICES "[%d];\n"
"float4 P2 = " I_POSTTRANSFORMMATRICES "[%d];\n",
postidx & 0x3f, (postidx + 1) & 0x3f, (postidx + 2) & 0x3f);
postInfo.index & 0x3f, (postInfo.index + 1) & 0x3f, (postInfo.index + 2) & 0x3f);
uid_data->postMtxInfo[i].normalize = xfmem.postMtxInfo[i].normalize;
if (postInfo.normalize)
out.Write("o.tex%d.xyz = normalize(o.tex%d.xyz);\n", i, i);
@ -342,15 +386,15 @@ static T GenerateVertexShader(API_TYPE api_type)
// clipPos/w needs to be done in pixel shader, not here
out.Write("o.clipPos = o.pos;\n");
if (g_ActiveConfig.bEnablePixelLighting)
if (uid_data->pixel_lighting)
{
out.Write("o.Normal = _norm0;\n");
out.Write("o.WorldPos = pos.xyz;\n");
if (components & VB_HAS_COL0)
if (uid_data->components & VB_HAS_COL0)
out.Write("o.colors_0 = color0;\n");
if (components & VB_HAS_COL1)
if (uid_data->components & VB_HAS_COL1)
out.Write("o.colors_1 = color1;\n");
}
@ -390,16 +434,16 @@ static T GenerateVertexShader(API_TYPE api_type)
{
if (g_ActiveConfig.backend_info.bSupportsGeometryShaders)
{
AssignVSOutputMembers(out, "vs", "o");
AssignVSOutputMembers(out, "vs", "o", uid_data->numTexGens, uid_data->pixel_lighting);
}
else
{
// TODO: Pass interface blocks between shader stages even if geometry shaders
// are not supported, however that will require at least OpenGL 3.2 support.
for (unsigned int i = 0; i < xfmem.numTexGen.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("clipPos = o.clipPos;\n");
if (g_ActiveConfig.bEnablePixelLighting)
if (uid_data->pixel_lighting)
{
out.Write("Normal = o.Normal;\n");
out.Write("WorldPos = o.WorldPos;\n");
@ -418,13 +462,3 @@ static T GenerateVertexShader(API_TYPE api_type)
return out;
}
VertexShaderUid GetVertexShaderUid(API_TYPE api_type)
{
return GenerateVertexShader<VertexShaderUid>(api_type);
}
ShaderCode GenerateVertexShaderCode(API_TYPE api_type)
{
return GenerateVertexShader<ShaderCode>(api_type);
}

View file

@ -37,10 +37,13 @@ struct vertex_shader_uid_data
u32 numColorChans : 2;
u32 dualTexTrans_enabled : 1;
u32 pixel_lighting : 1;
u32 pad : 1;
u32 msaa : 1;
u32 texMtxInfo_n_projection : 16; // Stored separately to guarantee that the texMtxInfo struct is
// 8 bits wide
u32 ssaa : 1;
u32 pad : 15;
struct
{
u32 inputform : 2;
@ -63,5 +66,5 @@ struct vertex_shader_uid_data
typedef ShaderUid<vertex_shader_uid_data> VertexShaderUid;
VertexShaderUid GetVertexShaderUid(API_TYPE api_type);
ShaderCode GenerateVertexShaderCode(API_TYPE api_type);
VertexShaderUid GetVertexShaderUid();
ShaderCode GenerateVertexShaderCode(API_TYPE api_type, const vertex_shader_uid_data* uid_data);

View file

@ -79,7 +79,6 @@ void VideoConfig::Load(const std::string& ini_file)
settings->Get("TexFmtOverlayCenter", &bTexFmtOverlayCenter, 0);
settings->Get("WireFrame", &bWireFrame, 0);
settings->Get("DisableFog", &bDisableFog, 0);
settings->Get("EnableShaderDebugging", &bEnableShaderDebugging, false);
settings->Get("BorderlessFullscreen", &bBorderlessFullscreen, false);
settings->Get("SWZComploc", &bZComploc, true);
@ -120,18 +119,6 @@ void VideoConfig::Load(const std::string& ini_file)
interface->Get("UsePanicHandlers", &bTmp, true);
SetEnableAlert(bTmp);
// Shader Debugging causes a huge slowdown and it's easy to forget about it
// since it's not exposed in the settings dialog. It's only used by
// developers, so displaying an obnoxious message avoids some confusion and
// is not too annoying/confusing for users.
//
// XXX(delroth): This is kind of a bad place to put this, but the current
// VideoCommon is a mess and we don't have a central initialization
// function to do these kind of checks. Instead, the init code is
// triplicated for each video backend.
if (bEnableShaderDebugging)
OSD::AddMessage("Warning: Shader Debugging is enabled, performance will suffer heavily", 15000);
VerifyValidity();
}
@ -299,7 +286,6 @@ void VideoConfig::Save(const std::string& ini_file)
settings->Set("TexFmtOverlayCenter", bTexFmtOverlayCenter);
settings->Set("Wireframe", bWireFrame);
settings->Set("DisableFog", bDisableFog);
settings->Set("EnableShaderDebugging", bEnableShaderDebugging);
settings->Set("BorderlessFullscreen", bBorderlessFullscreen);
settings->Set("SWZComploc", bZComploc);

View file

@ -132,9 +132,6 @@ struct VideoConfig final
// D3D only config, mostly to be merged into the above
int iAdapter;
// Debugging
bool bEnableShaderDebugging;
// VideoSW Debugging
int drawStart;
int drawEnd;