File vita3k-issue664.patch of Package vita3k

diff --git a/vita3k/config/src/config.cpp b/vita3k/config/src/config.cpp
index b4a7f3e1..ca78053e 100644
--- a/vita3k/config/src/config.cpp
+++ b/vita3k/config/src/config.cpp
@@ -30,6 +30,11 @@
 #include <exception>
 #include <iostream>
 
+fs::path user_home = getenv("HOME");
+fs::path local_path = user_home / "/.local/share/Vita3K/";
+fs::path config_path = user_home / "/.config/Vita3k/";
+fs::path output_path = local_path;
+
 namespace config {
 
 static std::set<std::string> get_file_set(const fs::path &loc, bool dirs_only = true) {
@@ -54,14 +59,14 @@ static std::set<std::string> get_file_set(const fs::path &loc, bool dirs_only =
     return cur_set;
 }
 
-static fs::path check_path(const fs::path &output_path) {
-    if (output_path.filename() != "config.yml") {
-        if (!output_path.has_extension()) // assume it is a folder
-            return output_path / "config.yml";
-        if (output_path.extension() != ".yml")
+static fs::path check_path(const fs::path &config_path) {
+    if (config_path.filename() != "config.yml") {
+        if (!config_path.has_extension()) // assume it is a folder
+            return config_path / "config.yml";
+        if (config_path.extension() != ".yml")
             return "";
     }
-    return output_path;
+    return config_path;
 }
 
 static ExitCode parse(Config &cfg, const fs::path &load_path, const fs::path &root_pref_path) {
@@ -118,12 +123,12 @@ ExitCode serialize_config(Config &cfg, const fs::path &output_path) {
 ExitCode init_config(Config &cfg, int argc, char **argv, const Root &root_paths) {
     // Always generate the default configuration file
     Config command_line{};
-    serialize_config(command_line, root_paths.get_base_path() / "data/config/default.yml");
+    serialize_config(command_line, output_path / "data/config/default.yml");
     // Load base path configuration by default; otherwise, move the default to the base path
-    if (fs::exists(check_path(root_paths.get_base_path())))
-        parse(cfg, root_paths.get_base_path(), root_paths.get_base_path());
+    if (fs::exists(check_path(config_path)))
+        parse(cfg, config_path, root_paths.get_pref_path_string());
     else
-        fs::copy(root_paths.get_base_path() / "data/config/default.yml", root_paths.get_base_path() / "config.yml");
+        fs::copy(output_path / "data/config/default.yml", config_path / "config.yml");
 
     // Declare all options
     CLI::App app{ "Vita3K Command Line Interface" }; // "--help,-h" is automatically generated
@@ -222,9 +227,9 @@ ExitCode init_config(Config &cfg, int argc, char **argv, const Root &root_paths)
         cfg.pkg_zrif = std::move(command_line.pkg_zrif);
         return QuitRequested;
     }
-    if (command_line.load_config || command_line.config_path != root_paths.get_base_path()) {
+    if (command_line.load_config || command_line.config_path != config_path) {
         if (command_line.config_path.empty()) {
-            command_line.config_path = root_paths.get_base_path();
+            command_line.config_path = config_path;
         } else {
             if (parse(command_line, command_line.config_path, root_paths.get_base_path()) != Success)
                 return InitConfigFailed;
diff --git a/vita3k/io/src/io.cpp b/vita3k/io/src/io.cpp
index 8ca6fa06..d075560e 100644
--- a/vita3k/io/src/io.cpp
+++ b/vita3k/io/src/io.cpp
@@ -96,7 +96,7 @@ SpaceInfo get_space_info(const VitaIoDevice device, const std::string &vfs_path,
 // * End utility functions *
 // ****************************
 
-bool init(IOState &io, const fs::path &base_path, const fs::path &pref_path, bool redirect_stdio) {
+bool init(IOState &io, const fs::path &output_path, const fs::path &pref_path, bool redirect_stdio) {
     // Iterate through the entire list of devices and create the subdirectories if they do not exist
     for (auto i : VitaIoDevice::_names()) {
         if (!device::is_valid_output_path(i))
@@ -128,9 +128,9 @@ bool init(IOState &io, const fs::path &base_path, const fs::path &pref_path, boo
     if (!fs::exists(uma0_data))
         fs::create_directory(uma0_data);
 
-    fs::create_directories(base_path / "cache/shaders");
-    fs::create_directory(base_path / "shaderlog");
-    fs::create_directory(base_path / "texturelog");
+    fs::create_directories(output_path / "cache/shaders");
+    fs::create_directory(output_path / "shaderlog");
+    fs::create_directory(output_path / "texturelog");
 
     io.redirect_stdio = redirect_stdio;
 
diff --git a/vita3k/main.cpp b/vita3k/main.cpp
index 27440b90..0f6f2424 100644
--- a/vita3k/main.cpp
+++ b/vita3k/main.cpp
@@ -84,8 +84,16 @@ static void run_execv(char *argv[], EmuEnvState &emuenv) {
 int main(int argc, char *argv[]) {
     ZoneScoped; // Tracy - Track main function scope
     Root root_paths;
+#ifdef WIN32
     root_paths.set_base_path(string_utils::utf_to_wide(SDL_GetBasePath()));
     root_paths.set_pref_path(string_utils::utf_to_wide(SDL_GetPrefPath(org_name, app_name)));
+#elif defined(__unix__) || defined(__APPLE__) && defined(__MACH__)
+    fs::path user_home = getenv("HOME");
+    fs::path local_path = user_home / "/.local/share/Vita3K/";
+    fs::path config_path = user_home / "/.config/Vita3k/";
+    root_paths.set_base_path(local_path);
+    root_paths.set_pref_path(config_path);
+#endif
 
     // Create default preference path for safety
     if (!fs::exists(root_paths.get_pref_path()))
diff --git a/vita3k/renderer/src/gl/screen_render.cpp b/vita3k/renderer/src/gl/screen_render.cpp
index 47c78ff3..d18a062d 100644
--- a/vita3k/renderer/src/gl/screen_render.cpp
+++ b/vita3k/renderer/src/gl/screen_render.cpp
@@ -23,10 +23,10 @@
 
 namespace renderer::gl {
 
-bool ScreenRenderer::init(const std::string &base_path) {
+bool ScreenRenderer::init(const std::string &output_path) {
     glGenTextures(1, &m_screen_texture);
 
-    const auto builtin_shaders_path = base_path + "shaders-builtin/opengl/";
+    const auto builtin_shaders_path = output_path + "shaders-builtin/opengl/";
 
     m_render_shader_nofilter = ::gl::load_shaders(builtin_shaders_path + "render_main.vert", builtin_shaders_path + "render_main.frag");
     m_render_shader_fxaa = ::gl::load_shaders(builtin_shaders_path + "render_main.vert", builtin_shaders_path + "render_main_fxaa.frag");
diff --git a/vita3k/renderer/src/shaders.cpp b/vita3k/renderer/src/shaders.cpp
index 18098cc7..05ffe35d 100644
--- a/vita3k/renderer/src/shaders.cpp
+++ b/vita3k/renderer/src/shaders.cpp
@@ -33,7 +33,7 @@
 namespace renderer {
 
 bool get_shaders_cache_hashs(State &renderer) {
-    const auto shaders_path{ fs::path(renderer.base_path) / "cache/shaders" / renderer.title_id / renderer.self_name };
+    const auto shaders_path{ fs::path(output_path) / "cache/shaders" / renderer.title_id / renderer.self_name };
     const std::string hash_file_name = fmt::format("hashs-{}.dat", (renderer.current_backend == Backend::OpenGL) ? "gl" : "vk");
 
     if (renderer.current_backend == Backend::Vulkan) {
@@ -54,7 +54,7 @@ bool get_shaders_cache_hashs(State &renderer) {
         if (versionInFile != shader::CURRENT_VERSION) {
             shaders_hashs.close();
             fs::remove_all(shaders_path);
-            fs::remove_all(fs::path(renderer.base_path) / "shaderlog" / renderer.title_id / renderer.self_name);
+            fs::remove_all(fs::path(output_path) / "shaderlog" / renderer.title_id / renderer.self_name);
             LOG_WARN("Current version of cache: {}, is outdated, recreate it.", versionInFile);
             return false;
         }
@@ -83,7 +83,7 @@ bool get_shaders_cache_hashs(State &renderer) {
 }
 
 void save_shaders_cache_hashs(State &renderer, std::vector<ShadersHash> &shaders_cache_hashs) {
-    const auto shaders_path{ fs::path(renderer.base_path) / "cache/shaders" / renderer.title_id / renderer.self_name };
+    const auto shaders_path{ fs::path(output_path) / "cache/shaders" / renderer.title_id / renderer.self_name };
     if (!fs::exists(shaders_path))
         fs::create_directory(shaders_path);
     std::string hash_file_name = fmt::format("hashs-{}.dat", (renderer.current_backend == Backend::OpenGL) ? "gl" : "vk");
@@ -111,8 +111,8 @@ void save_shaders_cache_hashs(State &renderer, std::vector<ShadersHash> &shaders
     }
 }
 
-static bool load_shader(const char *hash, const char *extension, const char *base_path, const char *title_id, const char *self_name, char **destination, std::size_t &size_read) {
-    const auto shader_path = fs_utils::construct_file_name(base_path, (fs::path("cache/shaders") / title_id / self_name).string().c_str(), hash, extension);
+static bool load_shader(const char *hash, const char *extension, const char *output_path, const char *title_id, const char *self_name, char **destination, std::size_t &size_read) {
+    const auto shader_path = fs_utils::construct_file_name(output_path, (fs::path("cache/shaders") / title_id / self_name).string().c_str(), hash, extension);
     fs::ifstream is(shader_path, fs::ifstream::binary);
     if (!is) {
         return false;
@@ -140,21 +140,21 @@ static const Sha256Hash get_shader_hash(const SceGxmProgram &program) {
 }
 
 template <typename R>
-R load_shader_generic(const char *hash_text, const char *base_path, const char *title_id, const char *self_name, const char *shader_type_str) {
+R load_shader_generic(const char *hash_text, const char *output_path, const char *title_id, const char *self_name, const char *shader_type_str) {
     std::size_t read_size = 0;
     R source;
 
-    if (load_shader(hash_text, shader_type_str, base_path, title_id, self_name, nullptr, read_size)) {
+    if (load_shader(hash_text, shader_type_str, output_path, title_id, self_name, nullptr, read_size)) {
         source.resize((read_size + sizeof(typename R::value_type) - 1) / sizeof(typename R::value_type));
 
         char *dest_pointer = reinterpret_cast<char *>(source.data());
-        load_shader(hash_text, shader_type_str, base_path, title_id, self_name, &dest_pointer, read_size);
+        load_shader(hash_text, shader_type_str, output_path, title_id, self_name, &dest_pointer, read_size);
     }
 
     return source;
 }
 
-shader::GeneratedShader load_shader_generic(shader::Target target, const SceGxmProgram &program, const FeatureState &features, const shader::Hints &hints, bool maskupdate, const char *base_path, const char *title_id, const char *self_name, const char *shader_type_str, const std::string &shader_version, bool shader_cache) {
+shader::GeneratedShader load_shader_generic(shader::Target target, const SceGxmProgram &program, const FeatureState &features, const shader::Hints &hints, bool maskupdate, const char *output_path, const char *title_id, const char *self_name, const char *shader_type_str, const std::string &shader_version, bool shader_cache) {
     // TODO: no need to recompute the hash here
     const std::string hash_text = hex_string(get_shader_hash(program));
     // Set Shader Hash with Version
@@ -162,12 +162,12 @@ shader::GeneratedShader load_shader_generic(shader::Target target, const SceGxmP
 
     if (shader_cache) {
         if (target == shader::Target::GLSLOpenGL) {
-            std::string source = load_shader_generic<std::string>(hash_hex_ver.c_str(), base_path, title_id, self_name, shader_type_str);
+            std::string source = load_shader_generic<std::string>(hash_hex_ver.c_str(), output_path, title_id, self_name, shader_type_str);
             if (!source.empty()) {
                 return { source, std::vector<uint32_t>() };
             }
         } else {
-            std::vector<uint32_t> source = load_shader_generic<std::vector<uint32_t>>(hash_hex_ver.c_str(), base_path, title_id, self_name, shader_type_str);
+            std::vector<uint32_t> source = load_shader_generic<std::vector<uint32_t>>(hash_hex_ver.c_str(), output_path, title_id, self_name, shader_type_str);
             if (!source.empty())
                 return { "", source };
         }
@@ -179,10 +179,10 @@ shader::GeneratedShader load_shader_generic(shader::Target target, const SceGxmP
     std::string disasm_dump;
 
     const fs::path shader_base_dir{ fs::path("shaderlog") / title_id / self_name };
-    if (!fs::exists(base_path / shader_base_dir))
-        fs::create_directories(base_path / shader_base_dir);
+    if (!fs::exists(output_path / shader_base_dir))
+        fs::create_directories(output_path / shader_base_dir);
 
-    auto shader_base_path = fs_utils::construct_file_name(base_path, shader_base_dir, hash_hex_ver.c_str(), ".gxp");
+    auto shader_base_path = fs_utils::construct_file_name(output_path, shader_base_dir, hash_hex_ver.c_str(), ".gxp");
 
     // Dump gxp binary
     fs::ofstream of{ shader_base_path, fs::ofstream::binary };
@@ -206,14 +206,14 @@ shader::GeneratedShader load_shader_generic(shader::Target target, const SceGxmP
 
     // Copy shader generate to shaders cache
     const auto shaders_cache_path = fs::path("cache/shaders") / title_id / self_name;
-    if (!fs::exists(base_path / shaders_cache_path))
-        fs::create_directories(base_path / shaders_cache_path);
+    if (!fs::exists(output_path / shaders_cache_path))
+        fs::create_directories(output_path / shaders_cache_path);
 
     if (target == shader::Target::GLSLOpenGL) {
         shader_base_path.replace_extension(shader_type_str);
         if (fs::exists(shader_base_path)) {
             try {
-                const auto shader_dst_path = fs_utils::construct_file_name(base_path, shaders_cache_path, hash_hex_ver.c_str(), shader_type_str);
+                const auto shader_dst_path = fs_utils::construct_file_name(output_path, shaders_cache_path, hash_hex_ver.c_str(), shader_type_str);
                 fs::copy_file(shader_base_path, shader_dst_path, fs::copy_option::overwrite_if_exists);
                 fs::remove(shader_base_path);
             } catch (std::exception &e) {
@@ -221,7 +221,7 @@ shader::GeneratedShader load_shader_generic(shader::Target target, const SceGxmP
             }
         }
     } else {
-        const auto shader_dst_path = fs_utils::construct_file_name(base_path, shaders_cache_path, hash_hex_ver.c_str(), "spv");
+        const auto shader_dst_path = fs_utils::construct_file_name(output_path, shaders_cache_path, hash_hex_ver.c_str(), "spv");
         fs::ofstream of{ shader_dst_path, fs::ofstream::binary };
         if (!of.fail()) {
             of.write(reinterpret_cast<const char *>(source.spirv.data()), sizeof(uint32_t) * source.spirv.size());
@@ -232,7 +232,7 @@ shader::GeneratedShader load_shader_generic(shader::Target target, const SceGxmP
     return source;
 }
 
-std::string load_glsl_shader(const SceGxmProgram &program, const FeatureState &features, const shader::Hints &hints, bool maskupdate, const char *base_path, const char *title_id, const char *self_name, const std::string &shader_version, bool shader_cache) {
+std::string load_glsl_shader(const SceGxmProgram &program, const FeatureState &features, const shader::Hints &hints, bool maskupdate, const char *output_path, const char *title_id, const char *self_name, const std::string &shader_version, bool shader_cache) {
     SceGxmProgramType program_type = program.get_type();
 
     auto shader_type_to_str = [](SceGxmProgramType type) {
@@ -240,25 +240,25 @@ std::string load_glsl_shader(const SceGxmProgram &program, const FeatureState &f
     };
 
     const char *shader_type_str = shader_type_to_str(program_type);
-    return load_shader_generic(shader::Target::GLSLOpenGL, program, features, hints, maskupdate, base_path, title_id, self_name, shader_type_str, shader_version, shader_cache).glsl;
+    return load_shader_generic(shader::Target::GLSLOpenGL, program, features, hints, maskupdate, output_path, title_id, self_name, shader_type_str, shader_version, shader_cache).glsl;
 }
 
-std::vector<uint32_t> load_spirv_shader(const SceGxmProgram &program, const FeatureState &features, bool is_vulkan, const shader::Hints &hints, bool maskupdate, const char *base_path, const char *title_id, const char *self_name, const std::string &shader_version, bool shader_cache) {
+std::vector<uint32_t> load_spirv_shader(const SceGxmProgram &program, const FeatureState &features, bool is_vulkan, const shader::Hints &hints, bool maskupdate, const char *output_path, const char *title_id, const char *self_name, const std::string &shader_version, bool shader_cache) {
     const shader::Target target = is_vulkan ? shader::Target::SpirVVulkan : shader::Target::SpirVOpenGL;
     auto shader_type_to_str = [](SceGxmProgramType type) {
         return (type == SceGxmProgramType::Vertex) ? "vert.spv.txt" : ((type == SceGxmProgramType::Fragment) ? "frag.spv.txt" : "unknown.spv.txt");
     };
     const char *shader_type_str = shader_type_to_str(program.get_type());
 
-    return load_shader_generic(target, program, features, hints, maskupdate, base_path, title_id, self_name, shader_type_str, shader_version, shader_cache).spirv;
+    return load_shader_generic(target, program, features, hints, maskupdate, output_path, title_id, self_name, shader_type_str, shader_version, shader_cache).spirv;
 }
 
-std::string pre_load_shader_glsl(const char *hash_text, const char *shader_type_str, const char *base_path, const char *title_id, const char *self_name) {
-    return load_shader_generic<std::string>(hash_text, base_path, title_id, self_name, shader_type_str);
+std::string pre_load_shader_glsl(const char *hash_text, const char *shader_type_str, const char *output_path, const char *title_id, const char *self_name) {
+    return load_shader_generic<std::string>(hash_text, output_path, title_id, self_name, shader_type_str);
 }
 
-std::vector<uint32_t> pre_load_shader_spirv(const char *hash_text, const char *shader_type_str, const char *base_path, const char *title_id, const char *self_name) {
-    return load_shader_generic<std::vector<uint32_t>>(hash_text, base_path, title_id, self_name, shader_type_str);
+std::vector<uint32_t> pre_load_shader_spirv(const char *hash_text, const char *shader_type_str, const char *output_path, const char *title_id, const char *self_name) {
+    return load_shader_generic<std::vector<uint32_t>>(hash_text, output_path, title_id, self_name, shader_type_str);
 }
 
 } // namespace renderer
diff --git a/vita3k/renderer/src/vulkan/screen_renderer.cpp b/vita3k/renderer/src/vulkan/screen_renderer.cpp
index 0359abaf..dbb3b07b 100644
--- a/vita3k/renderer/src/vulkan/screen_renderer.cpp
+++ b/vita3k/renderer/src/vulkan/screen_renderer.cpp
@@ -53,7 +53,7 @@ bool ScreenRenderer::create(SDL_Window *window) {
     return true;
 }
 
-bool ScreenRenderer::setup(const char *base_path) {
+bool ScreenRenderer::setup(const char *output_path) {
     vk::SemaphoreCreateInfo semaphore_info{};
     image_acquired_semaphore = state.device.createSemaphore(semaphore_info);
     image_ready_semaphore = state.device.createSemaphore(semaphore_info);
@@ -97,7 +97,7 @@ bool ScreenRenderer::setup(const char *base_path) {
     LOG_INFO("Present mode: {}", vk::to_string(present_mode));
 
     // part of the swapchain that does not need to be rebuilt every time
-    const auto builtin_shaders_path = std::string(base_path) + "shaders-builtin/vulkan/";
+    const auto builtin_shaders_path = std::string(output_path) + "shaders-builtin/vulkan/";
     shader_vertex = vkutil::load_shader(state.device, builtin_shaders_path + "render_main.vert.spv");
     shader_fragment = vkutil::load_shader(state.device, builtin_shaders_path + "render_main.frag.spv");
     shader_fragment_fxaa = vkutil::load_shader(state.device, builtin_shaders_path + "render_main_fxaa.frag.spv");
@@ -665,4 +665,4 @@ void ScreenRenderer::create_surface_image() {
     std::tie(vita_surface_staging, vita_surface_staging_alloc) = state.allocator.createBuffer(buffer_info, vkutil::vma_mapped_alloc, vita_surface_staging_info);
 }
 
-} // namespace renderer::vulkan
\ No newline at end of file
+} // namespace renderer::vulkan
diff --git a/vita3k/util/include/util/fs.h b/vita3k/util/include/util/fs.h
index 8076d61a..48c8325a 100644
--- a/vita3k/util/include/util/fs.h
+++ b/vita3k/util/include/util/fs.h
@@ -52,6 +52,11 @@ public:
     }
 }; // class root
 
+extern fs::path user_home;
+extern fs::path config_path;
+extern fs::path local_path;
+extern fs::path output_path;
+
 namespace fs_utils {
 
 /**
diff --git a/vita3k/util/src/util.cpp b/vita3k/util/src/util.cpp
index 2867b80d..de91f894 100644
--- a/vita3k/util/src/util.cpp
+++ b/vita3k/util/src/util.cpp
@@ -66,12 +66,28 @@ void flush() {
     spdlog::details::registry::instance().flush_all();
 }
 
+static fs::path check_path(const fs::path &output_path) {
+    if (output_path.filename() != LOG_FILE_NAME) {
+        if (!output_path.has_extension()) // assume it is a folder
+            return output_path / LOG_FILE_NAME;
+        if (output_path.extension() != ".log")
+            return "";
+    }
+    return output_path;
+}
+
 ExitCode init(const Root &root_paths, bool use_stdout) {
+    const auto output = check_path(output_path);
+    if (output.empty())
+        return InvalidApplicationPath;
+    if (!fs::exists(output.parent_path()))
+        fs::create_directories(output.parent_path());
+
     sinks.clear();
     if (use_stdout)
         sinks.push_back(std::make_shared<spdlog::sinks::stdout_color_sink_mt>());
 
-    if (add_sink(root_paths.get_base_path() / LOG_FILE_NAME) != Success)
+    if (add_sink(output_path.string() / LOG_FILE_NAME) != Success)
         return InitConfigFailed;
 
     spdlog::set_error_handler([](const std::string &msg) {
@@ -106,12 +122,12 @@ void set_level(spdlog::level::level_enum log_level) {
     spdlog::set_level(log_level);
 }
 
-ExitCode add_sink(const fs::path &log_path) {
+ExitCode add_sink(const fs::path &output_path) {
     try {
 #ifdef WIN32
-        sinks.push_back(std::make_shared<spdlog::sinks::basic_file_sink_mt>(log_path.generic_path().wstring(), true));
+        sinks.push_back(std::make_shared<spdlog::sinks::basic_file_sink_mt>(output_path.generic_path().wstring(), true));
 #else
-        sinks.push_back(std::make_shared<spdlog::sinks::basic_file_sink_mt>(log_path.generic_path().string(), true));
+        sinks.push_back(std::make_shared<spdlog::sinks::basic_file_sink_mt>(output_path.generic_path().string(), true));
 #endif
     } catch (const spdlog::spdlog_ex &ex) {
         std::cerr << "File log initialization failed: " << ex.what() << std::endl;
openSUSE Build Service is sponsored by