mirror of https://github.com/PCSX2/pcsx2.git
GL: Add support for compute shaders
This commit is contained in:
parent
46db4077b8
commit
d132ddefef
|
@ -137,6 +137,17 @@ namespace GL
|
|||
return true;
|
||||
}
|
||||
|
||||
bool Program::CompileCompute(const std::string_view glsl)
|
||||
{
|
||||
GLuint id = CompileShader(GL_COMPUTE_SHADER, glsl);
|
||||
if (id == 0)
|
||||
return false;
|
||||
|
||||
m_program_id = glCreateProgram();
|
||||
glAttachShader(m_program_id, id);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Program::CreateFromBinary(const void* data, u32 data_length, u32 data_format)
|
||||
{
|
||||
GLuint prog = glCreateProgram();
|
||||
|
|
|
@ -37,6 +37,8 @@ namespace GL
|
|||
bool Compile(const std::string_view vertex_shader, const std::string_view geometry_shader,
|
||||
const std::string_view fragment_shader);
|
||||
|
||||
bool CompileCompute(const std::string_view glsl);
|
||||
|
||||
bool CreateFromBinary(const void* data, u32 data_length, u32 data_format);
|
||||
|
||||
bool GetBinary(std::vector<u8>* out_data, u32* out_data_format);
|
||||
|
|
|
@ -352,6 +352,42 @@ namespace GL
|
|||
return true;
|
||||
}
|
||||
|
||||
bool ShaderCache::WriteToBlobFile(const CacheIndexKey& key, const std::vector<u8>& prog_data, u32 prog_format)
|
||||
{
|
||||
if (!m_blob_file || std::fseek(m_blob_file, 0, SEEK_END) != 0)
|
||||
return false;
|
||||
|
||||
CacheIndexData data;
|
||||
data.file_offset = static_cast<u32>(std::ftell(m_blob_file));
|
||||
data.blob_size = static_cast<u32>(prog_data.size());
|
||||
data.blob_format = prog_format;
|
||||
|
||||
CacheIndexEntry entry = {};
|
||||
entry.vertex_source_hash_low = key.vertex_source_hash_low;
|
||||
entry.vertex_source_hash_high = key.vertex_source_hash_high;
|
||||
entry.vertex_source_length = key.vertex_source_length;
|
||||
entry.geometry_source_hash_low = key.geometry_source_hash_low;
|
||||
entry.geometry_source_hash_high = key.geometry_source_hash_high;
|
||||
entry.geometry_source_length = key.geometry_source_length;
|
||||
entry.fragment_source_hash_low = key.fragment_source_hash_low;
|
||||
entry.fragment_source_hash_high = key.fragment_source_hash_high;
|
||||
entry.fragment_source_length = key.fragment_source_length;
|
||||
entry.file_offset = data.file_offset;
|
||||
entry.blob_size = data.blob_size;
|
||||
entry.blob_format = data.blob_format;
|
||||
|
||||
if (std::fwrite(prog_data.data(), 1, entry.blob_size, m_blob_file) != entry.blob_size ||
|
||||
std::fflush(m_blob_file) != 0 || std::fwrite(&entry, sizeof(entry), 1, m_index_file) != 1 ||
|
||||
std::fflush(m_index_file) != 0)
|
||||
{
|
||||
Console.Error("Failed to write shader blob to file");
|
||||
return false;
|
||||
}
|
||||
|
||||
m_index.emplace(key, data);
|
||||
return true;
|
||||
}
|
||||
|
||||
std::optional<Program> ShaderCache::CompileProgram(const std::string_view& vertex_shader,
|
||||
const std::string_view& geometry_shader,
|
||||
const std::string_view& fragment_shader,
|
||||
|
@ -373,6 +409,25 @@ namespace GL
|
|||
return std::optional<Program>(std::move(prog));
|
||||
}
|
||||
|
||||
std::optional<Program> ShaderCache::CompileComputeProgram(const std::string_view& glsl,
|
||||
const PreLinkCallback& callback, bool set_retrievable)
|
||||
{
|
||||
Program prog;
|
||||
if (!prog.CompileCompute(glsl))
|
||||
return std::nullopt;
|
||||
|
||||
if (callback)
|
||||
callback(prog);
|
||||
|
||||
if (set_retrievable)
|
||||
prog.SetBinaryRetrievableHint();
|
||||
|
||||
if (!prog.Link())
|
||||
return std::nullopt;
|
||||
|
||||
return std::optional<Program>(std::move(prog));
|
||||
}
|
||||
|
||||
std::optional<Program> ShaderCache::CompileAndAddProgram(const CacheIndexKey& key,
|
||||
const std::string_view& vertex_shader,
|
||||
const std::string_view& geometry_shader,
|
||||
|
@ -402,42 +457,110 @@ namespace GL
|
|||
timer.Reset();
|
||||
#endif
|
||||
|
||||
if (!m_blob_file || std::fseek(m_blob_file, 0, SEEK_END) != 0)
|
||||
return prog;
|
||||
|
||||
CacheIndexData data;
|
||||
data.file_offset = static_cast<u32>(std::ftell(m_blob_file));
|
||||
data.blob_size = static_cast<u32>(prog_data.size());
|
||||
data.blob_format = prog_format;
|
||||
|
||||
CacheIndexEntry entry = {};
|
||||
entry.vertex_source_hash_low = key.vertex_source_hash_low;
|
||||
entry.vertex_source_hash_high = key.vertex_source_hash_high;
|
||||
entry.vertex_source_length = key.vertex_source_length;
|
||||
entry.geometry_source_hash_low = key.geometry_source_hash_low;
|
||||
entry.geometry_source_hash_high = key.geometry_source_hash_high;
|
||||
entry.geometry_source_length = key.geometry_source_length;
|
||||
entry.fragment_source_hash_low = key.fragment_source_hash_low;
|
||||
entry.fragment_source_hash_high = key.fragment_source_hash_high;
|
||||
entry.fragment_source_length = key.fragment_source_length;
|
||||
entry.file_offset = data.file_offset;
|
||||
entry.blob_size = data.blob_size;
|
||||
entry.blob_format = data.blob_format;
|
||||
|
||||
if (std::fwrite(prog_data.data(), 1, entry.blob_size, m_blob_file) != entry.blob_size ||
|
||||
std::fflush(m_blob_file) != 0 || std::fwrite(&entry, sizeof(entry), 1, m_index_file) != 1 ||
|
||||
std::fflush(m_index_file) != 0)
|
||||
{
|
||||
Console.Error("Failed to write shader blob to file");
|
||||
return prog;
|
||||
}
|
||||
WriteToBlobFile(key, prog_data, prog_format);
|
||||
|
||||
#ifdef PCSX2_DEVBUILD
|
||||
const float write_time = timer.GetTimeMilliseconds();
|
||||
Console.WriteLn("Compiled and cached shader: Compile: %.2fms, Binary: %.2fms, Write: %.2fms", compile_time, binary_time, write_time);
|
||||
#endif
|
||||
|
||||
m_index.emplace(key, data);
|
||||
return prog;
|
||||
}
|
||||
|
||||
std::optional<Program> ShaderCache::GetComputeProgram(const std::string_view glsl, const PreLinkCallback& callback)
|
||||
{
|
||||
if (!m_program_binary_supported || !m_blob_file)
|
||||
{
|
||||
#ifdef PCSX2_DEVBUILD
|
||||
Common::Timer timer;
|
||||
#endif
|
||||
|
||||
std::optional<Program> res = CompileComputeProgram(glsl, callback, false);
|
||||
|
||||
#ifdef PCSX2_DEVBUILD
|
||||
Console.WriteLn("Time to compile shader without caching: %.2fms", timer.GetTimeMilliseconds());
|
||||
#endif
|
||||
return res;
|
||||
}
|
||||
|
||||
const auto key = GetCacheKey(glsl, std::string_view(), std::string_view());
|
||||
auto iter = m_index.find(key);
|
||||
if (iter == m_index.end())
|
||||
return CompileAndAddComputeProgram(key, glsl, callback);
|
||||
|
||||
std::vector<u8> data(iter->second.blob_size);
|
||||
if (std::fseek(m_blob_file, iter->second.file_offset, SEEK_SET) != 0 ||
|
||||
std::fread(data.data(), 1, iter->second.blob_size, m_blob_file) != iter->second.blob_size)
|
||||
{
|
||||
Console.Error("Read blob from file failed");
|
||||
return {};
|
||||
}
|
||||
|
||||
#ifdef PCSX2_DEVBUILD
|
||||
Common::Timer timer;
|
||||
#endif
|
||||
|
||||
Program prog;
|
||||
if (prog.CreateFromBinary(data.data(), static_cast<u32>(data.size()), iter->second.blob_format))
|
||||
{
|
||||
#ifdef PCSX2_DEVBUILD
|
||||
Console.WriteLn("Time to create program from binary: %.2fms", timer.GetTimeMilliseconds());
|
||||
#endif
|
||||
|
||||
return std::optional<Program>(std::move(prog));
|
||||
}
|
||||
|
||||
Console.Warning(
|
||||
"Failed to create program from binary, this may be due to a driver or GPU Change. Recreating cache.");
|
||||
if (!Recreate())
|
||||
return CompileComputeProgram(glsl, callback, false);
|
||||
else
|
||||
return CompileAndAddComputeProgram(key, glsl, callback);
|
||||
}
|
||||
|
||||
bool ShaderCache::GetComputeProgram(Program* out_program, const std::string_view glsl, const PreLinkCallback& callback)
|
||||
{
|
||||
auto prog = GetComputeProgram(glsl, callback);
|
||||
if (!prog)
|
||||
return false;
|
||||
|
||||
*out_program = std::move(*prog);
|
||||
return true;
|
||||
}
|
||||
|
||||
std::optional<Program> ShaderCache::CompileAndAddComputeProgram(
|
||||
const CacheIndexKey& key, const std::string_view& glsl, const PreLinkCallback& callback)
|
||||
{
|
||||
#ifdef PCSX2_DEVBUILD
|
||||
Common::Timer timer;
|
||||
#endif
|
||||
|
||||
std::optional<Program> prog = CompileComputeProgram(glsl, callback, true);
|
||||
if (!prog)
|
||||
return std::nullopt;
|
||||
|
||||
#ifdef PCSX2_DEVBUILD
|
||||
const float compile_time = timer.GetTimeMilliseconds();
|
||||
timer.Reset();
|
||||
#endif
|
||||
|
||||
std::vector<u8> prog_data;
|
||||
u32 prog_format = 0;
|
||||
if (!prog->GetBinary(&prog_data, &prog_format))
|
||||
return std::nullopt;
|
||||
|
||||
#ifdef PCSX2_DEVBUILD
|
||||
const float binary_time = timer.GetTimeMilliseconds();
|
||||
timer.Reset();
|
||||
#endif
|
||||
|
||||
WriteToBlobFile(key, prog_data, prog_format);
|
||||
|
||||
#ifdef PCSX2_DEVBUILD
|
||||
const float write_time = timer.GetTimeMilliseconds();
|
||||
Console.WriteLn("Compiled and cached compute shader: Compile: %.2fms, Binary: %.2fms, Write: %.2fms", compile_time, binary_time, write_time);
|
||||
#endif
|
||||
|
||||
return prog;
|
||||
}
|
||||
} // namespace GL
|
||||
|
|
|
@ -42,6 +42,9 @@ namespace GL
|
|||
bool GetProgram(Program* out_program, const std::string_view vertex_shader, const std::string_view geometry_shader,
|
||||
const std::string_view fragment_shader, const PreLinkCallback& callback = {});
|
||||
|
||||
std::optional<Program> GetComputeProgram(const std::string_view glsl, const PreLinkCallback& callback = {});
|
||||
bool GetComputeProgram(Program* out_program, const std::string_view glsl, const PreLinkCallback& callback = {});
|
||||
|
||||
private:
|
||||
static constexpr u32 FILE_VERSION = 1;
|
||||
|
||||
|
@ -94,6 +97,8 @@ namespace GL
|
|||
void Close();
|
||||
bool Recreate();
|
||||
|
||||
bool WriteToBlobFile(const CacheIndexKey& key, const std::vector<u8>& prog_data, u32 prog_format);
|
||||
|
||||
std::optional<Program> CompileProgram(const std::string_view& vertex_shader, const std::string_view& geometry_shader,
|
||||
const std::string_view& fragment_shader, const PreLinkCallback& callback,
|
||||
bool set_retrievable);
|
||||
|
@ -101,6 +106,9 @@ namespace GL
|
|||
const std::string_view& geometry_shader,
|
||||
const std::string_view& fragment_shader, const PreLinkCallback& callback);
|
||||
|
||||
std::optional<Program> CompileComputeProgram(const std::string_view& glsl, const PreLinkCallback& callback, bool set_retrievable);
|
||||
std::optional<Program> CompileAndAddComputeProgram(const CacheIndexKey& key, const std::string_view& glsl, const PreLinkCallback& callback);
|
||||
|
||||
std::string m_base_path;
|
||||
std::FILE* m_index_file = nullptr;
|
||||
std::FILE* m_blob_file = nullptr;
|
||||
|
|
Loading…
Reference in New Issue