Shader: better cache handling

This commit is contained in:
korenkonder
2024-06-23 13:49:38 +03:00
parent c070722178
commit 67d1b6e5f4
2 changed files with 100 additions and 69 deletions
+94 -63
View File
@@ -32,7 +32,7 @@ static GLuint shader_compile_shader(GLenum type, const char* data, const char* f
static GLuint shader_compile(const char* vert, const char* frag, const char* vp, const char* fp);
static GLuint shader_compile_binary(const char* vert, const char* frag, const char* vp, const char* fp,
program_binary* bin, GLsizei* buffer_size, void** binary);
static bool shader_load_binary_shader(program_binary* bin, GLuint* program);
static bool shader_load_binary_shader(program_binary* bin, GLuint* program, const char* vp, const char* fp);
static void shader_update_data(shader_set_data* set);
int32_t shader::bind(shader_set_data* set, uint32_t sub_index) {
@@ -400,7 +400,7 @@ int32_t shader_set_data::get_index_by_name(const char* name) {
void shader_set_data::load(farc* f, bool ignore_cache,
const char* name, const shader_table* shaders_table, const size_t size,
const shader_bind_func* bind_func_table, const size_t bind_func_table_size,
PFNSHADERGLSLGETINDEXFUNCPROC get_index_by_name) {
PFNSHADERGETINDEXFUNCPROC get_index_by_name) {
if (!this || !f || !shaders_table || !size)
return;
@@ -409,7 +409,7 @@ void shader_set_data::load(farc* f, bool ignore_cache,
return;
wcscat_s(temp_buf, sizeof(temp_buf) / sizeof(wchar_t), L"\\PDAFT");
CreateDirectoryW(temp_buf, 0);
path_create_directory(temp_buf);
wchar_t buf[MAX_PATH];
swprintf_s(buf, sizeof(buf) / sizeof(wchar_t), L"\\%hs_shader_cache", name);
@@ -425,6 +425,7 @@ void shader_set_data::load(farc* f, bool ignore_cache,
char frag_buf[MAX_PATH];
char vert_file_buf[MAX_PATH];
char frag_file_buf[MAX_PATH];
char shader_cache_file_name[MAX_PATH];
GLsizei buffer_size = 0x100000;
void* binary = force_malloc(buffer_size);
@@ -491,32 +492,44 @@ void shader_set_data::load(farc* f, bool ignore_cache,
continue;
}
uint32_t uniform_flags = 0;
uint32_t uniform_vert_flags = 0;
uint32_t uniform_frag_flags = 0;
for (int32_t k = 0; k < shader->num_uniform; k++)
if (shader->use_uniform[k].second)
uniform_flags |= 1 << k;
if (shader->use_uniform[k].second) {
if (sub_table->vp_unival_max[k] > 0)
uniform_vert_flags |= 1 << k;
if (sub_table->fp_unival_max[k] > 0)
uniform_frag_flags |= 1 << k;
}
char uniform_flags_buf[9];
char uniform_vert_flags_buf[9];
char uniform_frag_flags_buf[9];
for (int32_t k = 0, l = 7; k < 32; k += 4, l--) {
int32_t digit = (uniform_flags >> k) & 0xF;
if (digit >= 0x00 && digit <= 0x09)
uniform_flags_buf[l] = (char)('0' + digit);
int32_t vert_flags_digit = (uniform_vert_flags >> k) & 0xF;
if (vert_flags_digit >= 0x00 && vert_flags_digit <= 0x09)
uniform_vert_flags_buf[l] = (char)('0' + vert_flags_digit);
else
uniform_flags_buf[l] = (char)('A' + (digit - 0x0A));
uniform_vert_flags_buf[l] = (char)('A' + (vert_flags_digit - 0x0A));
int32_t frag_flags_digit = (uniform_frag_flags >> k) & 0xF;
if (frag_flags_digit >= 0x00 && frag_flags_digit <= 0x09)
uniform_frag_flags_buf[l] = (char)('0' + frag_flags_digit);
else
uniform_frag_flags_buf[l] = (char)('A' + (frag_flags_digit - 0x0A));
}
uniform_flags_buf[8] = 0;
uniform_vert_flags_buf[8] = 0;
uniform_frag_flags_buf[8] = 0;
strcpy_s(vert_buf, sizeof(vert_buf), vert_file_buf);
strcpy_s(frag_buf, sizeof(frag_buf), frag_file_buf);
strcat_s(vert_buf, sizeof(vert_buf), ".");
strcat_s(frag_buf, sizeof(frag_buf), ".");
strcat_s(vert_buf, sizeof(vert_buf), uniform_flags_buf);
strcat_s(frag_buf, sizeof(frag_buf), uniform_flags_buf);
strcat_s(vert_buf, sizeof(vert_buf), uniform_vert_flags_buf);
strcat_s(frag_buf, sizeof(frag_buf), uniform_frag_flags_buf);
uint64_t vert_file_name_hash = hash_utf8_fnv1a64m(vert_buf);
uint64_t frag_file_name_hash = hash_utf8_fnv1a64m(frag_buf);
uint64_t vert_file_name_hash = hash_utf8_xxh3_64bits(vert_buf);
uint64_t frag_file_name_hash = hash_utf8_xxh3_64bits(frag_buf);
char shader_cache_file_name[MAX_PATH];
strcpy_s(shader_cache_file_name, sizeof(shader_cache_file_name), sub_table->vp);
if (str_utils_compare(sub_table->vp, sub_table->fp)) {
strcat_s(shader_cache_file_name, sizeof(shader_cache_file_name), ".");
@@ -526,8 +539,8 @@ void shader_set_data::load(farc* f, bool ignore_cache,
vert_data = shader::parse_include(vert_data, f);
frag_data = shader::parse_include(frag_data, f);
uint64_t vert_data_hash = hash_utf8_fnv1a64m(vert_data);
uint64_t frag_data_hash = hash_utf8_fnv1a64m(frag_data);
uint64_t vert_data_hash = hash_utf8_xxh3_64bits(vert_data);
uint64_t frag_data_hash = hash_utf8_xxh3_64bits(frag_data);
farc_file* shader_cache_file = shader_cache_farc.read_file(shader_cache_file_name);
program_binary* bin = 0;
@@ -540,13 +553,8 @@ void shader_set_data::load(farc* f, bool ignore_cache,
else if (vert_data_hash != ((uint64_t*)shader_cache_file->data)[2]
|| frag_data_hash != ((uint64_t*)shader_cache_file->data)[3])
printf_debug("Shader hash not equal: %s %s\n", vert_file_buf, frag_file_buf);
else {
else
bin = (program_binary*)&((uint64_t*)shader_cache_file->data)[4];
if (bin->hash != hash_fnv1a64m((void*)((size_t)bin + bin->binary), bin->length)) {
printf_debug("Compiled binary hash could not be validated: %s %s\n", vert_file_buf, frag_file_buf);
bin = 0;
}
}
}
if (shader->num_uniform > 0
@@ -602,7 +610,7 @@ void shader_set_data::load(farc* f, bool ignore_cache,
}
if (!bin || !bin->binary_format || !bin->length
|| !shader_load_binary_shader(bin, &shaders[k].program)) {
|| !shader_load_binary_shader(bin, &shaders[k].program, vert_buf, frag_buf)) {
bool vert_succ = shader::parse_define(vert_data, num_uniform,
vec_vert_data, &temp_vert, &temp_vert_size);
bool frag_succ = shader::parse_define(frag_data, num_uniform,
@@ -648,7 +656,7 @@ void shader_set_data::load(farc* f, bool ignore_cache,
strcat_s(frag_buf, sizeof(vert_buf), "..frag");
if (!bin || !bin->binary_format || !bin->length
|| !shader_load_binary_shader(bin, &shaders[0].program)) {
|| !shader_load_binary_shader(bin, &shaders[0].program, vert_buf, frag_buf)) {
bool vert_succ = shader::parse_define(vert_data, &temp_vert, &temp_vert_size);
bool frag_succ = shader::parse_define(frag_data, &temp_frag, &temp_frag_size);
@@ -707,7 +715,7 @@ void shader_set_data::load(farc* f, bool ignore_cache,
bin->length = k.length;
bin->binary_format = k.binary_format;
bin->binary = bin_data - bin_data_base;
bin->hash = hash_fnv1a64m((void*)k.binary, k.length);
bin->hash = hash_xxh3_64bits((void*)k.binary, k.length);
memcpy((void*)bin_data, (void*)k.binary, k.length);
bin_data_base += sizeof(program_binary);
bin_data += align_val(k.length, 0x04);
@@ -735,7 +743,7 @@ void shader_set_data::load(farc* f, bool ignore_cache,
free_def(temp_vert);
free_def(temp_frag);
if (!ignore_cache && shader_cache_changed)
if (shader_cache_changed)
shader_cache_farc.write(temp_buf, FARC_FArC, FARC_NONE, true, false);
this->get_index_by_name_func = get_index_by_name;
@@ -763,14 +771,14 @@ void shader_set_data::unload() {
int32_t num_sub = shader->num_sub;
shader_sub* sub = shader->sub;
for (size_t j = 0; j < num_sub; j++, sub++) {
for (int32_t j = 0; j < num_sub; j++, sub++) {
int32_t unival_shad_count = 1;
if (shader->num_uniform > 0) {
int32_t num_uniform = shader->num_uniform;
int32_t unival_shad_curr = 1;
const int32_t* vp_unival_max = sub->vp_unival_max;
const int32_t* fp_unival_max = sub->fp_unival_max;
for (size_t k = 0; k < num_uniform; k++) {
for (int32_t k = 0; k < num_uniform; k++) {
const int32_t unival_max = shader->use_uniform[k].second
? max_def(vp_unival_max[k], fp_unival_max[k]) : 0;
unival_shad_count += unival_shad_curr * unival_max;
@@ -780,7 +788,7 @@ void shader_set_data::unload() {
if (sub->shaders) {
shader_sub_shader* shaders = sub->shaders;
for (size_t k = 0; k < unival_shad_count; k++)
for (int32_t k = 0; k < unival_shad_count; k++)
glDeleteProgram(shaders[k].program);
free(shaders);
sub->shaders = 0;
@@ -806,8 +814,10 @@ static GLuint shader_compile_shader(GLenum type, const char* data, const char* f
GLint success = 0;
glGetShaderiv(shader, GL_COMPILE_STATUS, &success);
if (!success) {
GLchar* info_log = force_malloc<GLchar>(0x10000);
glGetShaderInfoLog(shader, 0x10000, 0, info_log);
GLint length = 0;
glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &length);
GLchar* info_log = force_malloc<GLchar>(length);
glGetShaderInfoLog(shader, length, 0, info_log);
const char* type_str = "Unknown";
switch (type) {
case GL_FRAGMENT_SHADER:
@@ -818,21 +828,18 @@ static GLuint shader_compile_shader(GLenum type, const char* data, const char* f
break;
}
printf_debug("%s shader compile error:\nfile: %s\n%s\n", type_str, file, info_log);
free_def(info_log);
glDeleteShader(shader);
#if defined(CRE_DEV)
wchar_t temp_buf[MAX_PATH];
if (SUCCEEDED(SHGetFolderPathW(0, CSIDL_LOCAL_APPDATA, 0, 0, temp_buf))) {
wcscat_s(temp_buf, sizeof(temp_buf) / sizeof(wchar_t), L"\\ReDIVA");
wcscat_s(temp_buf, sizeof(temp_buf) / sizeof(wchar_t), L"\\PDAFT");
temp_buf[sizeof(temp_buf) / sizeof(wchar_t) - 1] = 0;
CreateDirectoryW(temp_buf, 0);
path_create_directory(temp_buf);
wchar_t buf[MAX_PATH];
swprintf_s(buf, sizeof(buf) / sizeof(wchar_t),
L"%ls\\shader_error", temp_buf);
buf[sizeof(buf) / sizeof(wchar_t) - 1] = 0;
CreateDirectoryW(buf, 0);
path_create_directory(buf);
swprintf_s(buf, sizeof(buf) / sizeof(wchar_t),
L"%ls\\shader_error\\%hs", temp_buf, file);
@@ -840,9 +847,14 @@ static GLuint shader_compile_shader(GLenum type, const char* data, const char* f
file_stream s;
s.open(buf, L"wb");
s.write(data, utf8_length(data));
s.write_utf8_string(data);
s.write_utf8_string("\n/*\n");
s.write_utf8_string(info_log);
s.write_utf8_string("*/\n");
}
#endif
free_def(info_log);
glDeleteShader(shader);
return 0;
}
return shader;
@@ -867,24 +879,23 @@ static GLuint shader_compile(const char* vert, const char* frag, const char* vp,
GLint success = 0;
glGetProgramiv(program, GL_LINK_STATUS, &success);
if (!success) {
GLchar* info_log = force_malloc<GLchar>(0x10000);
glGetProgramInfoLog(program, 0x10000, 0, info_log);
GLint length = 0;
glGetProgramiv(program, GL_INFO_LOG_LENGTH, &length);
GLchar* info_log = force_malloc<GLchar>(length);
glGetProgramInfoLog(program, length, 0, info_log);
printf_debug("Program Shader Permut linking error:\nvp: %s; fp: %s\n%s\n", vp, fp, info_log);
free_def(info_log);
glDeleteProgram(program);
#if defined(CRE_DEV)
wchar_t temp_buf[MAX_PATH];
if (SUCCEEDED(SHGetFolderPathW(0, CSIDL_LOCAL_APPDATA, 0, 0, temp_buf))) {
wcscat_s(temp_buf, sizeof(temp_buf) / sizeof(wchar_t), L"\\ReDIVA");
temp_buf[sizeof(temp_buf) / sizeof(wchar_t) - 1] = 0;
CreateDirectoryW(temp_buf, 0);
path_create_directory(temp_buf);
wchar_t buf[MAX_PATH];
swprintf_s(buf, sizeof(buf) / sizeof(wchar_t),
L"%ls\\shader_error", temp_buf);
buf[sizeof(buf) / sizeof(wchar_t) - 1] = 0;
CreateDirectoryW(buf, 0);
path_create_directory(buf);
swprintf_s(buf, sizeof(buf) / sizeof(wchar_t),
L"%ls\\shader_error\\%hs", temp_buf, vp);
@@ -892,7 +903,10 @@ static GLuint shader_compile(const char* vert, const char* frag, const char* vp,
file_stream s;
s.open(buf, L"wb");
s.write(vert, utf8_length(vert));
s.write_utf8_string(vert);
s.write_utf8_string("\n/*\n");
s.write_utf8_string(info_log);
s.write_utf8_string("*/\n");
s.close();
swprintf_s(buf, sizeof(buf) / sizeof(wchar_t),
@@ -900,10 +914,15 @@ static GLuint shader_compile(const char* vert, const char* frag, const char* vp,
buf[sizeof(buf) / sizeof(wchar_t) - 1] = 0;
s.open(buf, L"wb");
s.write(frag, utf8_length(frag));
s.write_utf8_string(frag);
s.write_utf8_string("\n/*\n");
s.write_utf8_string(info_log);
s.write_utf8_string("*/\n");
s.close();
}
#endif
free_def(info_log);
glDeleteProgram(program);
return 0;
}
else {
@@ -934,24 +953,23 @@ static GLuint shader_compile_binary(const char* vert, const char* frag, const ch
GLint success = 0;
glGetProgramiv(program, GL_LINK_STATUS, &success);
if (!success) {
GLchar* info_log = force_malloc<GLchar>(0x10000);
glGetProgramInfoLog(program, 0x10000, 0, info_log);
GLint length = 0;
glGetProgramiv(program, GL_INFO_LOG_LENGTH, &length);
GLchar* info_log = force_malloc<GLchar>(length);
glGetProgramInfoLog(program, length, 0, info_log);
printf_debug("Program Shader Permut linking error:\nvp: %s; fp: %s\n%s\n", vp, fp, info_log);
free_def(info_log);
glDeleteProgram(program);
#if defined(CRE_DEV)
wchar_t temp_buf[MAX_PATH];
if (SUCCEEDED(SHGetFolderPathW(0, CSIDL_LOCAL_APPDATA, 0, 0, temp_buf))) {
wcscat_s(temp_buf, sizeof(temp_buf) / sizeof(wchar_t), L"\\ReDIVA");
temp_buf[sizeof(temp_buf) / sizeof(wchar_t) - 1] = 0;
CreateDirectoryW(temp_buf, 0);
path_create_directory(temp_buf);
wchar_t buf[MAX_PATH];
swprintf_s(buf, sizeof(buf) / sizeof(wchar_t),
L"%ls\\shader_error", temp_buf);
buf[sizeof(buf) / sizeof(wchar_t) - 1] = 0;
CreateDirectoryW(buf, 0);
path_create_directory(buf);
swprintf_s(buf, sizeof(buf) / sizeof(wchar_t),
L"%ls\\shader_error\\%hs", temp_buf, vp);
@@ -959,7 +977,10 @@ static GLuint shader_compile_binary(const char* vert, const char* frag, const ch
file_stream s;
s.open(buf, L"wb");
s.write(vert, utf8_length(vert));
s.write_utf8_string(vert);
s.write_utf8_string("\n/*\n");
s.write_utf8_string(info_log);
s.write_utf8_string("*/\n");
s.close();
swprintf_s(buf, sizeof(buf) / sizeof(wchar_t),
@@ -967,10 +988,15 @@ static GLuint shader_compile_binary(const char* vert, const char* frag, const ch
buf[sizeof(buf) / sizeof(wchar_t) - 1] = 0;
s.open(buf, L"wb");
s.write(frag, utf8_length(frag));
s.write_utf8_string(frag);
s.write_utf8_string("\n/*\n");
s.write_utf8_string(info_log);
s.write_utf8_string("*/\n");
s.close();
}
#endif
free_def(info_log);
glDeleteProgram(program);
return 0;
}
else {
@@ -997,7 +1023,12 @@ static GLuint shader_compile_binary(const char* vert, const char* frag, const ch
}
}
static bool shader_load_binary_shader(program_binary* bin, GLuint* program) {
static bool shader_load_binary_shader(program_binary* bin, GLuint* program, const char* vp, const char* fp) {
if (bin->hash != hash_xxh3_64bits((void*)((size_t)bin + bin->binary), bin->length)) {
printf_debug("Compiled binary hash could not be validated: %s %s\n", vp, fp);
return false;
}
*program = glCreateProgram();
glProgramBinary(*program, bin->binary_format, (void*)((size_t)bin + bin->binary), bin->length);
GLint success = 0;
+6 -6
View File
@@ -44,13 +44,13 @@ struct shader_table {
struct shader;
struct shader_set_data;
typedef int32_t (*PFNSHADERGLSLGETINDEXFUNCPROC)(const char* name);
typedef int32_t (*PFNSHADERGETINDEXFUNCPROC)(const char* name);
typedef void (*PFNSHADERGLSLBINDFUNCPROC)(shader_set_data* set, shader* shad);
typedef void (*PFNSHADERBINDFUNCPROC)(shader_set_data* set, shader* shad);
struct shader_bind_func {
uint32_t name_index;
PFNSHADERGLSLBINDFUNCPROC bind_func;
PFNSHADERBINDFUNCPROC bind_func;
};
struct shader_sub_shader {
@@ -74,7 +74,7 @@ struct shader {
shader_sub* sub;
int32_t num_uniform;
const std::pair<uniform_name, bool>* use_uniform;
PFNSHADERGLSLBINDFUNCPROC bind_func;
PFNSHADERBINDFUNCPROC bind_func;
int32_t bind(shader_set_data* set, uint32_t sub_index);
@@ -92,7 +92,7 @@ struct shader_set_data {
GLboolean primitive_restart;
GLuint primitive_restart_index;
PFNSHADERGLSLGETINDEXFUNCPROC get_index_by_name_func;
PFNSHADERGETINDEXFUNCPROC get_index_by_name_func;
shader_set_data();
@@ -107,7 +107,7 @@ struct shader_set_data {
void load(farc* f, bool ignore_cache, const char* name,
const shader_table* shaders_table, const size_t size,
const shader_bind_func* bind_func_table, const size_t bind_func_table_size,
PFNSHADERGLSLGETINDEXFUNCPROC get_index_by_name);
PFNSHADERGETINDEXFUNCPROC get_index_by_name);
void set(uint32_t index);
void unload();
};