diff --git a/hw/xbox/nv2a/pgraph/vk/draw.c b/hw/xbox/nv2a/pgraph/vk/draw.c index e4b3d59e6a..c1218d58b5 100644 --- a/hw/xbox/nv2a/pgraph/vk/draw.c +++ b/hw/xbox/nv2a/pgraph/vk/draw.c @@ -19,7 +19,9 @@ #include "qemu/osdep.h" #include "qemu/fast-hash.h" +#include "qemu/timer.h" #include "renderer.h" +#include "ui/xemu-settings.h" #include "hw/xbox/nv2a/pgraph/prim_rewrite.h" #include #ifdef __aarch64__ @@ -107,6 +109,8 @@ static bool pipeline_cache_entry_compare(Lru *lru, LruNode *node, } #ifdef __ANDROID__ +#define PIPELINE_CACHE_SAVE_INTERVAL_US (30 * 1000000LL) + static char *get_pipeline_cache_path(PGRAPHVkState *r) { char *pref_path = SDL_GetPrefPath("xemu", "xemu"); @@ -120,6 +124,62 @@ static char *get_pipeline_cache_path(PGRAPHVkState *r) SDL_free(pref_path); return path; } + +static void save_pipeline_cache_to_disk(PGRAPHVkState *r) +{ + g_autofree char *cache_path = get_pipeline_cache_path(r); + size_t data_size = 0; + VkResult res; + + if (!cache_path) { + return; + } + + res = vkGetPipelineCacheData(r->device, r->vk_pipeline_cache, + &data_size, NULL); + if (res != VK_SUCCESS || data_size == 0) { + return; + } + + g_autofree void *data = g_malloc(data_size); + res = vkGetPipelineCacheData(r->device, r->vk_pipeline_cache, + &data_size, data); + if (res != VK_SUCCESS) { + return; + } + + GError *err = NULL; + if (g_file_set_contents(cache_path, (const gchar *)data, + (gssize)data_size, &err)) { + __android_log_print(ANDROID_LOG_INFO, "xemu-vk", + "Saved pipeline cache: %zu bytes", data_size); + } else { + __android_log_print(ANDROID_LOG_WARN, "xemu-vk", + "Failed to save pipeline cache"); + if (err) { + g_error_free(err); + } + } +} + +static void maybe_save_pipeline_cache(PGRAPHVkState *r) +{ + int64_t now; + + if (!g_config.perf.cache_shaders) { + return; + } + + now = qemu_clock_get_us(QEMU_CLOCK_REALTIME); + if (r->pipeline_cache_last_save_us != 0 && + (now - r->pipeline_cache_last_save_us) < + PIPELINE_CACHE_SAVE_INTERVAL_US) { + return; + } + + r->pipeline_cache_last_save_us = now; + save_pipeline_cache_to_disk(r); +} #endif static void init_pipeline_cache(PGRAPHState *pg) @@ -135,19 +195,23 @@ static void init_pipeline_cache(PGRAPHState *pg) }; #ifdef __ANDROID__ - g_autofree char *cache_path = get_pipeline_cache_path(r); - gchar *cache_data = NULL; + g_autofree gchar *cache_data = NULL; gsize cache_data_size = 0; - if (cache_path) { - GError *err = NULL; - if (g_file_get_contents(cache_path, &cache_data, &cache_data_size, &err)) { - cache_info.initialDataSize = (size_t)cache_data_size; - cache_info.pInitialData = (const void *)cache_data; - __android_log_print(ANDROID_LOG_INFO, "xemu-vk", - "Loaded pipeline cache: %zu bytes", cache_data_size); - } else { - if (err) { - g_error_free(err); + if (g_config.perf.cache_shaders) { + g_autofree char *cache_path = get_pipeline_cache_path(r); + if (cache_path) { + GError *err = NULL; + if (g_file_get_contents(cache_path, &cache_data, &cache_data_size, + &err)) { + cache_info.initialDataSize = (size_t)cache_data_size; + cache_info.pInitialData = (const void *)cache_data; + __android_log_print(ANDROID_LOG_INFO, "xemu-vk", + "Loaded pipeline cache: %zu bytes", + cache_data_size); + } else { + if (err) { + g_error_free(err); + } } } } @@ -156,10 +220,6 @@ static void init_pipeline_cache(PGRAPHState *pg) VK_CHECK(vkCreatePipelineCache(r->device, &cache_info, NULL, &r->vk_pipeline_cache)); -#ifdef __ANDROID__ - g_free(cache_data); -#endif - const size_t pipeline_cache_size = 2048; lru_init(&r->pipeline_cache); r->pipeline_cache_entries = @@ -178,38 +238,16 @@ static void finalize_pipeline_cache(PGRAPHState *pg) { PGRAPHVkState *r = pg->vk_renderer_state; +#ifdef __ANDROID__ + if (g_config.perf.cache_shaders) { + save_pipeline_cache_to_disk(r); + } +#endif + lru_flush(&r->pipeline_cache); g_free(r->pipeline_cache_entries); r->pipeline_cache_entries = NULL; -#ifdef __ANDROID__ - g_autofree char *cache_path = get_pipeline_cache_path(r); - if (cache_path) { - size_t data_size = 0; - VkResult res = vkGetPipelineCacheData(r->device, r->vk_pipeline_cache, - &data_size, NULL); - if (res == VK_SUCCESS && data_size > 0) { - g_autofree void *data = g_malloc(data_size); - res = vkGetPipelineCacheData(r->device, r->vk_pipeline_cache, - &data_size, data); - if (res == VK_SUCCESS) { - GError *err = NULL; - if (g_file_set_contents(cache_path, (const gchar *)data, - (gssize)data_size, &err)) { - __android_log_print(ANDROID_LOG_INFO, "xemu-vk", - "Saved pipeline cache: %zu bytes", data_size); - } else { - __android_log_print(ANDROID_LOG_WARN, "xemu-vk", - "Failed to save pipeline cache"); - if (err) { - g_error_free(err); - } - } - } - } - } -#endif - vkDestroyPipelineCache(r->device, r->vk_pipeline_cache, NULL); } @@ -661,6 +699,9 @@ static void create_clear_pipeline(PGRAPHState *pg) r->pipeline_binding = snode; r->pipeline_binding_changed = true; +#ifdef __ANDROID__ + maybe_save_pipeline_cache(r); +#endif NV2A_VK_DGROUP_END(); } @@ -1077,6 +1118,9 @@ static void create_pipeline(PGRAPHState *pg) r->pipeline_binding = snode; r->pipeline_binding_changed = true; +#ifdef __ANDROID__ + maybe_save_pipeline_cache(r); +#endif NV2A_VK_DGROUP_END(); } diff --git a/hw/xbox/nv2a/pgraph/vk/renderer.h b/hw/xbox/nv2a/pgraph/vk/renderer.h index 343fef7b8c..2be05ba080 100644 --- a/hw/xbox/nv2a/pgraph/vk/renderer.h +++ b/hw/xbox/nv2a/pgraph/vk/renderer.h @@ -364,6 +364,7 @@ typedef struct PGRAPHVkState { PipelineBinding *pipeline_cache_entries; PipelineBinding *pipeline_binding; bool pipeline_binding_changed; + int64_t pipeline_cache_last_save_us; VkDescriptorPool descriptor_pool; VkDescriptorSetLayout descriptor_set_layout;