mirror of https://github.com/xemu-project/xemu.git
nv2a/vk: Cache shader modules
This commit is contained in:
parent
93598e9648
commit
6d5cd495c6
|
@ -368,6 +368,7 @@ ShaderModuleInfo *pgraph_vk_create_shader_module_from_glsl(
|
|||
PGRAPHVkState *r, VkShaderStageFlagBits stage, const char *glsl)
|
||||
{
|
||||
ShaderModuleInfo *info = g_malloc0(sizeof(*info));
|
||||
info->refcnt = 0;
|
||||
info->glsl = strdup(glsl);
|
||||
info->spirv = pgraph_vk_compile_glsl_to_spv(
|
||||
vk_shader_stage_to_glslang_stage(stage), glsl);
|
||||
|
@ -386,8 +387,24 @@ static void finalize_uniform_layout(ShaderUniformLayout *layout)
|
|||
}
|
||||
}
|
||||
|
||||
void pgraph_vk_ref_shader_module(ShaderModuleInfo *info)
|
||||
{
|
||||
info->refcnt++;
|
||||
}
|
||||
|
||||
void pgraph_vk_unref_shader_module(PGRAPHVkState *r, ShaderModuleInfo *info)
|
||||
{
|
||||
assert(info->refcnt >= 1);
|
||||
|
||||
info->refcnt--;
|
||||
if (info->refcnt == 0) {
|
||||
pgraph_vk_destroy_shader_module(r, info);
|
||||
}
|
||||
}
|
||||
|
||||
void pgraph_vk_destroy_shader_module(PGRAPHVkState *r, ShaderModuleInfo *info)
|
||||
{
|
||||
assert(info->refcnt == 0);
|
||||
if (info->glsl) {
|
||||
free(info->glsl);
|
||||
}
|
||||
|
|
|
@ -146,6 +146,7 @@ typedef struct SurfaceBinding {
|
|||
} SurfaceBinding;
|
||||
|
||||
typedef struct ShaderModuleInfo {
|
||||
int refcnt;
|
||||
char *glsl;
|
||||
GByteArray *spirv;
|
||||
VkShaderModule module;
|
||||
|
@ -155,6 +156,30 @@ typedef struct ShaderModuleInfo {
|
|||
ShaderUniformLayout push_constants;
|
||||
} ShaderModuleInfo;
|
||||
|
||||
typedef struct ShaderModuleCacheKey {
|
||||
VkShaderStageFlagBits kind;
|
||||
union {
|
||||
struct {
|
||||
VshState state;
|
||||
GenVshGlslOptions glsl_opts;
|
||||
} vsh;
|
||||
struct {
|
||||
GeomState state;
|
||||
GenGeomGlslOptions glsl_opts;
|
||||
} geom;
|
||||
struct {
|
||||
PshState state;
|
||||
GenPshGlslOptions glsl_opts;
|
||||
} psh;
|
||||
};
|
||||
} ShaderModuleCacheKey;
|
||||
|
||||
typedef struct ShaderModuleCacheEntry {
|
||||
LruNode node;
|
||||
ShaderModuleCacheKey key;
|
||||
ShaderModuleInfo *module_info;
|
||||
} ShaderModuleCacheEntry;
|
||||
|
||||
typedef struct ShaderBinding {
|
||||
LruNode node;
|
||||
bool initialized;
|
||||
|
@ -380,6 +405,9 @@ typedef struct PGRAPHVkState {
|
|||
bool shader_bindings_changed;
|
||||
bool use_push_constants_for_uniform_attrs;
|
||||
|
||||
Lru shader_module_cache;
|
||||
ShaderModuleCacheEntry *shader_module_cache_entries;
|
||||
|
||||
// FIXME: Merge these into a structure
|
||||
uint64_t uniform_buffer_hashes[2];
|
||||
size_t uniform_buffer_offsets[2];
|
||||
|
@ -435,6 +463,8 @@ VkShaderModule pgraph_vk_create_shader_module_from_spv(PGRAPHVkState *r,
|
|||
GByteArray *spv);
|
||||
ShaderModuleInfo *pgraph_vk_create_shader_module_from_glsl(
|
||||
PGRAPHVkState *r, VkShaderStageFlagBits stage, const char *glsl);
|
||||
void pgraph_vk_ref_shader_module(ShaderModuleInfo *info);
|
||||
void pgraph_vk_unref_shader_module(PGRAPHVkState *r, ShaderModuleInfo *info);
|
||||
void pgraph_vk_destroy_shader_module(PGRAPHVkState *r, ShaderModuleInfo *info);
|
||||
|
||||
// buffer.c
|
||||
|
|
|
@ -268,7 +268,7 @@ static void shader_cache_entry_post_evict(Lru *lru, LruNode *node)
|
|||
};
|
||||
for (int i = 0; i < ARRAY_SIZE(modules); i++) {
|
||||
if (modules[i]) {
|
||||
pgraph_vk_destroy_shader_module(r, modules[i]);
|
||||
pgraph_vk_unref_shader_module(r, modules[i]);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -281,6 +281,56 @@ static bool shader_cache_entry_compare(Lru *lru, LruNode *node, void *key)
|
|||
return memcmp(&snode->state, key, sizeof(ShaderState));
|
||||
}
|
||||
|
||||
static void shader_module_cache_entry_init(Lru *lru, LruNode *node, void *key)
|
||||
{
|
||||
PGRAPHVkState *r = container_of(lru, PGRAPHVkState, shader_module_cache);
|
||||
ShaderModuleCacheEntry *module =
|
||||
container_of(node, ShaderModuleCacheEntry, node);
|
||||
memcpy(&module->key, key, sizeof(ShaderModuleCacheKey));
|
||||
|
||||
MString *code;
|
||||
|
||||
switch (module->key.kind) {
|
||||
case VK_SHADER_STAGE_VERTEX_BIT:
|
||||
code = pgraph_glsl_gen_vsh(&module->key.vsh.state,
|
||||
module->key.vsh.glsl_opts);
|
||||
break;
|
||||
case VK_SHADER_STAGE_GEOMETRY_BIT:
|
||||
code = pgraph_glsl_gen_geom(&module->key.geom.state,
|
||||
module->key.geom.glsl_opts);
|
||||
break;
|
||||
case VK_SHADER_STAGE_FRAGMENT_BIT:
|
||||
code = pgraph_glsl_gen_psh(&module->key.psh.state,
|
||||
module->key.psh.glsl_opts);
|
||||
break;
|
||||
default:
|
||||
assert(!"Invalid shader module kind");
|
||||
code = NULL;
|
||||
}
|
||||
|
||||
module->module_info = pgraph_vk_create_shader_module_from_glsl(
|
||||
r, module->key.kind, mstring_get_str(code));
|
||||
pgraph_vk_ref_shader_module(module->module_info);
|
||||
mstring_unref(code);
|
||||
}
|
||||
|
||||
static void shader_module_cache_entry_post_evict(Lru *lru, LruNode *node)
|
||||
{
|
||||
PGRAPHVkState *r = container_of(lru, PGRAPHVkState, shader_module_cache);
|
||||
ShaderModuleCacheEntry *module =
|
||||
container_of(node, ShaderModuleCacheEntry, node);
|
||||
pgraph_vk_unref_shader_module(r, module->module_info);
|
||||
module->module_info = NULL;
|
||||
}
|
||||
|
||||
static bool shader_module_cache_entry_compare(Lru *lru, LruNode *node,
|
||||
void *key)
|
||||
{
|
||||
ShaderModuleCacheEntry *module =
|
||||
container_of(node, ShaderModuleCacheEntry, node);
|
||||
return memcmp(&module->key, key, sizeof(ShaderModuleCacheKey));
|
||||
}
|
||||
|
||||
static void shader_cache_init(PGRAPHState *pg)
|
||||
{
|
||||
PGRAPHVkState *r = pg->vk_renderer_state;
|
||||
|
@ -295,6 +345,22 @@ static void shader_cache_init(PGRAPHState *pg)
|
|||
r->shader_cache.init_node = shader_cache_entry_init;
|
||||
r->shader_cache.compare_nodes = shader_cache_entry_compare;
|
||||
r->shader_cache.post_node_evict = shader_cache_entry_post_evict;
|
||||
|
||||
/* FIXME: Make this configurable */
|
||||
const size_t shader_module_cache_size = 50 * 1024;
|
||||
lru_init(&r->shader_module_cache);
|
||||
r->shader_module_cache_entries =
|
||||
g_malloc_n(shader_module_cache_size, sizeof(ShaderModuleCacheEntry));
|
||||
assert(r->shader_module_cache_entries != NULL);
|
||||
for (int i = 0; i < shader_module_cache_size; i++) {
|
||||
lru_add_free(&r->shader_module_cache,
|
||||
&r->shader_module_cache_entries[i].node);
|
||||
}
|
||||
|
||||
r->shader_module_cache.init_node = shader_module_cache_entry_init;
|
||||
r->shader_module_cache.compare_nodes = shader_module_cache_entry_compare;
|
||||
r->shader_module_cache.post_node_evict =
|
||||
shader_module_cache_entry_post_evict;
|
||||
}
|
||||
|
||||
static void shader_cache_finalize(PGRAPHState *pg)
|
||||
|
@ -304,6 +370,21 @@ static void shader_cache_finalize(PGRAPHState *pg)
|
|||
lru_flush(&r->shader_cache);
|
||||
g_free(r->shader_cache_entries);
|
||||
r->shader_cache_entries = NULL;
|
||||
|
||||
lru_flush(&r->shader_module_cache);
|
||||
g_free(r->shader_module_cache_entries);
|
||||
r->shader_module_cache_entries = NULL;
|
||||
}
|
||||
|
||||
static ShaderModuleInfo *
|
||||
get_and_ref_shader_module_for_key(PGRAPHVkState *r, ShaderModuleCacheKey *key)
|
||||
{
|
||||
uint64_t hash = fast_hash((void *)key, sizeof(ShaderModuleCacheKey));
|
||||
LruNode *node = lru_lookup(&r->shader_module_cache, hash, key);
|
||||
ShaderModuleCacheEntry *module =
|
||||
container_of(node, ShaderModuleCacheEntry, node);
|
||||
pgraph_vk_ref_shader_module(module->module_info);
|
||||
return module->module_info;
|
||||
}
|
||||
|
||||
static ShaderBinding *gen_shaders(PGRAPHState *pg, ShaderState *state)
|
||||
|
@ -328,46 +409,36 @@ static ShaderBinding *gen_shaders(PGRAPHState *pg, ShaderState *state)
|
|||
/* Ensure numeric values are printed with '.' radix, no grouping */
|
||||
setlocale(LC_NUMERIC, "C");
|
||||
|
||||
MString *geometry_shader_code = pgraph_glsl_gen_geom(
|
||||
&state->geom, (GenGeomGlslOptions){ .vulkan = true });
|
||||
if (geometry_shader_code) {
|
||||
NV2A_VK_DPRINTF("geometry shader: \n%s",
|
||||
mstring_get_str(geometry_shader_code));
|
||||
snode->geometry = pgraph_vk_create_shader_module_from_glsl(
|
||||
r, VK_SHADER_STAGE_GEOMETRY_BIT,
|
||||
mstring_get_str(geometry_shader_code));
|
||||
mstring_unref(geometry_shader_code);
|
||||
ShaderModuleCacheKey key;
|
||||
|
||||
bool need_geometry_shader = pgraph_glsl_need_geom(&state->geom);
|
||||
if (need_geometry_shader) {
|
||||
memset(&key, 0, sizeof(key));
|
||||
key.kind = VK_SHADER_STAGE_GEOMETRY_BIT;
|
||||
key.geom.state = state->geom;
|
||||
key.geom.glsl_opts.vulkan = true;
|
||||
snode->geometry = get_and_ref_shader_module_for_key(r, &key);
|
||||
} else {
|
||||
snode->geometry = NULL;
|
||||
}
|
||||
|
||||
MString *vertex_shader_code = pgraph_glsl_gen_vsh(
|
||||
&state->vsh, (GenVshGlslOptions){
|
||||
.vulkan = true,
|
||||
.prefix_outputs = geometry_shader_code != NULL,
|
||||
.use_push_constants_for_uniform_attrs =
|
||||
r->use_push_constants_for_uniform_attrs,
|
||||
.ubo_binding = VSH_UBO_BINDING,
|
||||
});
|
||||
NV2A_VK_DPRINTF("vertex shader: \n%s",
|
||||
mstring_get_str(vertex_shader_code));
|
||||
snode->vertex = pgraph_vk_create_shader_module_from_glsl(
|
||||
r, VK_SHADER_STAGE_VERTEX_BIT,
|
||||
mstring_get_str(vertex_shader_code));
|
||||
mstring_unref(vertex_shader_code);
|
||||
memset(&key, 0, sizeof(key));
|
||||
key.kind = VK_SHADER_STAGE_VERTEX_BIT;
|
||||
key.vsh.state = state->vsh;
|
||||
key.vsh.glsl_opts.vulkan = true;
|
||||
key.vsh.glsl_opts.prefix_outputs = need_geometry_shader;
|
||||
key.vsh.glsl_opts.use_push_constants_for_uniform_attrs =
|
||||
r->use_push_constants_for_uniform_attrs;
|
||||
key.vsh.glsl_opts.ubo_binding = VSH_UBO_BINDING;
|
||||
snode->vertex = get_and_ref_shader_module_for_key(r, &key);
|
||||
|
||||
MString *fragment_shader_code = pgraph_glsl_gen_psh(
|
||||
&state->psh, (GenPshGlslOptions){
|
||||
.vulkan = true,
|
||||
.ubo_binding = PSH_UBO_BINDING,
|
||||
.tex_binding = PSH_TEX_BINDING,
|
||||
});
|
||||
NV2A_VK_DPRINTF("fragment shader: \n%s",
|
||||
mstring_get_str(fragment_shader_code));
|
||||
snode->fragment = pgraph_vk_create_shader_module_from_glsl(
|
||||
r, VK_SHADER_STAGE_FRAGMENT_BIT,
|
||||
mstring_get_str(fragment_shader_code));
|
||||
mstring_unref(fragment_shader_code);
|
||||
memset(&key, 0, sizeof(key));
|
||||
key.kind = VK_SHADER_STAGE_FRAGMENT_BIT;
|
||||
key.psh.state = state->psh;
|
||||
key.psh.glsl_opts.vulkan = true;
|
||||
key.psh.glsl_opts.ubo_binding = PSH_UBO_BINDING;
|
||||
key.psh.glsl_opts.tex_binding = PSH_TEX_BINDING;
|
||||
snode->fragment = get_and_ref_shader_module_for_key(r, &key);
|
||||
|
||||
if (previous_numeric_locale) {
|
||||
setlocale(LC_NUMERIC, previous_numeric_locale);
|
||||
|
|
Loading…
Reference in New Issue