Implement shader caching
* Shader compilation is now cached. Subsequent loads take less than a millisecond. * Improved game, editor and project manager startup time. * Editor uses .godot/shader_cache to store shaders. * Game uses user://shader_cache * Project manager uses $config_dir/shader_cache * Options to tweak shader caching in project settings. * Editor path configuration moved from EditorSettings to new class, EditorPaths, so it can be available early on (before shaders are compiled). * Reworked ShaderCompilerRD to ensure deterministic shader code creation (else shader may change and cache will be invalidated). * Added shader compression with SMOLV: https://github.com/aras-p/smol-v
This commit is contained in:
parent
39df47b88f
commit
0d2e02945b
39 changed files with 3113 additions and 172 deletions
|
@ -360,6 +360,12 @@ Comment: SMAZ
|
||||||
Copyright: 2006-2009, Salvatore Sanfilippo
|
Copyright: 2006-2009, Salvatore Sanfilippo
|
||||||
License: BSD-3-clause
|
License: BSD-3-clause
|
||||||
|
|
||||||
|
Files: ./thirdparty/misc/smolv.cpp
|
||||||
|
./thirdparty/misc/smolv.h
|
||||||
|
Comment: SMOL-V
|
||||||
|
Copyright: 2016-2020, Aras Pranckevicius
|
||||||
|
License: public-domain or Unlicense or Expat
|
||||||
|
|
||||||
Files: ./thirdparty/misc/stb_rect_pack.h
|
Files: ./thirdparty/misc/stb_rect_pack.h
|
||||||
./thirdparty/misc/stb_vorbis.c
|
./thirdparty/misc/stb_vorbis.c
|
||||||
Comment: stb libraries
|
Comment: stb libraries
|
||||||
|
|
|
@ -59,6 +59,7 @@ thirdparty_misc_sources = [
|
||||||
"pcg.cpp",
|
"pcg.cpp",
|
||||||
"polypartition.cpp",
|
"polypartition.cpp",
|
||||||
"clipper.cpp",
|
"clipper.cpp",
|
||||||
|
"smolv.cpp",
|
||||||
]
|
]
|
||||||
thirdparty_misc_sources = [thirdparty_misc_dir + file for file in thirdparty_misc_sources]
|
thirdparty_misc_sources = [thirdparty_misc_dir + file for file in thirdparty_misc_sources]
|
||||||
env_thirdparty.add_source_files(thirdparty_obj, thirdparty_misc_sources)
|
env_thirdparty.add_source_files(thirdparty_obj, thirdparty_misc_sources)
|
||||||
|
|
|
@ -31,6 +31,7 @@
|
||||||
#include "engine.h"
|
#include "engine.h"
|
||||||
|
|
||||||
#include "core/authors.gen.h"
|
#include "core/authors.gen.h"
|
||||||
|
#include "core/config/project_settings.h"
|
||||||
#include "core/donors.gen.h"
|
#include "core/donors.gen.h"
|
||||||
#include "core/license.gen.h"
|
#include "core/license.gen.h"
|
||||||
#include "core/version.h"
|
#include "core/version.h"
|
||||||
|
@ -210,6 +211,13 @@ void Engine::get_singletons(List<Singleton> *p_singletons) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Engine::set_shader_cache_path(const String &p_path) {
|
||||||
|
shader_cache_path = p_path;
|
||||||
|
}
|
||||||
|
String Engine::get_shader_cache_path() const {
|
||||||
|
return shader_cache_path;
|
||||||
|
}
|
||||||
|
|
||||||
Engine *Engine::singleton = nullptr;
|
Engine *Engine::singleton = nullptr;
|
||||||
|
|
||||||
Engine *Engine::get_singleton() {
|
Engine *Engine::get_singleton() {
|
||||||
|
|
|
@ -72,6 +72,8 @@ private:
|
||||||
|
|
||||||
static Engine *singleton;
|
static Engine *singleton;
|
||||||
|
|
||||||
|
String shader_cache_path;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
static Engine *get_singleton();
|
static Engine *get_singleton();
|
||||||
|
|
||||||
|
@ -121,6 +123,9 @@ public:
|
||||||
Dictionary get_license_info() const;
|
Dictionary get_license_info() const;
|
||||||
String get_license_text() const;
|
String get_license_text() const;
|
||||||
|
|
||||||
|
void set_shader_cache_path(const String &p_path);
|
||||||
|
String get_shader_cache_path() const;
|
||||||
|
|
||||||
bool is_abort_on_gpu_errors_enabled() const;
|
bool is_abort_on_gpu_errors_enabled() const;
|
||||||
bool is_validation_layers_enabled() const;
|
bool is_validation_layers_enabled() const;
|
||||||
|
|
||||||
|
|
|
@ -57,6 +57,12 @@
|
||||||
[b]Note:[/b] This returns the main editor control containing the whole editor, not the 2D or 3D viewports specifically.
|
[b]Note:[/b] This returns the main editor control containing the whole editor, not the 2D or 3D viewports specifically.
|
||||||
</description>
|
</description>
|
||||||
</method>
|
</method>
|
||||||
|
<method name="get_editor_paths">
|
||||||
|
<return type="EditorPaths">
|
||||||
|
</return>
|
||||||
|
<description>
|
||||||
|
</description>
|
||||||
|
</method>
|
||||||
<method name="get_editor_scale" qualifiers="const">
|
<method name="get_editor_scale" qualifiers="const">
|
||||||
<return type="float">
|
<return type="float">
|
||||||
</return>
|
</return>
|
||||||
|
|
49
doc/classes/EditorPaths.xml
Normal file
49
doc/classes/EditorPaths.xml
Normal file
|
@ -0,0 +1,49 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8" ?>
|
||||||
|
<class name="EditorPaths" inherits="Object" version="4.0">
|
||||||
|
<brief_description>
|
||||||
|
</brief_description>
|
||||||
|
<description>
|
||||||
|
</description>
|
||||||
|
<tutorials>
|
||||||
|
</tutorials>
|
||||||
|
<methods>
|
||||||
|
<method name="get_cache_dir" qualifiers="const">
|
||||||
|
<return type="String">
|
||||||
|
</return>
|
||||||
|
<description>
|
||||||
|
</description>
|
||||||
|
</method>
|
||||||
|
<method name="get_config_dir" qualifiers="const">
|
||||||
|
<return type="String">
|
||||||
|
</return>
|
||||||
|
<description>
|
||||||
|
</description>
|
||||||
|
</method>
|
||||||
|
<method name="get_data_dir" qualifiers="const">
|
||||||
|
<return type="String">
|
||||||
|
</return>
|
||||||
|
<description>
|
||||||
|
</description>
|
||||||
|
</method>
|
||||||
|
<method name="get_self_contained_file" qualifiers="const">
|
||||||
|
<return type="String">
|
||||||
|
</return>
|
||||||
|
<description>
|
||||||
|
</description>
|
||||||
|
</method>
|
||||||
|
<method name="get_settings_dir" qualifiers="const">
|
||||||
|
<return type="String">
|
||||||
|
</return>
|
||||||
|
<description>
|
||||||
|
</description>
|
||||||
|
</method>
|
||||||
|
<method name="is_self_contained" qualifiers="const">
|
||||||
|
<return type="bool">
|
||||||
|
</return>
|
||||||
|
<description>
|
||||||
|
</description>
|
||||||
|
</method>
|
||||||
|
</methods>
|
||||||
|
<constants>
|
||||||
|
</constants>
|
||||||
|
</class>
|
|
@ -124,15 +124,6 @@
|
||||||
Returns the value of the setting specified by [code]name[/code]. This is equivalent to using [method Object.get] on the EditorSettings instance.
|
Returns the value of the setting specified by [code]name[/code]. This is equivalent to using [method Object.get] on the EditorSettings instance.
|
||||||
</description>
|
</description>
|
||||||
</method>
|
</method>
|
||||||
<method name="get_settings_dir" qualifiers="const">
|
|
||||||
<return type="String">
|
|
||||||
</return>
|
|
||||||
<description>
|
|
||||||
Gets the global settings path for the engine. Inside this path, you can find some standard paths such as:
|
|
||||||
[code]settings/tmp[/code] - Used for temporary storage of files
|
|
||||||
[code]settings/templates[/code] - Where export templates are located
|
|
||||||
</description>
|
|
||||||
</method>
|
|
||||||
<method name="has_setting" qualifiers="const">
|
<method name="has_setting" qualifiers="const">
|
||||||
<return type="bool">
|
<return type="bool">
|
||||||
</return>
|
</return>
|
||||||
|
|
|
@ -1502,6 +1502,16 @@
|
||||||
<member name="rendering/reflections/sky_reflections/texture_array_reflections.mobile" type="bool" setter="" getter="" default="false">
|
<member name="rendering/reflections/sky_reflections/texture_array_reflections.mobile" type="bool" setter="" getter="" default="false">
|
||||||
Lower-end override for [member rendering/reflections/sky_reflections/texture_array_reflections] on mobile devices, due to performance concerns or driver support.
|
Lower-end override for [member rendering/reflections/sky_reflections/texture_array_reflections] on mobile devices, due to performance concerns or driver support.
|
||||||
</member>
|
</member>
|
||||||
|
<member name="rendering/shader_compiler/shader_cache/compress" type="bool" setter="" getter="" default="true">
|
||||||
|
</member>
|
||||||
|
<member name="rendering/shader_compiler/shader_cache/enabled" type="bool" setter="" getter="" default="true">
|
||||||
|
</member>
|
||||||
|
<member name="rendering/shader_compiler/shader_cache/strip_debug" type="bool" setter="" getter="" default="false">
|
||||||
|
</member>
|
||||||
|
<member name="rendering/shader_compiler/shader_cache/strip_debug.release" type="bool" setter="" getter="" default="true">
|
||||||
|
</member>
|
||||||
|
<member name="rendering/shader_compiler/shader_cache/use_zstd_compression" type="bool" setter="" getter="" default="true">
|
||||||
|
</member>
|
||||||
<member name="rendering/shading/overrides/force_blinn_over_ggx" type="bool" setter="" getter="" default="false">
|
<member name="rendering/shading/overrides/force_blinn_over_ggx" type="bool" setter="" getter="" default="false">
|
||||||
If [code]true[/code], uses faster but lower-quality Blinn model to generate blurred reflections instead of the GGX model.
|
If [code]true[/code], uses faster but lower-quality Blinn model to generate blurred reflections instead of the GGX model.
|
||||||
</member>
|
</member>
|
||||||
|
|
|
@ -1065,7 +1065,7 @@ Error EditorExportPlatform::export_project_files(const Ref<EditorExportPreset> &
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Use default text server data.
|
// Use default text server data.
|
||||||
String icu_data_file = EditorSettings::get_singleton()->get_cache_dir().plus_file("tmp_icu_data");
|
String icu_data_file = EditorPaths::get_singleton()->get_cache_dir().plus_file("tmp_icu_data");
|
||||||
TS->save_support_data(icu_data_file);
|
TS->save_support_data(icu_data_file);
|
||||||
Vector<uint8_t> array = FileAccess::get_file_as_array(icu_data_file);
|
Vector<uint8_t> array = FileAccess::get_file_as_array(icu_data_file);
|
||||||
err = p_func(p_udata, ts_data, array, idx, total, enc_in_filters, enc_ex_filters, key);
|
err = p_func(p_udata, ts_data, array, idx, total, enc_in_filters, enc_ex_filters, key);
|
||||||
|
@ -1078,7 +1078,7 @@ Error EditorExportPlatform::export_project_files(const Ref<EditorExportPreset> &
|
||||||
}
|
}
|
||||||
|
|
||||||
String config_file = "project.binary";
|
String config_file = "project.binary";
|
||||||
String engine_cfb = EditorSettings::get_singleton()->get_cache_dir().plus_file("tmp" + config_file);
|
String engine_cfb = EditorPaths::get_singleton()->get_cache_dir().plus_file("tmp" + config_file);
|
||||||
ProjectSettings::get_singleton()->save_custom(engine_cfb, custom_map, custom_list);
|
ProjectSettings::get_singleton()->save_custom(engine_cfb, custom_map, custom_list);
|
||||||
Vector<uint8_t> data = FileAccess::get_file_as_array(engine_cfb);
|
Vector<uint8_t> data = FileAccess::get_file_as_array(engine_cfb);
|
||||||
DirAccess::remove_file_or_error(engine_cfb);
|
DirAccess::remove_file_or_error(engine_cfb);
|
||||||
|
@ -1100,9 +1100,9 @@ Error EditorExportPlatform::save_pack(const Ref<EditorExportPreset> &p_preset, c
|
||||||
|
|
||||||
// Create the temporary export directory if it doesn't exist.
|
// Create the temporary export directory if it doesn't exist.
|
||||||
DirAccessRef da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
|
DirAccessRef da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
|
||||||
da->make_dir_recursive(EditorSettings::get_singleton()->get_cache_dir());
|
da->make_dir_recursive(EditorPaths::get_singleton()->get_cache_dir());
|
||||||
|
|
||||||
String tmppath = EditorSettings::get_singleton()->get_cache_dir().plus_file("packtmp");
|
String tmppath = EditorPaths::get_singleton()->get_cache_dir().plus_file("packtmp");
|
||||||
FileAccess *ftmp = FileAccess::open(tmppath, FileAccess::WRITE);
|
FileAccess *ftmp = FileAccess::open(tmppath, FileAccess::WRITE);
|
||||||
ERR_FAIL_COND_V_MSG(!ftmp, ERR_CANT_CREATE, "Cannot create file '" + tmppath + "'.");
|
ERR_FAIL_COND_V_MSG(!ftmp, ERR_CANT_CREATE, "Cannot create file '" + tmppath + "'.");
|
||||||
|
|
||||||
|
@ -1984,7 +1984,7 @@ void EditorExportTextSceneToBinaryPlugin::_export_file(const String &p_path, con
|
||||||
if (!convert) {
|
if (!convert) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
String tmp_path = EditorSettings::get_singleton()->get_cache_dir().plus_file("tmpfile.res");
|
String tmp_path = EditorPaths::get_singleton()->get_cache_dir().plus_file("tmpfile.res");
|
||||||
Error err = ResourceFormatLoaderText::convert_file_to_binary(p_path, tmp_path);
|
Error err = ResourceFormatLoaderText::convert_file_to_binary(p_path, tmp_path);
|
||||||
if (err != OK) {
|
if (err != OK) {
|
||||||
DirAccess::remove_file_or_error(tmp_path);
|
DirAccess::remove_file_or_error(tmp_path);
|
||||||
|
|
|
@ -80,6 +80,7 @@
|
||||||
#include "editor/editor_inspector.h"
|
#include "editor/editor_inspector.h"
|
||||||
#include "editor/editor_layouts_dialog.h"
|
#include "editor/editor_layouts_dialog.h"
|
||||||
#include "editor/editor_log.h"
|
#include "editor/editor_log.h"
|
||||||
|
#include "editor/editor_paths.h"
|
||||||
#include "editor/editor_plugin.h"
|
#include "editor/editor_plugin.h"
|
||||||
#include "editor/editor_properties.h"
|
#include "editor/editor_properties.h"
|
||||||
#include "editor/editor_resource_picker.h"
|
#include "editor/editor_resource_picker.h"
|
||||||
|
@ -1457,7 +1458,7 @@ void EditorNode::_save_scene_with_preview(String p_file, int p_idx) {
|
||||||
img->convert(Image::FORMAT_RGB8);
|
img->convert(Image::FORMAT_RGB8);
|
||||||
|
|
||||||
//save thumbnail directly, as thumbnailer may not update due to actual scene not changing md5
|
//save thumbnail directly, as thumbnailer may not update due to actual scene not changing md5
|
||||||
String temp_path = EditorSettings::get_singleton()->get_cache_dir();
|
String temp_path = EditorPaths::get_singleton()->get_cache_dir();
|
||||||
String cache_base = ProjectSettings::get_singleton()->globalize_path(p_file).md5_text();
|
String cache_base = ProjectSettings::get_singleton()->globalize_path(p_file).md5_text();
|
||||||
cache_base = temp_path.plus_file("resthumb-" + cache_base);
|
cache_base = temp_path.plus_file("resthumb-" + cache_base);
|
||||||
|
|
||||||
|
@ -2745,10 +2746,10 @@ void EditorNode::_menu_option_confirm(int p_option, bool p_confirmed) {
|
||||||
settings_config_dialog->popup_edit_settings();
|
settings_config_dialog->popup_edit_settings();
|
||||||
} break;
|
} break;
|
||||||
case SETTINGS_EDITOR_DATA_FOLDER: {
|
case SETTINGS_EDITOR_DATA_FOLDER: {
|
||||||
OS::get_singleton()->shell_open(String("file://") + EditorSettings::get_singleton()->get_data_dir());
|
OS::get_singleton()->shell_open(String("file://") + EditorPaths::get_singleton()->get_data_dir());
|
||||||
} break;
|
} break;
|
||||||
case SETTINGS_EDITOR_CONFIG_FOLDER: {
|
case SETTINGS_EDITOR_CONFIG_FOLDER: {
|
||||||
OS::get_singleton()->shell_open(String("file://") + EditorSettings::get_singleton()->get_settings_dir());
|
OS::get_singleton()->shell_open(String("file://") + EditorPaths::get_singleton()->get_settings_dir());
|
||||||
} break;
|
} break;
|
||||||
case SETTINGS_MANAGE_EXPORT_TEMPLATES: {
|
case SETTINGS_MANAGE_EXPORT_TEMPLATES: {
|
||||||
export_template_manager->popup_manager();
|
export_template_manager->popup_manager();
|
||||||
|
@ -3727,10 +3728,15 @@ bool EditorNode::is_scene_in_use(const String &p_path) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void EditorNode::register_editor_paths(bool p_for_project_manager) {
|
||||||
|
EditorPaths::create(p_for_project_manager);
|
||||||
|
}
|
||||||
|
|
||||||
void EditorNode::register_editor_types() {
|
void EditorNode::register_editor_types() {
|
||||||
ResourceLoader::set_timestamp_on_load(true);
|
ResourceLoader::set_timestamp_on_load(true);
|
||||||
ResourceSaver::set_timestamp_on_save(true);
|
ResourceSaver::set_timestamp_on_save(true);
|
||||||
|
|
||||||
|
ClassDB::register_class<EditorPaths>();
|
||||||
ClassDB::register_class<EditorPlugin>();
|
ClassDB::register_class<EditorPlugin>();
|
||||||
ClassDB::register_class<EditorTranslationParserPlugin>();
|
ClassDB::register_class<EditorTranslationParserPlugin>();
|
||||||
ClassDB::register_class<EditorImportPlugin>();
|
ClassDB::register_class<EditorImportPlugin>();
|
||||||
|
@ -3774,6 +3780,9 @@ void EditorNode::register_editor_types() {
|
||||||
|
|
||||||
void EditorNode::unregister_editor_types() {
|
void EditorNode::unregister_editor_types() {
|
||||||
_init_callbacks.clear();
|
_init_callbacks.clear();
|
||||||
|
if (EditorPaths::get_singleton()) {
|
||||||
|
EditorPaths::free();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void EditorNode::stop_child_process(OS::ProcessID p_pid) {
|
void EditorNode::stop_child_process(OS::ProcessID p_pid) {
|
||||||
|
|
|
@ -798,6 +798,7 @@ public:
|
||||||
|
|
||||||
Error export_preset(const String &p_preset, const String &p_path, bool p_debug, bool p_pack_only);
|
Error export_preset(const String &p_preset, const String &p_path, bool p_debug, bool p_pack_only);
|
||||||
|
|
||||||
|
static void register_editor_paths(bool p_for_project_manager);
|
||||||
static void register_editor_types();
|
static void register_editor_types();
|
||||||
static void unregister_editor_types();
|
static void unregister_editor_types();
|
||||||
|
|
||||||
|
|
156
editor/editor_paths.cpp
Normal file
156
editor/editor_paths.cpp
Normal file
|
@ -0,0 +1,156 @@
|
||||||
|
/*************************************************************************/
|
||||||
|
/* editor_paths.cpp */
|
||||||
|
/*************************************************************************/
|
||||||
|
/* This file is part of: */
|
||||||
|
/* GODOT ENGINE */
|
||||||
|
/* https://godotengine.org */
|
||||||
|
/*************************************************************************/
|
||||||
|
/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
|
||||||
|
/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
|
||||||
|
/* */
|
||||||
|
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||||
|
/* a copy of this software and associated documentation files (the */
|
||||||
|
/* "Software"), to deal in the Software without restriction, including */
|
||||||
|
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||||
|
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||||
|
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||||
|
/* the following conditions: */
|
||||||
|
/* */
|
||||||
|
/* The above copyright notice and this permission notice shall be */
|
||||||
|
/* included in all copies or substantial portions of the Software. */
|
||||||
|
/* */
|
||||||
|
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||||
|
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||||
|
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
|
||||||
|
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||||
|
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||||
|
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||||
|
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||||
|
/*************************************************************************/
|
||||||
|
|
||||||
|
#include "editor_paths.h"
|
||||||
|
#include "core/os/dir_access.h"
|
||||||
|
#include "core/os/os.h"
|
||||||
|
|
||||||
|
EditorPaths *EditorPaths::singleton = nullptr;
|
||||||
|
|
||||||
|
bool EditorPaths::are_paths_valid() const {
|
||||||
|
return paths_valid;
|
||||||
|
}
|
||||||
|
|
||||||
|
String EditorPaths::get_settings_dir() const {
|
||||||
|
return settings_dir;
|
||||||
|
}
|
||||||
|
String EditorPaths::get_data_dir() const {
|
||||||
|
return data_dir;
|
||||||
|
}
|
||||||
|
String EditorPaths::get_config_dir() const {
|
||||||
|
return config_dir;
|
||||||
|
}
|
||||||
|
String EditorPaths::get_cache_dir() const {
|
||||||
|
return cache_dir;
|
||||||
|
}
|
||||||
|
bool EditorPaths::is_self_contained() const {
|
||||||
|
return self_contained;
|
||||||
|
}
|
||||||
|
String EditorPaths::get_self_contained_file() const {
|
||||||
|
return self_contained_file;
|
||||||
|
}
|
||||||
|
|
||||||
|
void EditorPaths::create(bool p_for_project_manager) {
|
||||||
|
ERR_FAIL_COND(singleton != nullptr);
|
||||||
|
memnew(EditorPaths(p_for_project_manager));
|
||||||
|
}
|
||||||
|
void EditorPaths::free() {
|
||||||
|
ERR_FAIL_COND(singleton == nullptr);
|
||||||
|
memdelete(singleton);
|
||||||
|
}
|
||||||
|
|
||||||
|
void EditorPaths::_bind_methods() {
|
||||||
|
ClassDB::bind_method(D_METHOD("get_settings_dir"), &EditorPaths::get_settings_dir);
|
||||||
|
ClassDB::bind_method(D_METHOD("get_data_dir"), &EditorPaths::get_data_dir);
|
||||||
|
ClassDB::bind_method(D_METHOD("get_config_dir"), &EditorPaths::get_config_dir);
|
||||||
|
ClassDB::bind_method(D_METHOD("get_cache_dir"), &EditorPaths::get_cache_dir);
|
||||||
|
ClassDB::bind_method(D_METHOD("is_self_contained"), &EditorPaths::is_self_contained);
|
||||||
|
ClassDB::bind_method(D_METHOD("get_self_contained_file"), &EditorPaths::get_self_contained_file);
|
||||||
|
}
|
||||||
|
|
||||||
|
EditorPaths::EditorPaths(bool p_for_project_mamanger) {
|
||||||
|
singleton = this;
|
||||||
|
|
||||||
|
String exe_path = OS::get_singleton()->get_executable_path().get_base_dir();
|
||||||
|
{
|
||||||
|
DirAccessRef d = DirAccess::create_for_path(exe_path);
|
||||||
|
|
||||||
|
if (d->file_exists(exe_path + "/._sc_")) {
|
||||||
|
self_contained = true;
|
||||||
|
self_contained_file = exe_path + "/._sc_";
|
||||||
|
} else if (d->file_exists(exe_path + "/_sc_")) {
|
||||||
|
self_contained = true;
|
||||||
|
self_contained_file = exe_path + "/_sc_";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
String data_path;
|
||||||
|
String config_path;
|
||||||
|
String cache_path;
|
||||||
|
|
||||||
|
if (self_contained) {
|
||||||
|
// editor is self contained, all in same folder
|
||||||
|
data_path = exe_path;
|
||||||
|
data_dir = data_path.plus_file("editor_data");
|
||||||
|
config_path = exe_path;
|
||||||
|
config_dir = data_dir;
|
||||||
|
cache_path = exe_path;
|
||||||
|
cache_dir = data_dir.plus_file("cache");
|
||||||
|
} else {
|
||||||
|
// Typically XDG_DATA_HOME or %APPDATA%
|
||||||
|
data_path = OS::get_singleton()->get_data_path();
|
||||||
|
data_dir = data_path.plus_file(OS::get_singleton()->get_godot_dir_name());
|
||||||
|
// Can be different from data_path e.g. on Linux or macOS
|
||||||
|
config_path = OS::get_singleton()->get_config_path();
|
||||||
|
config_dir = config_path.plus_file(OS::get_singleton()->get_godot_dir_name());
|
||||||
|
// Can be different from above paths, otherwise a subfolder of data_dir
|
||||||
|
cache_path = OS::get_singleton()->get_cache_path();
|
||||||
|
if (cache_path == data_path) {
|
||||||
|
cache_dir = data_dir.plus_file("cache");
|
||||||
|
} else {
|
||||||
|
cache_dir = cache_path.plus_file(OS::get_singleton()->get_godot_dir_name());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
paths_valid = (data_path != "" && config_path != "" && cache_path != "");
|
||||||
|
|
||||||
|
if (paths_valid) {
|
||||||
|
DirAccessRef dir = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
|
||||||
|
if (dir->change_dir(data_dir) != OK) {
|
||||||
|
dir->make_dir_recursive(data_dir);
|
||||||
|
if (dir->change_dir(data_dir) != OK) {
|
||||||
|
ERR_PRINT("Cannot create data directory!");
|
||||||
|
paths_valid = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Validate/create cache dir
|
||||||
|
|
||||||
|
if (dir->change_dir(EditorPaths::get_singleton()->get_cache_dir()) != OK) {
|
||||||
|
dir->make_dir_recursive(cache_dir);
|
||||||
|
if (dir->change_dir(cache_dir) != OK) {
|
||||||
|
ERR_PRINT("Cannot create cache directory!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (p_for_project_mamanger) {
|
||||||
|
Engine::get_singleton()->set_shader_cache_path(get_data_dir());
|
||||||
|
} else {
|
||||||
|
DirAccessRef dir2 = DirAccess::open("res://");
|
||||||
|
if (dir2->change_dir(".godot") != OK) { //ensure the .godot subdir exists
|
||||||
|
if (dir2->make_dir(".godot") != OK) {
|
||||||
|
ERR_PRINT("Cannot create res://.godot directory!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Engine::get_singleton()->set_shader_cache_path("res://.godot");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
72
editor/editor_paths.h
Normal file
72
editor/editor_paths.h
Normal file
|
@ -0,0 +1,72 @@
|
||||||
|
/*************************************************************************/
|
||||||
|
/* editor_paths.h */
|
||||||
|
/*************************************************************************/
|
||||||
|
/* This file is part of: */
|
||||||
|
/* GODOT ENGINE */
|
||||||
|
/* https://godotengine.org */
|
||||||
|
/*************************************************************************/
|
||||||
|
/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
|
||||||
|
/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
|
||||||
|
/* */
|
||||||
|
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||||
|
/* a copy of this software and associated documentation files (the */
|
||||||
|
/* "Software"), to deal in the Software without restriction, including */
|
||||||
|
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||||
|
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||||
|
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||||
|
/* the following conditions: */
|
||||||
|
/* */
|
||||||
|
/* The above copyright notice and this permission notice shall be */
|
||||||
|
/* included in all copies or substantial portions of the Software. */
|
||||||
|
/* */
|
||||||
|
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||||
|
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||||
|
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
|
||||||
|
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||||
|
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||||
|
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||||
|
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||||
|
/*************************************************************************/
|
||||||
|
|
||||||
|
#ifndef EDITORPATHS_H
|
||||||
|
#define EDITORPATHS_H
|
||||||
|
|
||||||
|
#include "core/config/engine.h"
|
||||||
|
|
||||||
|
class EditorPaths : public Object {
|
||||||
|
GDCLASS(EditorPaths, Object)
|
||||||
|
|
||||||
|
bool paths_valid = false;
|
||||||
|
String settings_dir;
|
||||||
|
String data_dir; //editor data dir
|
||||||
|
String config_dir; //editor config dir
|
||||||
|
String cache_dir; //editor cache dir
|
||||||
|
bool self_contained = false; //true if running self contained
|
||||||
|
String self_contained_file; //self contained file with configuration
|
||||||
|
|
||||||
|
static EditorPaths *singleton;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
static void _bind_methods();
|
||||||
|
|
||||||
|
public:
|
||||||
|
bool are_paths_valid() const;
|
||||||
|
|
||||||
|
String get_settings_dir() const;
|
||||||
|
String get_data_dir() const;
|
||||||
|
String get_config_dir() const;
|
||||||
|
String get_cache_dir() const;
|
||||||
|
bool is_self_contained() const;
|
||||||
|
String get_self_contained_file() const;
|
||||||
|
|
||||||
|
static EditorPaths *get_singleton() {
|
||||||
|
return singleton;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void create(bool p_for_project_manager);
|
||||||
|
static void free();
|
||||||
|
|
||||||
|
EditorPaths(bool p_for_project_mamanger = false);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // EDITORPATHS_H
|
|
@ -32,6 +32,7 @@
|
||||||
|
|
||||||
#include "editor/editor_export.h"
|
#include "editor/editor_export.h"
|
||||||
#include "editor/editor_node.h"
|
#include "editor/editor_node.h"
|
||||||
|
#include "editor/editor_paths.h"
|
||||||
#include "editor/editor_settings.h"
|
#include "editor/editor_settings.h"
|
||||||
#include "editor/filesystem_dock.h"
|
#include "editor/filesystem_dock.h"
|
||||||
#include "editor/project_settings_editor.h"
|
#include "editor/project_settings_editor.h"
|
||||||
|
@ -257,6 +258,9 @@ EditorSelection *EditorInterface::get_selection() {
|
||||||
Ref<EditorSettings> EditorInterface::get_editor_settings() {
|
Ref<EditorSettings> EditorInterface::get_editor_settings() {
|
||||||
return EditorSettings::get_singleton();
|
return EditorSettings::get_singleton();
|
||||||
}
|
}
|
||||||
|
EditorPaths *EditorInterface::get_editor_paths() {
|
||||||
|
return EditorPaths::get_singleton();
|
||||||
|
}
|
||||||
|
|
||||||
EditorResourcePreview *EditorInterface::get_resource_previewer() {
|
EditorResourcePreview *EditorInterface::get_resource_previewer() {
|
||||||
return EditorResourcePreview::get_singleton();
|
return EditorResourcePreview::get_singleton();
|
||||||
|
@ -335,6 +339,7 @@ void EditorInterface::_bind_methods() {
|
||||||
ClassDB::bind_method(D_METHOD("get_selected_path"), &EditorInterface::get_selected_path);
|
ClassDB::bind_method(D_METHOD("get_selected_path"), &EditorInterface::get_selected_path);
|
||||||
ClassDB::bind_method(D_METHOD("get_current_path"), &EditorInterface::get_current_path);
|
ClassDB::bind_method(D_METHOD("get_current_path"), &EditorInterface::get_current_path);
|
||||||
ClassDB::bind_method(D_METHOD("get_file_system_dock"), &EditorInterface::get_file_system_dock);
|
ClassDB::bind_method(D_METHOD("get_file_system_dock"), &EditorInterface::get_file_system_dock);
|
||||||
|
ClassDB::bind_method(D_METHOD("get_editor_paths"), &EditorInterface::get_editor_paths);
|
||||||
|
|
||||||
ClassDB::bind_method(D_METHOD("set_plugin_enabled", "plugin", "enabled"), &EditorInterface::set_plugin_enabled);
|
ClassDB::bind_method(D_METHOD("set_plugin_enabled", "plugin", "enabled"), &EditorInterface::set_plugin_enabled);
|
||||||
ClassDB::bind_method(D_METHOD("is_plugin_enabled", "plugin"), &EditorInterface::is_plugin_enabled);
|
ClassDB::bind_method(D_METHOD("is_plugin_enabled", "plugin"), &EditorInterface::is_plugin_enabled);
|
||||||
|
|
|
@ -54,6 +54,7 @@ class EditorNode3DGizmoPlugin;
|
||||||
class EditorResourcePreview;
|
class EditorResourcePreview;
|
||||||
class EditorFileSystem;
|
class EditorFileSystem;
|
||||||
class EditorToolAddons;
|
class EditorToolAddons;
|
||||||
|
class EditorPaths;
|
||||||
class FileSystemDock;
|
class FileSystemDock;
|
||||||
class ScriptEditor;
|
class ScriptEditor;
|
||||||
|
|
||||||
|
@ -95,6 +96,7 @@ public:
|
||||||
EditorSelection *get_selection();
|
EditorSelection *get_selection();
|
||||||
//EditorImportExport *get_import_export();
|
//EditorImportExport *get_import_export();
|
||||||
Ref<EditorSettings> get_editor_settings();
|
Ref<EditorSettings> get_editor_settings();
|
||||||
|
EditorPaths *get_editor_paths();
|
||||||
EditorResourcePreview *get_resource_previewer();
|
EditorResourcePreview *get_resource_previewer();
|
||||||
EditorFileSystem *get_resource_file_system();
|
EditorFileSystem *get_resource_file_system();
|
||||||
|
|
||||||
|
|
|
@ -241,7 +241,7 @@ void EditorResourcePreview::_thread() {
|
||||||
_preview_ready(item.path + ":" + itos(item.resource->hash_edited_version()), texture, small_texture, item.id, item.function, item.userdata);
|
_preview_ready(item.path + ":" + itos(item.resource->hash_edited_version()), texture, small_texture, item.id, item.function, item.userdata);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
String temp_path = EditorSettings::get_singleton()->get_cache_dir();
|
String temp_path = EditorPaths::get_singleton()->get_cache_dir();
|
||||||
String cache_base = ProjectSettings::get_singleton()->globalize_path(item.path).md5_text();
|
String cache_base = ProjectSettings::get_singleton()->globalize_path(item.path).md5_text();
|
||||||
cache_base = temp_path.plus_file("resthumb-" + cache_base);
|
cache_base = temp_path.plus_file("resthumb-" + cache_base);
|
||||||
|
|
||||||
|
|
|
@ -902,67 +902,26 @@ void EditorSettings::create() {
|
||||||
return; //pointless
|
return; //pointless
|
||||||
}
|
}
|
||||||
|
|
||||||
DirAccess *dir = nullptr;
|
|
||||||
|
|
||||||
String data_path;
|
|
||||||
String data_dir;
|
|
||||||
String config_path;
|
|
||||||
String config_dir;
|
|
||||||
String cache_path;
|
|
||||||
String cache_dir;
|
|
||||||
|
|
||||||
Ref<ConfigFile> extra_config = memnew(ConfigFile);
|
Ref<ConfigFile> extra_config = memnew(ConfigFile);
|
||||||
|
|
||||||
String exe_path = OS::get_singleton()->get_executable_path().get_base_dir();
|
if (EditorPaths::get_singleton()->is_self_contained()) {
|
||||||
DirAccess *d = DirAccess::create_for_path(exe_path);
|
Error err = extra_config->load(EditorPaths::get_singleton()->get_self_contained_file());
|
||||||
bool self_contained = false;
|
|
||||||
|
|
||||||
if (d->file_exists(exe_path + "/._sc_")) {
|
|
||||||
self_contained = true;
|
|
||||||
Error err = extra_config->load(exe_path + "/._sc_");
|
|
||||||
if (err != OK) {
|
if (err != OK) {
|
||||||
ERR_PRINT("Can't load config from path '" + exe_path + "/._sc_'.");
|
ERR_PRINT("Can't load extra config from path :" + EditorPaths::get_singleton()->get_self_contained_file());
|
||||||
}
|
|
||||||
} else if (d->file_exists(exe_path + "/_sc_")) {
|
|
||||||
self_contained = true;
|
|
||||||
Error err = extra_config->load(exe_path + "/_sc_");
|
|
||||||
if (err != OK) {
|
|
||||||
ERR_PRINT("Can't load config from path '" + exe_path + "/_sc_'.");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
memdelete(d);
|
|
||||||
|
|
||||||
if (self_contained) {
|
DirAccess *dir = nullptr;
|
||||||
// editor is self contained, all in same folder
|
|
||||||
data_path = exe_path;
|
|
||||||
data_dir = data_path.plus_file("editor_data");
|
|
||||||
config_path = exe_path;
|
|
||||||
config_dir = data_dir;
|
|
||||||
cache_path = exe_path;
|
|
||||||
cache_dir = data_dir.plus_file("cache");
|
|
||||||
} else {
|
|
||||||
// Typically XDG_DATA_HOME or %APPDATA%
|
|
||||||
data_path = OS::get_singleton()->get_data_path();
|
|
||||||
data_dir = data_path.plus_file(OS::get_singleton()->get_godot_dir_name());
|
|
||||||
// Can be different from data_path e.g. on Linux or macOS
|
|
||||||
config_path = OS::get_singleton()->get_config_path();
|
|
||||||
config_dir = config_path.plus_file(OS::get_singleton()->get_godot_dir_name());
|
|
||||||
// Can be different from above paths, otherwise a subfolder of data_dir
|
|
||||||
cache_path = OS::get_singleton()->get_cache_path();
|
|
||||||
if (cache_path == data_path) {
|
|
||||||
cache_dir = data_dir.plus_file("cache");
|
|
||||||
} else {
|
|
||||||
cache_dir = cache_path.plus_file(OS::get_singleton()->get_godot_dir_name());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ClassDB::register_class<EditorSettings>(); //otherwise it can't be unserialized
|
ClassDB::register_class<EditorSettings>(); //otherwise it can't be unserialized
|
||||||
|
|
||||||
String config_file_path;
|
String config_file_path;
|
||||||
|
|
||||||
if (data_path != "" && config_path != "" && cache_path != "") {
|
if (EditorPaths::get_singleton()->are_paths_valid()) {
|
||||||
// Validate/create data dir and subdirectories
|
// Validate/create data dir and subdirectories
|
||||||
|
|
||||||
|
String data_dir = EditorPaths::get_singleton()->get_data_dir();
|
||||||
|
|
||||||
dir = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
|
dir = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
|
||||||
if (dir->change_dir(data_dir) != OK) {
|
if (dir->change_dir(data_dir) != OK) {
|
||||||
dir->make_dir_recursive(data_dir);
|
dir->make_dir_recursive(data_dir);
|
||||||
|
@ -979,22 +938,11 @@ void EditorSettings::create() {
|
||||||
dir->change_dir("..");
|
dir->change_dir("..");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Validate/create cache dir
|
|
||||||
|
|
||||||
if (dir->change_dir(cache_dir) != OK) {
|
|
||||||
dir->make_dir_recursive(cache_dir);
|
|
||||||
if (dir->change_dir(cache_dir) != OK) {
|
|
||||||
ERR_PRINT("Cannot create cache directory!");
|
|
||||||
memdelete(dir);
|
|
||||||
goto fail;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Validate/create config dir and subdirectories
|
// Validate/create config dir and subdirectories
|
||||||
|
|
||||||
if (dir->change_dir(config_dir) != OK) {
|
if (dir->change_dir(EditorPaths::get_singleton()->get_config_dir()) != OK) {
|
||||||
dir->make_dir_recursive(config_dir);
|
dir->make_dir_recursive(EditorPaths::get_singleton()->get_config_dir());
|
||||||
if (dir->change_dir(config_dir) != OK) {
|
if (dir->change_dir(EditorPaths::get_singleton()->get_config_dir()) != OK) {
|
||||||
ERR_PRINT("Cannot create config directory!");
|
ERR_PRINT("Cannot create config directory!");
|
||||||
memdelete(dir);
|
memdelete(dir);
|
||||||
goto fail;
|
goto fail;
|
||||||
|
@ -1035,7 +983,7 @@ void EditorSettings::create() {
|
||||||
// Validate editor config file
|
// Validate editor config file
|
||||||
|
|
||||||
String config_file_name = "editor_settings-" + itos(VERSION_MAJOR) + ".tres";
|
String config_file_name = "editor_settings-" + itos(VERSION_MAJOR) + ".tres";
|
||||||
config_file_path = config_dir.plus_file(config_file_name);
|
config_file_path = EditorPaths::get_singleton()->get_config_dir().plus_file(config_file_name);
|
||||||
if (!dir->file_exists(config_file_name)) {
|
if (!dir->file_exists(config_file_name)) {
|
||||||
memdelete(dir);
|
memdelete(dir);
|
||||||
goto fail;
|
goto fail;
|
||||||
|
@ -1052,9 +1000,6 @@ void EditorSettings::create() {
|
||||||
|
|
||||||
singleton->save_changed_setting = true;
|
singleton->save_changed_setting = true;
|
||||||
singleton->config_file_path = config_file_path;
|
singleton->config_file_path = config_file_path;
|
||||||
singleton->settings_dir = config_dir;
|
|
||||||
singleton->data_dir = data_dir;
|
|
||||||
singleton->cache_dir = cache_dir;
|
|
||||||
|
|
||||||
print_verbose("EditorSettings: Load OK!");
|
print_verbose("EditorSettings: Load OK!");
|
||||||
|
|
||||||
|
@ -1069,6 +1014,8 @@ void EditorSettings::create() {
|
||||||
fail:
|
fail:
|
||||||
|
|
||||||
// patch init projects
|
// patch init projects
|
||||||
|
String exe_path = OS::get_singleton()->get_executable_path().get_base_dir();
|
||||||
|
|
||||||
if (extra_config->has_section("init_projects")) {
|
if (extra_config->has_section("init_projects")) {
|
||||||
Vector<String> list = extra_config->get_value("init_projects", "list");
|
Vector<String> list = extra_config->get_value("init_projects", "list");
|
||||||
for (int i = 0; i < list.size(); i++) {
|
for (int i = 0; i < list.size(); i++) {
|
||||||
|
@ -1080,9 +1027,6 @@ fail:
|
||||||
singleton = Ref<EditorSettings>(memnew(EditorSettings));
|
singleton = Ref<EditorSettings>(memnew(EditorSettings));
|
||||||
singleton->save_changed_setting = true;
|
singleton->save_changed_setting = true;
|
||||||
singleton->config_file_path = config_file_path;
|
singleton->config_file_path = config_file_path;
|
||||||
singleton->settings_dir = config_dir;
|
|
||||||
singleton->data_dir = data_dir;
|
|
||||||
singleton->cache_dir = cache_dir;
|
|
||||||
singleton->_load_defaults(extra_config);
|
singleton->_load_defaults(extra_config);
|
||||||
singleton->setup_language();
|
singleton->setup_language();
|
||||||
singleton->setup_network();
|
singleton->setup_network();
|
||||||
|
@ -1312,30 +1256,22 @@ void EditorSettings::add_property_hint(const PropertyInfo &p_hint) {
|
||||||
|
|
||||||
// Data directories
|
// Data directories
|
||||||
|
|
||||||
String EditorSettings::get_data_dir() const {
|
|
||||||
return data_dir;
|
|
||||||
}
|
|
||||||
|
|
||||||
String EditorSettings::get_templates_dir() const {
|
String EditorSettings::get_templates_dir() const {
|
||||||
return get_data_dir().plus_file("templates");
|
return EditorPaths::get_singleton()->get_data_dir().plus_file("templates");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Config directories
|
// Config directories
|
||||||
|
|
||||||
String EditorSettings::get_settings_dir() const {
|
|
||||||
return settings_dir;
|
|
||||||
}
|
|
||||||
|
|
||||||
String EditorSettings::get_project_settings_dir() const {
|
String EditorSettings::get_project_settings_dir() const {
|
||||||
return EditorSettings::PROJECT_EDITOR_SETTINGS_PATH;
|
return EditorSettings::PROJECT_EDITOR_SETTINGS_PATH;
|
||||||
}
|
}
|
||||||
|
|
||||||
String EditorSettings::get_text_editor_themes_dir() const {
|
String EditorSettings::get_text_editor_themes_dir() const {
|
||||||
return get_settings_dir().plus_file("text_editor_themes");
|
return EditorPaths::get_singleton()->get_settings_dir().plus_file("text_editor_themes");
|
||||||
}
|
}
|
||||||
|
|
||||||
String EditorSettings::get_script_templates_dir() const {
|
String EditorSettings::get_script_templates_dir() const {
|
||||||
return get_settings_dir().plus_file("script_templates");
|
return EditorPaths::get_singleton()->get_settings_dir().plus_file("script_templates");
|
||||||
}
|
}
|
||||||
|
|
||||||
String EditorSettings::get_project_script_templates_dir() const {
|
String EditorSettings::get_project_script_templates_dir() const {
|
||||||
|
@ -1344,12 +1280,8 @@ String EditorSettings::get_project_script_templates_dir() const {
|
||||||
|
|
||||||
// Cache directory
|
// Cache directory
|
||||||
|
|
||||||
String EditorSettings::get_cache_dir() const {
|
|
||||||
return cache_dir;
|
|
||||||
}
|
|
||||||
|
|
||||||
String EditorSettings::get_feature_profiles_dir() const {
|
String EditorSettings::get_feature_profiles_dir() const {
|
||||||
return get_settings_dir().plus_file("feature_profiles");
|
return EditorPaths::get_singleton()->get_settings_dir().plus_file("feature_profiles");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Metadata
|
// Metadata
|
||||||
|
@ -1576,7 +1508,7 @@ Vector<String> EditorSettings::get_script_templates(const String &p_extension, c
|
||||||
}
|
}
|
||||||
|
|
||||||
String EditorSettings::get_editor_layouts_config() const {
|
String EditorSettings::get_editor_layouts_config() const {
|
||||||
return get_settings_dir().plus_file("editor_layouts.cfg");
|
return EditorPaths::get_singleton()->get_settings_dir().plus_file("editor_layouts.cfg");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Shortcuts
|
// Shortcuts
|
||||||
|
@ -1778,7 +1710,6 @@ void EditorSettings::_bind_methods() {
|
||||||
ClassDB::bind_method(D_METHOD("property_get_revert", "name"), &EditorSettings::property_get_revert);
|
ClassDB::bind_method(D_METHOD("property_get_revert", "name"), &EditorSettings::property_get_revert);
|
||||||
ClassDB::bind_method(D_METHOD("add_property_info", "info"), &EditorSettings::_add_property_info_bind);
|
ClassDB::bind_method(D_METHOD("add_property_info", "info"), &EditorSettings::_add_property_info_bind);
|
||||||
|
|
||||||
ClassDB::bind_method(D_METHOD("get_settings_dir"), &EditorSettings::get_settings_dir);
|
|
||||||
ClassDB::bind_method(D_METHOD("get_project_settings_dir"), &EditorSettings::get_project_settings_dir);
|
ClassDB::bind_method(D_METHOD("get_project_settings_dir"), &EditorSettings::get_project_settings_dir);
|
||||||
|
|
||||||
ClassDB::bind_method(D_METHOD("set_project_metadata", "section", "key", "data"), &EditorSettings::set_project_metadata);
|
ClassDB::bind_method(D_METHOD("set_project_metadata", "section", "key", "data"), &EditorSettings::set_project_metadata);
|
||||||
|
|
|
@ -36,6 +36,7 @@
|
||||||
#include "core/object/class_db.h"
|
#include "core/object/class_db.h"
|
||||||
#include "core/os/thread_safe.h"
|
#include "core/os/thread_safe.h"
|
||||||
#include "core/string/translation.h"
|
#include "core/string/translation.h"
|
||||||
|
#include "editor/editor_paths.h"
|
||||||
#include "scene/gui/shortcut.h"
|
#include "scene/gui/shortcut.h"
|
||||||
|
|
||||||
class EditorPlugin;
|
class EditorPlugin;
|
||||||
|
@ -87,12 +88,7 @@ private:
|
||||||
mutable Map<String, Ref<Shortcut>> shortcuts;
|
mutable Map<String, Ref<Shortcut>> shortcuts;
|
||||||
Map<String, List<Ref<InputEvent>>> builtin_action_overrides;
|
Map<String, List<Ref<InputEvent>>> builtin_action_overrides;
|
||||||
|
|
||||||
String resource_path;
|
|
||||||
String settings_dir;
|
|
||||||
String data_dir;
|
|
||||||
String cache_dir;
|
|
||||||
String config_file_path;
|
String config_file_path;
|
||||||
String project_config_dir;
|
|
||||||
|
|
||||||
Vector<String> favorites;
|
Vector<String> favorites;
|
||||||
Vector<String> recent_dirs;
|
Vector<String> recent_dirs;
|
||||||
|
@ -153,12 +149,10 @@ public:
|
||||||
|
|
||||||
String get_data_dir() const;
|
String get_data_dir() const;
|
||||||
String get_templates_dir() const;
|
String get_templates_dir() const;
|
||||||
String get_settings_dir() const;
|
|
||||||
String get_project_settings_dir() const;
|
String get_project_settings_dir() const;
|
||||||
String get_text_editor_themes_dir() const;
|
String get_text_editor_themes_dir() const;
|
||||||
String get_script_templates_dir() const;
|
String get_script_templates_dir() const;
|
||||||
String get_project_script_templates_dir() const;
|
String get_project_script_templates_dir() const;
|
||||||
String get_cache_dir() const;
|
|
||||||
String get_feature_profiles_dir() const;
|
String get_feature_profiles_dir() const;
|
||||||
|
|
||||||
void set_project_metadata(const String &p_section, const String &p_key, Variant p_data);
|
void set_project_metadata(const String &p_section, const String &p_key, Variant p_data);
|
||||||
|
|
|
@ -444,7 +444,7 @@ void ExportTemplateManager::_begin_template_download(const String &p_url) {
|
||||||
}
|
}
|
||||||
|
|
||||||
download_data.clear();
|
download_data.clear();
|
||||||
download_templates->set_download_file(EditorSettings::get_singleton()->get_cache_dir().plus_file("tmp_templates.tpz"));
|
download_templates->set_download_file(EditorPaths::get_singleton()->get_cache_dir().plus_file("tmp_templates.tpz"));
|
||||||
download_templates->set_use_threads(true);
|
download_templates->set_use_threads(true);
|
||||||
|
|
||||||
Error err = download_templates->request(p_url);
|
Error err = download_templates->request(p_url);
|
||||||
|
|
|
@ -464,7 +464,7 @@ void EditorAssetLibraryItemDownload::_make_request() {
|
||||||
retry->hide();
|
retry->hide();
|
||||||
|
|
||||||
download->cancel_request();
|
download->cancel_request();
|
||||||
download->set_download_file(EditorSettings::get_singleton()->get_cache_dir().plus_file("tmp_asset_" + itos(asset_id)) + ".zip");
|
download->set_download_file(EditorPaths::get_singleton()->get_cache_dir().plus_file("tmp_asset_" + itos(asset_id)) + ".zip");
|
||||||
|
|
||||||
Error err = download->request(host);
|
Error err = download->request(host);
|
||||||
if (err != OK) {
|
if (err != OK) {
|
||||||
|
@ -702,7 +702,7 @@ void EditorAssetLibrary::_image_update(bool use_cache, bool final, const PackedB
|
||||||
PackedByteArray image_data = p_data;
|
PackedByteArray image_data = p_data;
|
||||||
|
|
||||||
if (use_cache) {
|
if (use_cache) {
|
||||||
String cache_filename_base = EditorSettings::get_singleton()->get_cache_dir().plus_file("assetimage_" + image_queue[p_queue_id].image_url.md5_text());
|
String cache_filename_base = EditorPaths::get_singleton()->get_cache_dir().plus_file("assetimage_" + image_queue[p_queue_id].image_url.md5_text());
|
||||||
|
|
||||||
FileAccess *file = FileAccess::open(cache_filename_base + ".data", FileAccess::READ);
|
FileAccess *file = FileAccess::open(cache_filename_base + ".data", FileAccess::READ);
|
||||||
|
|
||||||
|
@ -781,7 +781,7 @@ void EditorAssetLibrary::_image_request_completed(int p_status, int p_code, cons
|
||||||
if (p_code != HTTPClient::RESPONSE_NOT_MODIFIED) {
|
if (p_code != HTTPClient::RESPONSE_NOT_MODIFIED) {
|
||||||
for (int i = 0; i < headers.size(); i++) {
|
for (int i = 0; i < headers.size(); i++) {
|
||||||
if (headers[i].findn("ETag:") == 0) { // Save etag
|
if (headers[i].findn("ETag:") == 0) { // Save etag
|
||||||
String cache_filename_base = EditorSettings::get_singleton()->get_cache_dir().plus_file("assetimage_" + image_queue[p_queue_id].image_url.md5_text());
|
String cache_filename_base = EditorPaths::get_singleton()->get_cache_dir().plus_file("assetimage_" + image_queue[p_queue_id].image_url.md5_text());
|
||||||
String new_etag = headers[i].substr(headers[i].find(":") + 1, headers[i].length()).strip_edges();
|
String new_etag = headers[i].substr(headers[i].find(":") + 1, headers[i].length()).strip_edges();
|
||||||
FileAccess *file;
|
FileAccess *file;
|
||||||
|
|
||||||
|
@ -829,7 +829,7 @@ void EditorAssetLibrary::_update_image_queue() {
|
||||||
List<int> to_delete;
|
List<int> to_delete;
|
||||||
for (Map<int, ImageQueue>::Element *E = image_queue.front(); E; E = E->next()) {
|
for (Map<int, ImageQueue>::Element *E = image_queue.front(); E; E = E->next()) {
|
||||||
if (!E->get().active && current_images < max_images) {
|
if (!E->get().active && current_images < max_images) {
|
||||||
String cache_filename_base = EditorSettings::get_singleton()->get_cache_dir().plus_file("assetimage_" + E->get().image_url.md5_text());
|
String cache_filename_base = EditorPaths::get_singleton()->get_cache_dir().plus_file("assetimage_" + E->get().image_url.md5_text());
|
||||||
Vector<String> headers;
|
Vector<String> headers;
|
||||||
|
|
||||||
if (FileAccess::exists(cache_filename_base + ".etag") && FileAccess::exists(cache_filename_base + ".data")) {
|
if (FileAccess::exists(cache_filename_base + ".etag") && FileAccess::exists(cache_filename_base + ".data")) {
|
||||||
|
|
|
@ -265,7 +265,7 @@ Ref<Texture2D> EditorPackedScenePreviewPlugin::generate(const RES &p_from, const
|
||||||
}
|
}
|
||||||
|
|
||||||
Ref<Texture2D> EditorPackedScenePreviewPlugin::generate_from_path(const String &p_path, const Size2 &p_size) const {
|
Ref<Texture2D> EditorPackedScenePreviewPlugin::generate_from_path(const String &p_path, const Size2 &p_size) const {
|
||||||
String temp_path = EditorSettings::get_singleton()->get_cache_dir();
|
String temp_path = EditorPaths::get_singleton()->get_cache_dir();
|
||||||
String cache_base = ProjectSettings::get_singleton()->globalize_path(p_path).md5_text();
|
String cache_base = ProjectSettings::get_singleton()->globalize_path(p_path).md5_text();
|
||||||
cache_base = temp_path.plus_file("resthumb-" + cache_base);
|
cache_base = temp_path.plus_file("resthumb-" + cache_base);
|
||||||
|
|
||||||
|
|
|
@ -1445,6 +1445,12 @@ Error Main::setup2(Thread::ID p_main_tid_override) {
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef TOOLS_ENABLED
|
||||||
|
if (editor || project_manager) {
|
||||||
|
EditorNode::register_editor_paths(project_manager);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
/* Determine text driver */
|
/* Determine text driver */
|
||||||
|
|
||||||
if (text_driver == "") {
|
if (text_driver == "") {
|
||||||
|
|
|
@ -179,11 +179,18 @@ static Vector<uint8_t> _compile_shader_glsl(RenderingDevice::ShaderStage p_stage
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static String _get_cache_key_function_glsl(const RenderingDevice::Capabilities *p_capabilities) {
|
||||||
|
String version;
|
||||||
|
version = "SpirVGen=" + itos(glslang::GetSpirvGeneratorVersion()) + ", major=" + itos(p_capabilities->version_major) + ", minor=" + itos(p_capabilities->version_minor) + " , subgroup_size=" + itos(p_capabilities->subgroup_operations) + " , subgroup_ops=" + itos(p_capabilities->subgroup_operations) + " , subgroup_in_shaders=" + itos(p_capabilities->subgroup_in_shaders);
|
||||||
|
return version;
|
||||||
|
}
|
||||||
|
|
||||||
void preregister_glslang_types() {
|
void preregister_glslang_types() {
|
||||||
// initialize in case it's not initialized. This is done once per thread
|
// initialize in case it's not initialized. This is done once per thread
|
||||||
// and it's safe to call multiple times
|
// and it's safe to call multiple times
|
||||||
glslang::InitializeProcess();
|
glslang::InitializeProcess();
|
||||||
RenderingDevice::shader_set_compile_function(_compile_shader_glsl);
|
RenderingDevice::shader_set_compile_function(_compile_shader_glsl);
|
||||||
|
RenderingDevice::shader_set_get_cache_key_function(_get_cache_key_function_glsl);
|
||||||
}
|
}
|
||||||
|
|
||||||
void register_glslang_types() {
|
void register_glslang_types() {
|
||||||
|
|
|
@ -63,8 +63,8 @@ String _get_expected_build_config() {
|
||||||
|
|
||||||
String _get_mono_user_dir() {
|
String _get_mono_user_dir() {
|
||||||
#ifdef TOOLS_ENABLED
|
#ifdef TOOLS_ENABLED
|
||||||
if (EditorSettings::get_singleton()) {
|
if (EditorPaths::get_singleton()) {
|
||||||
return EditorSettings::get_singleton()->get_data_dir().plus_file("mono");
|
return EditorPaths::get_singleton()->get_data_dir().plus_file("mono");
|
||||||
} else {
|
} else {
|
||||||
String settings_path;
|
String settings_path;
|
||||||
|
|
||||||
|
|
|
@ -1793,7 +1793,7 @@ public:
|
||||||
p_debug_flags |= DEBUG_FLAG_REMOTE_DEBUG_LOCALHOST;
|
p_debug_flags |= DEBUG_FLAG_REMOTE_DEBUG_LOCALHOST;
|
||||||
}
|
}
|
||||||
|
|
||||||
String tmp_export_path = EditorSettings::get_singleton()->get_cache_dir().plus_file("tmpexport." + uitos(OS::get_singleton()->get_unix_time()) + ".apk");
|
String tmp_export_path = EditorPaths::get_singleton()->get_cache_dir().plus_file("tmpexport." + uitos(OS::get_singleton()->get_unix_time()) + ".apk");
|
||||||
|
|
||||||
#define CLEANUP_AND_RETURN(m_err) \
|
#define CLEANUP_AND_RETURN(m_err) \
|
||||||
{ \
|
{ \
|
||||||
|
@ -2651,7 +2651,7 @@ public:
|
||||||
FileAccess *dst_f = nullptr;
|
FileAccess *dst_f = nullptr;
|
||||||
io2.opaque = &dst_f;
|
io2.opaque = &dst_f;
|
||||||
|
|
||||||
String tmp_unaligned_path = EditorSettings::get_singleton()->get_cache_dir().plus_file("tmpexport-unaligned." + uitos(OS::get_singleton()->get_unix_time()) + ".apk");
|
String tmp_unaligned_path = EditorPaths::get_singleton()->get_cache_dir().plus_file("tmpexport-unaligned." + uitos(OS::get_singleton()->get_unix_time()) + ".apk");
|
||||||
|
|
||||||
#define CLEANUP_AND_RETURN(m_err) \
|
#define CLEANUP_AND_RETURN(m_err) \
|
||||||
{ \
|
{ \
|
||||||
|
|
|
@ -63,7 +63,7 @@ private:
|
||||||
}
|
}
|
||||||
|
|
||||||
void _set_internal_certs(Ref<Crypto> p_crypto) {
|
void _set_internal_certs(Ref<Crypto> p_crypto) {
|
||||||
const String cache_path = EditorSettings::get_singleton()->get_cache_dir();
|
const String cache_path = EditorPaths::get_singleton()->get_cache_dir();
|
||||||
const String key_path = cache_path.plus_file("html5_server.key");
|
const String key_path = cache_path.plus_file("html5_server.key");
|
||||||
const String crt_path = cache_path.plus_file("html5_server.crt");
|
const String crt_path = cache_path.plus_file("html5_server.crt");
|
||||||
bool regen = !FileAccess::exists(key_path) || !FileAccess::exists(crt_path);
|
bool regen = !FileAccess::exists(key_path) || !FileAccess::exists(crt_path);
|
||||||
|
@ -138,7 +138,7 @@ public:
|
||||||
|
|
||||||
const String req_file = req[1].get_file();
|
const String req_file = req[1].get_file();
|
||||||
const String req_ext = req[1].get_extension();
|
const String req_ext = req[1].get_extension();
|
||||||
const String cache_path = EditorSettings::get_singleton()->get_cache_dir().plus_file("web");
|
const String cache_path = EditorPaths::get_singleton()->get_cache_dir().plus_file("web");
|
||||||
const String filepath = cache_path.plus_file(req_file);
|
const String filepath = cache_path.plus_file(req_file);
|
||||||
|
|
||||||
if (!mimes.has(req_ext) || !FileAccess::exists(filepath)) {
|
if (!mimes.has(req_ext) || !FileAccess::exists(filepath)) {
|
||||||
|
@ -888,7 +888,7 @@ Error EditorExportPlatformJavaScript::run(const Ref<EditorExportPreset> &p_prese
|
||||||
return OK;
|
return OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
const String dest = EditorSettings::get_singleton()->get_cache_dir().plus_file("web");
|
const String dest = EditorPaths::get_singleton()->get_cache_dir().plus_file("web");
|
||||||
DirAccessRef da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
|
DirAccessRef da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
|
||||||
if (!da->dir_exists(dest)) {
|
if (!da->dir_exists(dest)) {
|
||||||
Error err = da->make_dir_recursive(dest);
|
Error err = da->make_dir_recursive(dest);
|
||||||
|
|
|
@ -301,7 +301,7 @@ void EditorExportPlatformOSX::_make_icon(const Ref<Image> &p_icon, Vector<uint8_
|
||||||
if (icon_infos[i].is_png) {
|
if (icon_infos[i].is_png) {
|
||||||
// Encode PNG icon.
|
// Encode PNG icon.
|
||||||
it->create_from_image(copy);
|
it->create_from_image(copy);
|
||||||
String path = EditorSettings::get_singleton()->get_cache_dir().plus_file("icon.png");
|
String path = EditorPaths::get_singleton()->get_cache_dir().plus_file("icon.png");
|
||||||
ResourceSaver::save(path, it);
|
ResourceSaver::save(path, it);
|
||||||
|
|
||||||
FileAccess *f = FileAccess::open(path, FileAccess::READ);
|
FileAccess *f = FileAccess::open(path, FileAccess::READ);
|
||||||
|
@ -610,7 +610,7 @@ Error EditorExportPlatformOSX::export_project(const Ref<EditorExportPreset> &p_p
|
||||||
|
|
||||||
// Create our application bundle.
|
// Create our application bundle.
|
||||||
String tmp_app_dir_name = pkg_name + ".app";
|
String tmp_app_dir_name = pkg_name + ".app";
|
||||||
String tmp_app_path_name = EditorSettings::get_singleton()->get_cache_dir().plus_file(tmp_app_dir_name);
|
String tmp_app_path_name = EditorPaths::get_singleton()->get_cache_dir().plus_file(tmp_app_dir_name);
|
||||||
print_line("Exporting to " + tmp_app_path_name);
|
print_line("Exporting to " + tmp_app_path_name);
|
||||||
|
|
||||||
Error err = OK;
|
Error err = OK;
|
||||||
|
@ -774,7 +774,7 @@ Error EditorExportPlatformOSX::export_project(const Ref<EditorExportPreset> &p_p
|
||||||
|
|
||||||
String ent_path = p_preset->get("codesign/entitlements/custom_file");
|
String ent_path = p_preset->get("codesign/entitlements/custom_file");
|
||||||
if (sign_enabled && (ent_path == "")) {
|
if (sign_enabled && (ent_path == "")) {
|
||||||
ent_path = EditorSettings::get_singleton()->get_cache_dir().plus_file(pkg_name + ".entitlements");
|
ent_path = EditorPaths::get_singleton()->get_cache_dir().plus_file(pkg_name + ".entitlements");
|
||||||
|
|
||||||
FileAccess *ent_f = FileAccess::open(ent_path, FileAccess::WRITE);
|
FileAccess *ent_f = FileAccess::open(ent_path, FileAccess::WRITE);
|
||||||
if (ent_f) {
|
if (ent_f) {
|
||||||
|
@ -959,7 +959,7 @@ Error EditorExportPlatformOSX::export_project(const Ref<EditorExportPreset> &p_p
|
||||||
zlib_filefunc_def io_dst = zipio_create_io_from_file(&dst_f);
|
zlib_filefunc_def io_dst = zipio_create_io_from_file(&dst_f);
|
||||||
zipFile zip = zipOpen2(p_path.utf8().get_data(), APPEND_STATUS_CREATE, nullptr, &io_dst);
|
zipFile zip = zipOpen2(p_path.utf8().get_data(), APPEND_STATUS_CREATE, nullptr, &io_dst);
|
||||||
|
|
||||||
_zip_folder_recursive(zip, EditorSettings::get_singleton()->get_cache_dir(), pkg_name + ".app", pkg_name);
|
_zip_folder_recursive(zip, EditorPaths::get_singleton()->get_cache_dir(), pkg_name + ".app", pkg_name);
|
||||||
|
|
||||||
zipClose(zip, nullptr);
|
zipClose(zip, nullptr);
|
||||||
}
|
}
|
||||||
|
|
|
@ -567,7 +567,7 @@ void AppxPackager::finish() {
|
||||||
// Create and add block map file
|
// Create and add block map file
|
||||||
EditorNode::progress_task_step("export", "Creating block map...", 4);
|
EditorNode::progress_task_step("export", "Creating block map...", 4);
|
||||||
|
|
||||||
const String &tmp_blockmap_file_path = EditorSettings::get_singleton()->get_cache_dir().plus_file("tmpblockmap.xml");
|
const String &tmp_blockmap_file_path = EditorPaths::get_singleton()->get_cache_dir().plus_file("tmpblockmap.xml");
|
||||||
make_block_map(tmp_blockmap_file_path);
|
make_block_map(tmp_blockmap_file_path);
|
||||||
|
|
||||||
FileAccess *blockmap_file = FileAccess::open(tmp_blockmap_file_path, FileAccess::READ);
|
FileAccess *blockmap_file = FileAccess::open(tmp_blockmap_file_path, FileAccess::READ);
|
||||||
|
@ -585,7 +585,7 @@ void AppxPackager::finish() {
|
||||||
|
|
||||||
EditorNode::progress_task_step("export", "Setting content types...", 5);
|
EditorNode::progress_task_step("export", "Setting content types...", 5);
|
||||||
|
|
||||||
const String &tmp_content_types_file_path = EditorSettings::get_singleton()->get_cache_dir().plus_file("tmpcontenttypes.xml");
|
const String &tmp_content_types_file_path = EditorPaths::get_singleton()->get_cache_dir().plus_file("tmpcontenttypes.xml");
|
||||||
make_content_types(tmp_content_types_file_path);
|
make_content_types(tmp_content_types_file_path);
|
||||||
|
|
||||||
FileAccess *types_file = FileAccess::open(tmp_content_types_file_path, FileAccess::READ);
|
FileAccess *types_file = FileAccess::open(tmp_content_types_file_path, FileAccess::READ);
|
||||||
|
@ -879,7 +879,7 @@ class EditorExportPlatformUWP : public EditorExportPlatform {
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
String tmp_path = EditorSettings::get_singleton()->get_cache_dir().plus_file("uwp_tmp_logo.png");
|
String tmp_path = EditorPaths::get_singleton()->get_cache_dir().plus_file("uwp_tmp_logo.png");
|
||||||
|
|
||||||
Error err = texture->get_image()->save_png(tmp_path);
|
Error err = texture->get_image()->save_png(tmp_path);
|
||||||
|
|
||||||
|
|
|
@ -31,6 +31,7 @@
|
||||||
#include "renderer_compositor_rd.h"
|
#include "renderer_compositor_rd.h"
|
||||||
|
|
||||||
#include "core/config/project_settings.h"
|
#include "core/config/project_settings.h"
|
||||||
|
#include "core/os/dir_access.h"
|
||||||
|
|
||||||
void RendererCompositorRD::prepare_for_blitting_render_targets() {
|
void RendererCompositorRD::prepare_for_blitting_render_targets() {
|
||||||
RD::get_singleton()->prepare_screen_for_drawing();
|
RD::get_singleton()->prepare_screen_for_drawing();
|
||||||
|
@ -155,6 +156,43 @@ void RendererCompositorRD::finalize() {
|
||||||
RendererCompositorRD *RendererCompositorRD::singleton = nullptr;
|
RendererCompositorRD *RendererCompositorRD::singleton = nullptr;
|
||||||
|
|
||||||
RendererCompositorRD::RendererCompositorRD() {
|
RendererCompositorRD::RendererCompositorRD() {
|
||||||
|
{
|
||||||
|
String shader_cache_dir = Engine::get_singleton()->get_shader_cache_path();
|
||||||
|
if (shader_cache_dir == String()) {
|
||||||
|
shader_cache_dir = "user://";
|
||||||
|
}
|
||||||
|
DirAccessRef da = DirAccess::open(shader_cache_dir);
|
||||||
|
if (!da) {
|
||||||
|
ERR_PRINT("Can't create shader cache folder, no shader caching will happen: " + shader_cache_dir);
|
||||||
|
} else {
|
||||||
|
Error err = da->change_dir("shader_cache");
|
||||||
|
if (err != OK) {
|
||||||
|
err = da->make_dir("shader_cache");
|
||||||
|
}
|
||||||
|
if (err != OK) {
|
||||||
|
ERR_PRINT("Can't create shader cache folder, no shader caching will happen: " + shader_cache_dir);
|
||||||
|
} else {
|
||||||
|
shader_cache_dir = shader_cache_dir.plus_file("shader_cache");
|
||||||
|
|
||||||
|
bool shader_cache_enabled = GLOBAL_GET("rendering/shader_compiler/shader_cache/enabled");
|
||||||
|
if (!Engine::get_singleton()->is_editor_hint() && !shader_cache_enabled) {
|
||||||
|
shader_cache_dir = String(); //disable only if not editor
|
||||||
|
}
|
||||||
|
|
||||||
|
if (shader_cache_dir != String()) {
|
||||||
|
bool compress = GLOBAL_GET("rendering/shader_compiler/shader_cache/compress");
|
||||||
|
bool use_zstd = GLOBAL_GET("rendering/shader_compiler/shader_cache/use_zstd_compression");
|
||||||
|
bool strip_debug = GLOBAL_GET("rendering/shader_compiler/shader_cache/strip_debug");
|
||||||
|
|
||||||
|
ShaderRD::set_shader_cache_dir(shader_cache_dir);
|
||||||
|
ShaderRD::set_shader_cache_save_compressed(compress);
|
||||||
|
ShaderRD::set_shader_cache_save_compressed_zstd(use_zstd);
|
||||||
|
ShaderRD::set_shader_cache_save_debug(!strip_debug);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
singleton = this;
|
singleton = this;
|
||||||
time = 0;
|
time = 0;
|
||||||
|
|
||||||
|
@ -171,3 +209,7 @@ RendererCompositorRD::RendererCompositorRD() {
|
||||||
scene = memnew(RendererSceneRenderImplementation::RenderForwardClustered(storage));
|
scene = memnew(RendererSceneRenderImplementation::RenderForwardClustered(storage));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
RendererCompositorRD::~RendererCompositorRD() {
|
||||||
|
ShaderRD::set_shader_cache_dir(String());
|
||||||
|
}
|
||||||
|
|
|
@ -118,6 +118,6 @@ public:
|
||||||
|
|
||||||
static RendererCompositorRD *singleton;
|
static RendererCompositorRD *singleton;
|
||||||
RendererCompositorRD();
|
RendererCompositorRD();
|
||||||
~RendererCompositorRD() {}
|
~RendererCompositorRD();
|
||||||
};
|
};
|
||||||
#endif // RASTERIZER_RD_H
|
#endif // RASTERIZER_RD_H
|
||||||
|
|
|
@ -369,17 +369,24 @@ void ShaderCompilerRD::_dump_function_deps(const SL::ShaderNode *p_node, const S
|
||||||
|
|
||||||
ERR_FAIL_COND(fidx == -1);
|
ERR_FAIL_COND(fidx == -1);
|
||||||
|
|
||||||
|
Vector<StringName> uses_functions;
|
||||||
|
|
||||||
for (Set<StringName>::Element *E = p_node->functions[fidx].uses_function.front(); E; E = E->next()) {
|
for (Set<StringName>::Element *E = p_node->functions[fidx].uses_function.front(); E; E = E->next()) {
|
||||||
if (added.has(E->get())) {
|
uses_functions.push_back(E->get());
|
||||||
|
}
|
||||||
|
uses_functions.sort_custom<StringName::AlphCompare>(); //ensure order is deterministic so the same shader is always produced
|
||||||
|
|
||||||
|
for (int k = 0; k < uses_functions.size(); k++) {
|
||||||
|
if (added.has(uses_functions[k])) {
|
||||||
continue; //was added already
|
continue; //was added already
|
||||||
}
|
}
|
||||||
|
|
||||||
_dump_function_deps(p_node, E->get(), p_func_code, r_to_add, added);
|
_dump_function_deps(p_node, uses_functions[k], p_func_code, r_to_add, added);
|
||||||
|
|
||||||
SL::FunctionNode *fnode = nullptr;
|
SL::FunctionNode *fnode = nullptr;
|
||||||
|
|
||||||
for (int i = 0; i < p_node->functions.size(); i++) {
|
for (int i = 0; i < p_node->functions.size(); i++) {
|
||||||
if (p_node->functions[i].name == E->get()) {
|
if (p_node->functions[i].name == uses_functions[k]) {
|
||||||
fnode = p_node->functions[i].function;
|
fnode = p_node->functions[i].function;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -427,9 +434,9 @@ void ShaderCompilerRD::_dump_function_deps(const SL::ShaderNode *p_node, const S
|
||||||
|
|
||||||
header += ")\n";
|
header += ")\n";
|
||||||
r_to_add += header;
|
r_to_add += header;
|
||||||
r_to_add += p_func_code[E->get()];
|
r_to_add += p_func_code[uses_functions[k]];
|
||||||
|
|
||||||
added.insert(E->get());
|
added.insert(uses_functions[k]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -581,63 +588,74 @@ String ShaderCompilerRD::_dump_node_code(const SL::Node *p_node, int p_level, Ge
|
||||||
uniform_defines.resize(max_uniforms);
|
uniform_defines.resize(max_uniforms);
|
||||||
bool uses_uniforms = false;
|
bool uses_uniforms = false;
|
||||||
|
|
||||||
|
Vector<StringName> uniform_names;
|
||||||
|
|
||||||
for (Map<StringName, SL::ShaderNode::Uniform>::Element *E = pnode->uniforms.front(); E; E = E->next()) {
|
for (Map<StringName, SL::ShaderNode::Uniform>::Element *E = pnode->uniforms.front(); E; E = E->next()) {
|
||||||
|
uniform_names.push_back(E->key());
|
||||||
|
}
|
||||||
|
|
||||||
|
uniform_names.sort_custom<StringName::AlphCompare>(); //ensure order is deterministic so the same shader is always produced
|
||||||
|
|
||||||
|
for (int k = 0; k < uniform_names.size(); k++) {
|
||||||
|
StringName uniform_name = uniform_names[k];
|
||||||
|
const SL::ShaderNode::Uniform &uniform = pnode->uniforms[uniform_name];
|
||||||
|
|
||||||
String ucode;
|
String ucode;
|
||||||
|
|
||||||
if (E->get().scope == SL::ShaderNode::Uniform::SCOPE_INSTANCE) {
|
if (uniform.scope == SL::ShaderNode::Uniform::SCOPE_INSTANCE) {
|
||||||
//insert, but don't generate any code.
|
//insert, but don't generate any code.
|
||||||
p_actions.uniforms->insert(E->key(), E->get());
|
p_actions.uniforms->insert(uniform_name, uniform);
|
||||||
continue; //instances are indexed directly, dont need index uniforms
|
continue; //instances are indexed directly, dont need index uniforms
|
||||||
}
|
}
|
||||||
if (SL::is_sampler_type(E->get().type)) {
|
if (SL::is_sampler_type(uniform.type)) {
|
||||||
ucode = "layout(set = " + itos(actions.texture_layout_set) + ", binding = " + itos(actions.base_texture_binding_index + E->get().texture_order) + ") uniform ";
|
ucode = "layout(set = " + itos(actions.texture_layout_set) + ", binding = " + itos(actions.base_texture_binding_index + uniform.texture_order) + ") uniform ";
|
||||||
}
|
}
|
||||||
|
|
||||||
bool is_buffer_global = !SL::is_sampler_type(E->get().type) && E->get().scope == SL::ShaderNode::Uniform::SCOPE_GLOBAL;
|
bool is_buffer_global = !SL::is_sampler_type(uniform.type) && uniform.scope == SL::ShaderNode::Uniform::SCOPE_GLOBAL;
|
||||||
|
|
||||||
if (is_buffer_global) {
|
if (is_buffer_global) {
|
||||||
//this is an integer to index the global table
|
//this is an integer to index the global table
|
||||||
ucode += _typestr(ShaderLanguage::TYPE_UINT);
|
ucode += _typestr(ShaderLanguage::TYPE_UINT);
|
||||||
} else {
|
} else {
|
||||||
ucode += _prestr(E->get().precision);
|
ucode += _prestr(uniform.precision);
|
||||||
ucode += _typestr(E->get().type);
|
ucode += _typestr(uniform.type);
|
||||||
}
|
}
|
||||||
|
|
||||||
ucode += " " + _mkid(E->key());
|
ucode += " " + _mkid(uniform_name);
|
||||||
ucode += ";\n";
|
ucode += ";\n";
|
||||||
if (SL::is_sampler_type(E->get().type)) {
|
if (SL::is_sampler_type(uniform.type)) {
|
||||||
for (int j = 0; j < STAGE_MAX; j++) {
|
for (int j = 0; j < STAGE_MAX; j++) {
|
||||||
r_gen_code.stage_globals[j] += ucode;
|
r_gen_code.stage_globals[j] += ucode;
|
||||||
}
|
}
|
||||||
|
|
||||||
GeneratedCode::Texture texture;
|
GeneratedCode::Texture texture;
|
||||||
texture.name = E->key();
|
texture.name = uniform_name;
|
||||||
texture.hint = E->get().hint;
|
texture.hint = uniform.hint;
|
||||||
texture.type = E->get().type;
|
texture.type = uniform.type;
|
||||||
texture.filter = E->get().filter;
|
texture.filter = uniform.filter;
|
||||||
texture.repeat = E->get().repeat;
|
texture.repeat = uniform.repeat;
|
||||||
texture.global = E->get().scope == ShaderLanguage::ShaderNode::Uniform::SCOPE_GLOBAL;
|
texture.global = uniform.scope == ShaderLanguage::ShaderNode::Uniform::SCOPE_GLOBAL;
|
||||||
if (texture.global) {
|
if (texture.global) {
|
||||||
r_gen_code.uses_global_textures = true;
|
r_gen_code.uses_global_textures = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
r_gen_code.texture_uniforms.write[E->get().texture_order] = texture;
|
r_gen_code.texture_uniforms.write[uniform.texture_order] = texture;
|
||||||
} else {
|
} else {
|
||||||
if (!uses_uniforms) {
|
if (!uses_uniforms) {
|
||||||
uses_uniforms = true;
|
uses_uniforms = true;
|
||||||
}
|
}
|
||||||
uniform_defines.write[E->get().order] = ucode;
|
uniform_defines.write[uniform.order] = ucode;
|
||||||
if (is_buffer_global) {
|
if (is_buffer_global) {
|
||||||
//globals are indices into the global table
|
//globals are indices into the global table
|
||||||
uniform_sizes.write[E->get().order] = _get_datatype_size(ShaderLanguage::TYPE_UINT);
|
uniform_sizes.write[uniform.order] = _get_datatype_size(ShaderLanguage::TYPE_UINT);
|
||||||
uniform_alignments.write[E->get().order] = _get_datatype_alignment(ShaderLanguage::TYPE_UINT);
|
uniform_alignments.write[uniform.order] = _get_datatype_alignment(ShaderLanguage::TYPE_UINT);
|
||||||
} else {
|
} else {
|
||||||
uniform_sizes.write[E->get().order] = _get_datatype_size(E->get().type);
|
uniform_sizes.write[uniform.order] = _get_datatype_size(uniform.type);
|
||||||
uniform_alignments.write[E->get().order] = _get_datatype_alignment(E->get().type);
|
uniform_alignments.write[uniform.order] = _get_datatype_alignment(uniform.type);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
p_actions.uniforms->insert(E->key(), E->get());
|
p_actions.uniforms->insert(uniform_name, uniform);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int i = 0; i < max_uniforms; i++) {
|
for (int i = 0; i < max_uniforms; i++) {
|
||||||
|
@ -704,21 +722,32 @@ String ShaderCompilerRD::_dump_node_code(const SL::Node *p_node, int p_level, Ge
|
||||||
|
|
||||||
List<Pair<StringName, SL::ShaderNode::Varying>> var_frag_to_light;
|
List<Pair<StringName, SL::ShaderNode::Varying>> var_frag_to_light;
|
||||||
|
|
||||||
|
Vector<StringName> varying_names;
|
||||||
|
|
||||||
for (Map<StringName, SL::ShaderNode::Varying>::Element *E = pnode->varyings.front(); E; E = E->next()) {
|
for (Map<StringName, SL::ShaderNode::Varying>::Element *E = pnode->varyings.front(); E; E = E->next()) {
|
||||||
if (E->get().stage == SL::ShaderNode::Varying::STAGE_FRAGMENT_TO_LIGHT || E->get().stage == SL::ShaderNode::Varying::STAGE_FRAGMENT) {
|
varying_names.push_back(E->key());
|
||||||
var_frag_to_light.push_back(Pair<StringName, SL::ShaderNode::Varying>(E->key(), E->get()));
|
}
|
||||||
fragment_varyings.insert(E->key());
|
|
||||||
|
varying_names.sort_custom<StringName::AlphCompare>(); //ensure order is deterministic so the same shader is always produced
|
||||||
|
|
||||||
|
for (int k = 0; k < varying_names.size(); k++) {
|
||||||
|
StringName varying_name = varying_names[k];
|
||||||
|
const SL::ShaderNode::Varying &varying = pnode->varyings[varying_name];
|
||||||
|
|
||||||
|
if (varying.stage == SL::ShaderNode::Varying::STAGE_FRAGMENT_TO_LIGHT || varying.stage == SL::ShaderNode::Varying::STAGE_FRAGMENT) {
|
||||||
|
var_frag_to_light.push_back(Pair<StringName, SL::ShaderNode::Varying>(varying_name, varying));
|
||||||
|
fragment_varyings.insert(varying_name);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
String vcode;
|
String vcode;
|
||||||
String interp_mode = _interpstr(E->get().interpolation);
|
String interp_mode = _interpstr(varying.interpolation);
|
||||||
vcode += _prestr(E->get().precision);
|
vcode += _prestr(varying.precision);
|
||||||
vcode += _typestr(E->get().type);
|
vcode += _typestr(varying.type);
|
||||||
vcode += " " + _mkid(E->key());
|
vcode += " " + _mkid(varying_name);
|
||||||
if (E->get().array_size > 0) {
|
if (varying.array_size > 0) {
|
||||||
vcode += "[";
|
vcode += "[";
|
||||||
vcode += itos(E->get().array_size);
|
vcode += itos(varying.array_size);
|
||||||
vcode += "]";
|
vcode += "]";
|
||||||
}
|
}
|
||||||
vcode += ";\n";
|
vcode += ";\n";
|
||||||
|
|
|
@ -30,8 +30,12 @@
|
||||||
|
|
||||||
#include "shader_rd.h"
|
#include "shader_rd.h"
|
||||||
|
|
||||||
|
#include "core/io/compression.h"
|
||||||
|
#include "core/os/dir_access.h"
|
||||||
|
#include "core/os/file_access.h"
|
||||||
#include "renderer_compositor_rd.h"
|
#include "renderer_compositor_rd.h"
|
||||||
#include "servers/rendering/rendering_device.h"
|
#include "servers/rendering/rendering_device.h"
|
||||||
|
#include "thirdparty/misc/smolv.h"
|
||||||
|
|
||||||
void ShaderRD::_add_stage(const char *p_code, StageType p_stage_type) {
|
void ShaderRD::_add_stage(const char *p_code, StageType p_stage_type) {
|
||||||
Vector<String> lines = String(p_code).split("\n");
|
Vector<String> lines = String(p_code).split("\n");
|
||||||
|
@ -97,6 +101,7 @@ void ShaderRD::_add_stage(const char *p_code, StageType p_stage_type) {
|
||||||
|
|
||||||
void ShaderRD::setup(const char *p_vertex_code, const char *p_fragment_code, const char *p_compute_code, const char *p_name) {
|
void ShaderRD::setup(const char *p_vertex_code, const char *p_fragment_code, const char *p_compute_code, const char *p_name) {
|
||||||
name = p_name;
|
name = p_name;
|
||||||
|
|
||||||
if (p_compute_code) {
|
if (p_compute_code) {
|
||||||
_add_stage(p_compute_code, STAGE_TYPE_COMPUTE);
|
_add_stage(p_compute_code, STAGE_TYPE_COMPUTE);
|
||||||
is_compute = true;
|
is_compute = true;
|
||||||
|
@ -109,6 +114,18 @@ void ShaderRD::setup(const char *p_vertex_code, const char *p_fragment_code, con
|
||||||
_add_stage(p_fragment_code, STAGE_TYPE_FRAGMENT);
|
_add_stage(p_fragment_code, STAGE_TYPE_FRAGMENT);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
StringBuilder tohash;
|
||||||
|
tohash.append("[VersionKey]");
|
||||||
|
tohash.append(RenderingDevice::get_singleton()->shader_get_cache_key());
|
||||||
|
tohash.append("[Vertex]");
|
||||||
|
tohash.append(p_vertex_code ? p_vertex_code : "");
|
||||||
|
tohash.append("[Fragment]");
|
||||||
|
tohash.append(p_fragment_code ? p_fragment_code : "");
|
||||||
|
tohash.append("[Compute]");
|
||||||
|
tohash.append(p_compute_code ? p_compute_code : "");
|
||||||
|
|
||||||
|
base_sha256 = tohash.as_string().sha256_text();
|
||||||
}
|
}
|
||||||
|
|
||||||
RID ShaderRD::version_create() {
|
RID ShaderRD::version_create() {
|
||||||
|
@ -131,6 +148,9 @@ void ShaderRD::_clear_version(Version *p_version) {
|
||||||
}
|
}
|
||||||
|
|
||||||
memdelete_arr(p_version->variants);
|
memdelete_arr(p_version->variants);
|
||||||
|
if (p_version->variant_stages) {
|
||||||
|
memdelete_arr(p_version->variant_stages);
|
||||||
|
}
|
||||||
p_version->variants = nullptr;
|
p_version->variants = nullptr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -183,7 +203,7 @@ void ShaderRD::_compile_variant(uint32_t p_variant, Version *p_version) {
|
||||||
return; //variant is disabled, return
|
return; //variant is disabled, return
|
||||||
}
|
}
|
||||||
|
|
||||||
Vector<RD::ShaderStageData> stages;
|
Vector<RD::ShaderStageData> &stages = p_version->variant_stages[p_variant];
|
||||||
|
|
||||||
String error;
|
String error;
|
||||||
String current_source;
|
String current_source;
|
||||||
|
@ -313,6 +333,197 @@ RS::ShaderNativeSourceCode ShaderRD::version_get_native_source_code(RID p_versio
|
||||||
return source_code;
|
return source_code;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
String ShaderRD::_version_get_sha1(Version *p_version) const {
|
||||||
|
StringBuilder hash_build;
|
||||||
|
|
||||||
|
hash_build.append("[uniforms]");
|
||||||
|
hash_build.append(p_version->uniforms.get_data());
|
||||||
|
hash_build.append("[vertex_globals]");
|
||||||
|
hash_build.append(p_version->vertex_globals.get_data());
|
||||||
|
hash_build.append("[fragment_globals]");
|
||||||
|
hash_build.append(p_version->fragment_globals.get_data());
|
||||||
|
hash_build.append("[compute_globals]");
|
||||||
|
hash_build.append(p_version->compute_globals.get_data());
|
||||||
|
|
||||||
|
Vector<StringName> code_sections;
|
||||||
|
for (Map<StringName, CharString>::Element *E = p_version->code_sections.front(); E; E = E->next()) {
|
||||||
|
code_sections.push_back(E->key());
|
||||||
|
}
|
||||||
|
code_sections.sort_custom<StringName::AlphCompare>();
|
||||||
|
|
||||||
|
for (int i = 0; i < code_sections.size(); i++) {
|
||||||
|
hash_build.append(String("[code:") + String(code_sections[i]) + "]");
|
||||||
|
hash_build.append(p_version->code_sections[code_sections[i]].get_data());
|
||||||
|
}
|
||||||
|
for (int i = 0; i < p_version->custom_defines.size(); i++) {
|
||||||
|
hash_build.append("[custom_defines:" + itos(i) + "]");
|
||||||
|
hash_build.append(p_version->custom_defines[i].get_data());
|
||||||
|
}
|
||||||
|
|
||||||
|
return hash_build.as_string().sha1_text();
|
||||||
|
}
|
||||||
|
|
||||||
|
static const char *shader_file_header = "GDSC";
|
||||||
|
static const uint32_t cache_file_version = 1;
|
||||||
|
|
||||||
|
bool ShaderRD::_load_from_cache(Version *p_version) {
|
||||||
|
String sha1 = _version_get_sha1(p_version);
|
||||||
|
String path = shader_cache_dir.plus_file(name).plus_file(base_sha256).plus_file(sha1) + ".cache";
|
||||||
|
|
||||||
|
uint64_t time_from = OS::get_singleton()->get_ticks_usec();
|
||||||
|
|
||||||
|
FileAccessRef f = FileAccess::open(path, FileAccess::READ);
|
||||||
|
if (!f) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
char header[5] = { 0, 0, 0, 0, 0 };
|
||||||
|
f->get_buffer((uint8_t *)header, 4);
|
||||||
|
ERR_FAIL_COND_V(header != String(shader_file_header), false);
|
||||||
|
|
||||||
|
uint32_t file_version = f->get_32();
|
||||||
|
if (file_version != cache_file_version) {
|
||||||
|
return false; // wrong version
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t variant_count = f->get_32();
|
||||||
|
|
||||||
|
ERR_FAIL_COND_V(variant_count != (uint32_t)variant_defines.size(), false); //should not happen but check
|
||||||
|
|
||||||
|
bool success = true;
|
||||||
|
for (uint32_t i = 0; i < variant_count; i++) {
|
||||||
|
uint32_t stage_count = f->get_32();
|
||||||
|
p_version->variant_stages[i].resize(stage_count);
|
||||||
|
for (uint32_t j = 0; j < stage_count; j++) {
|
||||||
|
p_version->variant_stages[i].write[j].shader_stage = RD::ShaderStage(f->get_32());
|
||||||
|
|
||||||
|
int compression = f->get_32();
|
||||||
|
uint32_t length = f->get_32();
|
||||||
|
|
||||||
|
if (compression == 0) {
|
||||||
|
Vector<uint8_t> data;
|
||||||
|
data.resize(length);
|
||||||
|
|
||||||
|
f->get_buffer(data.ptrw(), length);
|
||||||
|
|
||||||
|
p_version->variant_stages[i].write[j].spir_v = data;
|
||||||
|
} else {
|
||||||
|
Vector<uint8_t> data;
|
||||||
|
|
||||||
|
if (compression == 2) {
|
||||||
|
//zstd
|
||||||
|
int smol_length = f->get_32();
|
||||||
|
Vector<uint8_t> zstd_data;
|
||||||
|
|
||||||
|
zstd_data.resize(smol_length);
|
||||||
|
f->get_buffer(zstd_data.ptrw(), smol_length);
|
||||||
|
|
||||||
|
data.resize(length);
|
||||||
|
Compression::decompress(data.ptrw(), data.size(), zstd_data.ptr(), zstd_data.size(), Compression::MODE_ZSTD);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
data.resize(length);
|
||||||
|
f->get_buffer(data.ptrw(), length);
|
||||||
|
}
|
||||||
|
|
||||||
|
Vector<uint8_t> spirv;
|
||||||
|
uint32_t spirv_size = smolv::GetDecodedBufferSize(data.ptr(), data.size());
|
||||||
|
spirv.resize(spirv_size);
|
||||||
|
if (!smolv::Decode(data.ptr(), data.size(), spirv.ptrw(), spirv_size)) {
|
||||||
|
ERR_PRINT("Malformed smolv input uncompressing shader " + name + ", variant #" + itos(i) + " stage :" + itos(j));
|
||||||
|
success = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
p_version->variant_stages[i].write[j].spir_v = spirv;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!success) {
|
||||||
|
for (uint32_t i = 0; i < variant_count; i++) {
|
||||||
|
p_version->variant_stages[i].resize(0);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
float time_ms = double(OS::get_singleton()->get_ticks_usec() - time_from) / 1000.0;
|
||||||
|
|
||||||
|
print_verbose("Shader cache load success '" + path + "' " + rtos(time_ms) + "ms.");
|
||||||
|
|
||||||
|
for (uint32_t i = 0; i < variant_count; i++) {
|
||||||
|
RID shader = RD::get_singleton()->shader_create(p_version->variant_stages[i]);
|
||||||
|
{
|
||||||
|
MutexLock lock(variant_set_mutex);
|
||||||
|
p_version->variants[i] = shader;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
memdelete_arr(p_version->variant_stages); //clear stages
|
||||||
|
p_version->variant_stages = nullptr;
|
||||||
|
p_version->valid = true;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ShaderRD::_save_to_cache(Version *p_version) {
|
||||||
|
String sha1 = _version_get_sha1(p_version);
|
||||||
|
String path = shader_cache_dir.plus_file(name).plus_file(base_sha256).plus_file(sha1) + ".cache";
|
||||||
|
|
||||||
|
FileAccessRef f = FileAccess::open(path, FileAccess::WRITE);
|
||||||
|
ERR_FAIL_COND(!f);
|
||||||
|
f->store_buffer((const uint8_t *)shader_file_header, 4);
|
||||||
|
f->store_32(cache_file_version); //file version
|
||||||
|
uint32_t variant_count = variant_defines.size();
|
||||||
|
f->store_32(variant_count); //variant count
|
||||||
|
|
||||||
|
for (uint32_t i = 0; i < variant_count; i++) {
|
||||||
|
f->store_32(p_version->variant_stages[i].size()); //stage count
|
||||||
|
for (int j = 0; j < p_version->variant_stages[i].size(); j++) {
|
||||||
|
f->store_32(p_version->variant_stages[i][j].shader_stage); //stage count
|
||||||
|
Vector<uint8_t> spirv = p_version->variant_stages[i][j].spir_v;
|
||||||
|
|
||||||
|
bool save_uncompressed = true;
|
||||||
|
if (shader_cache_save_compressed) {
|
||||||
|
smolv::ByteArray smolv;
|
||||||
|
bool strip_debug = !shader_cache_save_debug;
|
||||||
|
if (!smolv::Encode(spirv.ptr(), spirv.size(), smolv, strip_debug ? smolv::kEncodeFlagStripDebugInfo : 0)) {
|
||||||
|
ERR_PRINT("Error compressing shader " + name + ", variant #" + itos(i) + " stage :" + itos(i));
|
||||||
|
} else {
|
||||||
|
bool compress_zstd = shader_cache_save_compressed_zstd;
|
||||||
|
|
||||||
|
if (compress_zstd) {
|
||||||
|
Vector<uint8_t> zstd;
|
||||||
|
zstd.resize(Compression::get_max_compressed_buffer_size(smolv.size(), Compression::MODE_ZSTD));
|
||||||
|
int dst_size = Compression::compress(zstd.ptrw(), &smolv[0], smolv.size(), Compression::MODE_ZSTD);
|
||||||
|
if (dst_size >= 0 && (uint32_t)dst_size < smolv.size()) {
|
||||||
|
f->store_32(2); //compressed zstd
|
||||||
|
f->store_32(smolv.size()); //size of smolv buffer
|
||||||
|
f->store_32(dst_size); //size of smolv buffer
|
||||||
|
f->store_buffer(zstd.ptr(), dst_size); //smolv buffer
|
||||||
|
} else {
|
||||||
|
compress_zstd = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!compress_zstd) {
|
||||||
|
f->store_32(1); //compressed
|
||||||
|
f->store_32(smolv.size()); //size of smolv buffer
|
||||||
|
f->store_buffer(&smolv[0], smolv.size()); //smolv buffer
|
||||||
|
}
|
||||||
|
save_uncompressed = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (save_uncompressed) {
|
||||||
|
f->store_32(0); //uncompressed
|
||||||
|
f->store_32(spirv.size()); //stage count
|
||||||
|
f->store_buffer(spirv.ptr(), spirv.size()); //stage count
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
f->close();
|
||||||
|
}
|
||||||
|
|
||||||
void ShaderRD::_compile_version(Version *p_version) {
|
void ShaderRD::_compile_version(Version *p_version) {
|
||||||
_clear_version(p_version);
|
_clear_version(p_version);
|
||||||
|
|
||||||
|
@ -320,6 +531,15 @@ void ShaderRD::_compile_version(Version *p_version) {
|
||||||
p_version->dirty = false;
|
p_version->dirty = false;
|
||||||
|
|
||||||
p_version->variants = memnew_arr(RID, variant_defines.size());
|
p_version->variants = memnew_arr(RID, variant_defines.size());
|
||||||
|
typedef Vector<RD::ShaderStageData> ShaderStageArray;
|
||||||
|
p_version->variant_stages = memnew_arr(ShaderStageArray, variant_defines.size());
|
||||||
|
|
||||||
|
if (shader_cache_dir_valid) {
|
||||||
|
if (_load_from_cache(p_version)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#if 1
|
#if 1
|
||||||
|
|
||||||
RendererThreadPool::singleton->thread_work_pool.do_work(variant_defines.size(), this, &ShaderRD::_compile_variant, p_version);
|
RendererThreadPool::singleton->thread_work_pool.do_work(variant_defines.size(), this, &ShaderRD::_compile_variant, p_version);
|
||||||
|
@ -351,9 +571,19 @@ void ShaderRD::_compile_version(Version *p_version) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
memdelete_arr(p_version->variants);
|
memdelete_arr(p_version->variants);
|
||||||
p_version->variants = nullptr;
|
if (p_version->variant_stages) {
|
||||||
return;
|
memdelete_arr(p_version->variant_stages);
|
||||||
}
|
}
|
||||||
|
p_version->variants = nullptr;
|
||||||
|
p_version->variant_stages = nullptr;
|
||||||
|
return;
|
||||||
|
} else if (shader_cache_dir_valid) {
|
||||||
|
//save shader cache
|
||||||
|
_save_to_cache(p_version);
|
||||||
|
}
|
||||||
|
|
||||||
|
memdelete_arr(p_version->variant_stages); //clear stages
|
||||||
|
p_version->variant_stages = nullptr;
|
||||||
|
|
||||||
p_version->valid = true;
|
p_version->valid = true;
|
||||||
}
|
}
|
||||||
|
@ -443,6 +673,8 @@ bool ShaderRD::is_variant_enabled(int p_variant) const {
|
||||||
return variants_enabled[p_variant];
|
return variants_enabled[p_variant];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool ShaderRD::shader_cache_cleanup_on_start = false;
|
||||||
|
|
||||||
ShaderRD::ShaderRD() {
|
ShaderRD::ShaderRD() {
|
||||||
// Do not feel forced to use this, in most cases it makes little to no difference.
|
// Do not feel forced to use this, in most cases it makes little to no difference.
|
||||||
bool use_32_threads = false;
|
bool use_32_threads = false;
|
||||||
|
@ -469,8 +701,64 @@ void ShaderRD::initialize(const Vector<String> &p_variant_defines, const String
|
||||||
variant_defines.push_back(p_variant_defines[i].utf8());
|
variant_defines.push_back(p_variant_defines[i].utf8());
|
||||||
variants_enabled.push_back(true);
|
variants_enabled.push_back(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (shader_cache_dir != String()) {
|
||||||
|
StringBuilder hash_build;
|
||||||
|
|
||||||
|
hash_build.append("[base_hash]");
|
||||||
|
hash_build.append(base_sha256);
|
||||||
|
hash_build.append("[general_defines]");
|
||||||
|
hash_build.append(general_defines.get_data());
|
||||||
|
for (int i = 0; i < variant_defines.size(); i++) {
|
||||||
|
hash_build.append("[variant_defines:" + itos(i) + "]");
|
||||||
|
hash_build.append(variant_defines[i].get_data());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
base_sha256 = hash_build.as_string().sha256_text();
|
||||||
|
|
||||||
|
DirAccessRef d = DirAccess::open(shader_cache_dir);
|
||||||
|
ERR_FAIL_COND(!d);
|
||||||
|
if (d->change_dir(name) != OK) {
|
||||||
|
Error err = d->make_dir(name);
|
||||||
|
ERR_FAIL_COND(err != OK);
|
||||||
|
d->change_dir(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
//erase other versions?
|
||||||
|
if (shader_cache_cleanup_on_start) {
|
||||||
|
}
|
||||||
|
//
|
||||||
|
if (d->change_dir(base_sha256) != OK) {
|
||||||
|
Error err = d->make_dir(base_sha256);
|
||||||
|
ERR_FAIL_COND(err != OK);
|
||||||
|
}
|
||||||
|
shader_cache_dir_valid = true;
|
||||||
|
|
||||||
|
print_verbose("Shader '" + name + "' SHA256: " + base_sha256);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ShaderRD::set_shader_cache_dir(const String &p_dir) {
|
||||||
|
shader_cache_dir = p_dir;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ShaderRD::set_shader_cache_save_compressed(bool p_enable) {
|
||||||
|
shader_cache_save_compressed = p_enable;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ShaderRD::set_shader_cache_save_compressed_zstd(bool p_enable) {
|
||||||
|
shader_cache_save_compressed_zstd = p_enable;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ShaderRD::set_shader_cache_save_debug(bool p_enable) {
|
||||||
|
shader_cache_save_debug = p_enable;
|
||||||
|
}
|
||||||
|
|
||||||
|
String ShaderRD::shader_cache_dir;
|
||||||
|
bool ShaderRD::shader_cache_save_compressed = true;
|
||||||
|
bool ShaderRD::shader_cache_save_compressed_zstd = true;
|
||||||
|
bool ShaderRD::shader_cache_save_debug = true;
|
||||||
|
|
||||||
ShaderRD::~ShaderRD() {
|
ShaderRD::~ShaderRD() {
|
||||||
List<RID> remaining;
|
List<RID> remaining;
|
||||||
version_owner.get_owned_list(&remaining);
|
version_owner.get_owned_list(&remaining);
|
||||||
|
|
|
@ -59,7 +59,8 @@ class ShaderRD {
|
||||||
Map<StringName, CharString> code_sections;
|
Map<StringName, CharString> code_sections;
|
||||||
Vector<CharString> custom_defines;
|
Vector<CharString> custom_defines;
|
||||||
|
|
||||||
RID *variants; //same size as version defines
|
Vector<RD::ShaderStageData> *variant_stages = nullptr;
|
||||||
|
RID *variants = nullptr; //same size as version defines
|
||||||
|
|
||||||
bool valid;
|
bool valid;
|
||||||
bool dirty;
|
bool dirty;
|
||||||
|
@ -96,10 +97,19 @@ class ShaderRD {
|
||||||
|
|
||||||
bool is_compute = false;
|
bool is_compute = false;
|
||||||
|
|
||||||
const char *name;
|
String name;
|
||||||
|
|
||||||
CharString base_compute_defines;
|
CharString base_compute_defines;
|
||||||
|
|
||||||
|
String base_sha256;
|
||||||
|
|
||||||
|
static String shader_cache_dir;
|
||||||
|
static bool shader_cache_cleanup_on_start;
|
||||||
|
static bool shader_cache_save_compressed;
|
||||||
|
static bool shader_cache_save_compressed_zstd;
|
||||||
|
static bool shader_cache_save_debug;
|
||||||
|
bool shader_cache_dir_valid = false;
|
||||||
|
|
||||||
enum StageType {
|
enum StageType {
|
||||||
STAGE_TYPE_VERTEX,
|
STAGE_TYPE_VERTEX,
|
||||||
STAGE_TYPE_FRAGMENT,
|
STAGE_TYPE_FRAGMENT,
|
||||||
|
@ -113,6 +123,10 @@ class ShaderRD {
|
||||||
|
|
||||||
void _add_stage(const char *p_code, StageType p_stage_type);
|
void _add_stage(const char *p_code, StageType p_stage_type);
|
||||||
|
|
||||||
|
String _version_get_sha1(Version *p_version) const;
|
||||||
|
bool _load_from_cache(Version *p_version);
|
||||||
|
void _save_to_cache(Version *p_version);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
ShaderRD();
|
ShaderRD();
|
||||||
void setup(const char *p_vertex_code, const char *p_fragment_code, const char *p_compute_code, const char *p_name);
|
void setup(const char *p_vertex_code, const char *p_fragment_code, const char *p_compute_code, const char *p_name);
|
||||||
|
@ -148,6 +162,11 @@ public:
|
||||||
void set_variant_enabled(int p_variant, bool p_enabled);
|
void set_variant_enabled(int p_variant, bool p_enabled);
|
||||||
bool is_variant_enabled(int p_variant) const;
|
bool is_variant_enabled(int p_variant) const;
|
||||||
|
|
||||||
|
static void set_shader_cache_dir(const String &p_dir);
|
||||||
|
static void set_shader_cache_save_compressed(bool p_enable);
|
||||||
|
static void set_shader_cache_save_compressed_zstd(bool p_enable);
|
||||||
|
static void set_shader_cache_save_debug(bool p_enable);
|
||||||
|
|
||||||
RS::ShaderNativeSourceCode version_get_native_source_code(RID p_version);
|
RS::ShaderNativeSourceCode version_get_native_source_code(RID p_version);
|
||||||
|
|
||||||
void initialize(const Vector<String> &p_variant_defines, const String &p_general_defines = "");
|
void initialize(const Vector<String> &p_variant_defines, const String &p_general_defines = "");
|
||||||
|
|
|
@ -40,6 +40,7 @@ RenderingDevice *RenderingDevice::get_singleton() {
|
||||||
|
|
||||||
RenderingDevice::ShaderCompileFunction RenderingDevice::compile_function = nullptr;
|
RenderingDevice::ShaderCompileFunction RenderingDevice::compile_function = nullptr;
|
||||||
RenderingDevice::ShaderCacheFunction RenderingDevice::cache_function = nullptr;
|
RenderingDevice::ShaderCacheFunction RenderingDevice::cache_function = nullptr;
|
||||||
|
RenderingDevice::ShaderGetCacheKeyFunction RenderingDevice::get_cache_key_function = nullptr;
|
||||||
|
|
||||||
void RenderingDevice::shader_set_compile_function(ShaderCompileFunction p_function) {
|
void RenderingDevice::shader_set_compile_function(ShaderCompileFunction p_function) {
|
||||||
compile_function = p_function;
|
compile_function = p_function;
|
||||||
|
@ -49,6 +50,10 @@ void RenderingDevice::shader_set_cache_function(ShaderCacheFunction p_function)
|
||||||
cache_function = p_function;
|
cache_function = p_function;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void RenderingDevice::shader_set_get_cache_key_function(ShaderGetCacheKeyFunction p_function) {
|
||||||
|
get_cache_key_function = p_function;
|
||||||
|
}
|
||||||
|
|
||||||
Vector<uint8_t> RenderingDevice::shader_compile_from_source(ShaderStage p_stage, const String &p_source_code, ShaderLanguage p_language, String *r_error, bool p_allow_cache) {
|
Vector<uint8_t> RenderingDevice::shader_compile_from_source(ShaderStage p_stage, const String &p_source_code, ShaderLanguage p_language, String *r_error, bool p_allow_cache) {
|
||||||
if (p_allow_cache && cache_function) {
|
if (p_allow_cache && cache_function) {
|
||||||
Vector<uint8_t> cache = cache_function(p_stage, p_source_code, p_language);
|
Vector<uint8_t> cache = cache_function(p_stage, p_source_code, p_language);
|
||||||
|
@ -62,6 +67,13 @@ Vector<uint8_t> RenderingDevice::shader_compile_from_source(ShaderStage p_stage,
|
||||||
return compile_function(p_stage, p_source_code, p_language, r_error, &device_capabilities);
|
return compile_function(p_stage, p_source_code, p_language, r_error, &device_capabilities);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
String RenderingDevice::shader_get_cache_key() const {
|
||||||
|
if (get_cache_key_function) {
|
||||||
|
return get_cache_key_function(&device_capabilities);
|
||||||
|
}
|
||||||
|
return String();
|
||||||
|
}
|
||||||
|
|
||||||
RID RenderingDevice::_texture_create(const Ref<RDTextureFormat> &p_format, const Ref<RDTextureView> &p_view, const TypedArray<PackedByteArray> &p_data) {
|
RID RenderingDevice::_texture_create(const Ref<RDTextureFormat> &p_format, const Ref<RDTextureView> &p_view, const TypedArray<PackedByteArray> &p_data) {
|
||||||
ERR_FAIL_COND_V(p_format.is_null(), RID());
|
ERR_FAIL_COND_V(p_format.is_null(), RID());
|
||||||
ERR_FAIL_COND_V(p_view.is_null(), RID());
|
ERR_FAIL_COND_V(p_view.is_null(), RID());
|
||||||
|
|
|
@ -103,12 +103,14 @@ public:
|
||||||
bool supports_multiview = false; // If true this device supports multiview options
|
bool supports_multiview = false; // If true this device supports multiview options
|
||||||
};
|
};
|
||||||
|
|
||||||
|
typedef String (*ShaderGetCacheKeyFunction)(const Capabilities *p_capabilities);
|
||||||
typedef Vector<uint8_t> (*ShaderCompileFunction)(ShaderStage p_stage, const String &p_source_code, ShaderLanguage p_language, String *r_error, const Capabilities *p_capabilities);
|
typedef Vector<uint8_t> (*ShaderCompileFunction)(ShaderStage p_stage, const String &p_source_code, ShaderLanguage p_language, String *r_error, const Capabilities *p_capabilities);
|
||||||
typedef Vector<uint8_t> (*ShaderCacheFunction)(ShaderStage p_stage, const String &p_source_code, ShaderLanguage p_language);
|
typedef Vector<uint8_t> (*ShaderCacheFunction)(ShaderStage p_stage, const String &p_source_code, ShaderLanguage p_language);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static ShaderCompileFunction compile_function;
|
static ShaderCompileFunction compile_function;
|
||||||
static ShaderCacheFunction cache_function;
|
static ShaderCacheFunction cache_function;
|
||||||
|
static ShaderGetCacheKeyFunction get_cache_key_function;
|
||||||
|
|
||||||
static RenderingDevice *singleton;
|
static RenderingDevice *singleton;
|
||||||
|
|
||||||
|
@ -635,9 +637,11 @@ public:
|
||||||
const Capabilities *get_device_capabilities() const { return &device_capabilities; };
|
const Capabilities *get_device_capabilities() const { return &device_capabilities; };
|
||||||
|
|
||||||
virtual Vector<uint8_t> shader_compile_from_source(ShaderStage p_stage, const String &p_source_code, ShaderLanguage p_language = SHADER_LANGUAGE_GLSL, String *r_error = nullptr, bool p_allow_cache = true);
|
virtual Vector<uint8_t> shader_compile_from_source(ShaderStage p_stage, const String &p_source_code, ShaderLanguage p_language = SHADER_LANGUAGE_GLSL, String *r_error = nullptr, bool p_allow_cache = true);
|
||||||
|
virtual String shader_get_cache_key() const;
|
||||||
|
|
||||||
static void shader_set_compile_function(ShaderCompileFunction p_function);
|
static void shader_set_compile_function(ShaderCompileFunction p_function);
|
||||||
static void shader_set_cache_function(ShaderCacheFunction p_function);
|
static void shader_set_cache_function(ShaderCacheFunction p_function);
|
||||||
|
static void shader_set_get_cache_key_function(ShaderGetCacheKeyFunction p_function);
|
||||||
|
|
||||||
struct ShaderStageData {
|
struct ShaderStageData {
|
||||||
ShaderStage shader_stage;
|
ShaderStage shader_stage;
|
||||||
|
|
|
@ -2306,6 +2306,12 @@ RenderingServer::RenderingServer() {
|
||||||
"rendering/vulkan/rendering/back_end",
|
"rendering/vulkan/rendering/back_end",
|
||||||
PROPERTY_HINT_ENUM, "ForwardClustered,ForwardMobile"));
|
PROPERTY_HINT_ENUM, "ForwardClustered,ForwardMobile"));
|
||||||
|
|
||||||
|
GLOBAL_DEF("rendering/shader_compiler/shader_cache/enabled", true);
|
||||||
|
GLOBAL_DEF("rendering/shader_compiler/shader_cache/compress", true);
|
||||||
|
GLOBAL_DEF("rendering/shader_compiler/shader_cache/use_zstd_compression", true);
|
||||||
|
GLOBAL_DEF("rendering/shader_compiler/shader_cache/strip_debug", false);
|
||||||
|
GLOBAL_DEF("rendering/shader_compiler/shader_cache/strip_debug.release", true);
|
||||||
|
|
||||||
GLOBAL_DEF("rendering/reflections/sky_reflections/roughness_layers", 8);
|
GLOBAL_DEF("rendering/reflections/sky_reflections/roughness_layers", 8);
|
||||||
GLOBAL_DEF("rendering/reflections/sky_reflections/texture_array_reflections", true);
|
GLOBAL_DEF("rendering/reflections/sky_reflections/texture_array_reflections", true);
|
||||||
GLOBAL_DEF("rendering/reflections/sky_reflections/texture_array_reflections.mobile", false);
|
GLOBAL_DEF("rendering/reflections/sky_reflections/texture_array_reflections.mobile", false);
|
||||||
|
|
5
thirdparty/README.md
vendored
5
thirdparty/README.md
vendored
|
@ -469,6 +469,10 @@ Collection of single-file libraries used in Godot components.
|
||||||
* Version: git (2f625846a775501fb69456567409a8b12f10ea25, 2012)
|
* Version: git (2f625846a775501fb69456567409a8b12f10ea25, 2012)
|
||||||
* License: BSD-3-Clause
|
* License: BSD-3-Clause
|
||||||
* Modifications: use `const char*` instead of `char*` for input string
|
* Modifications: use `const char*` instead of `char*` for input string
|
||||||
|
- `smolv.h`
|
||||||
|
* Upstream: https://github.com/aras-p/smol-v
|
||||||
|
* Version: git (4b52c165c13763051a18e80ffbc2ee436314ceb2, 2020)
|
||||||
|
* License: Public Domain or MIT
|
||||||
- `stb_rect_pack.h`
|
- `stb_rect_pack.h`
|
||||||
* Upstream: https://github.com/nothings/stb
|
* Upstream: https://github.com/nothings/stb
|
||||||
* Version: 1.00 (2bb4a0accd4003c1db4c24533981e01b1adfd656, 2019)
|
* Version: 1.00 (2bb4a0accd4003c1db4c24533981e01b1adfd656, 2019)
|
||||||
|
@ -731,3 +735,4 @@ Files extracted from upstream source:
|
||||||
|
|
||||||
- lib/{common/,compress/,decompress/,zstd.h}
|
- lib/{common/,compress/,decompress/,zstd.h}
|
||||||
- LICENSE
|
- LICENSE
|
||||||
|
|
||||||
|
|
2108
thirdparty/misc/smolv.cpp
vendored
Normal file
2108
thirdparty/misc/smolv.cpp
vendored
Normal file
File diff suppressed because it is too large
Load diff
169
thirdparty/misc/smolv.h
vendored
Normal file
169
thirdparty/misc/smolv.h
vendored
Normal file
|
@ -0,0 +1,169 @@
|
||||||
|
// smol-v - public domain - https://github.com/aras-p/smol-v
|
||||||
|
// authored 2016-2020 by Aras Pranckevicius
|
||||||
|
// no warranty implied; use at your own risk
|
||||||
|
// See end of file for license information.
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// ### OVERVIEW:
|
||||||
|
//
|
||||||
|
// SMOL-V encodes Vulkan/Khronos SPIR-V format programs into a form that is smaller, and is more
|
||||||
|
// compressible. Normally no changes to the programs are done; they decode
|
||||||
|
// into exactly same program as what was encoded. Optionally, debug information
|
||||||
|
// can be removed too.
|
||||||
|
//
|
||||||
|
// SPIR-V is a very verbose format, several times larger than same programs expressed in other
|
||||||
|
// shader formats (e.g. DX11 bytecode, GLSL, DX9 bytecode etc.). The SSA-form with ever increasing
|
||||||
|
// IDs is not very appreciated by regular data compressors either. SMOL-V does several things
|
||||||
|
// to improve this:
|
||||||
|
// - Many words, especially ones that most often have small values, are encoded using
|
||||||
|
// "varint" scheme (1-5 bytes per word, with just one byte for values in 0..127 range).
|
||||||
|
// See https://developers.google.com/protocol-buffers/docs/encoding
|
||||||
|
// - Some IDs used in the program are delta-encoded, relative to previously seen IDs (e.g. Result
|
||||||
|
// IDs). Often instructions reference things that were computed just before, so this results in
|
||||||
|
// small deltas. These values are also encoded using "varint" scheme.
|
||||||
|
// - Reordering instruction opcodes so that the most common ones are the smallest values, for smaller
|
||||||
|
// varint encoding.
|
||||||
|
// - Encoding several instructions in a more compact form, e.g. the "typical <=4 component swizzle"
|
||||||
|
// shape of a VectorShuffle instruction, or sequences of MemberDecorate instructions.
|
||||||
|
//
|
||||||
|
// A somewhat similar utility is spirv-remap from glslang, see
|
||||||
|
// https://github.com/KhronosGroup/glslang/blob/master/README-spirv-remap.txt
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// ### USAGE:
|
||||||
|
//
|
||||||
|
// Add source/smolv.h and source/smolv.cpp to your C++ project build.
|
||||||
|
// Currently it might require C++11 or somesuch; I only tested with Visual Studio 2017/2019, Mac Xcode 11 and Gcc 5.4.
|
||||||
|
//
|
||||||
|
// smolv::Encode and smolv::Decode is the basic functionality.
|
||||||
|
//
|
||||||
|
// Other functions are for development/statistics purposes, to figure out frequencies and
|
||||||
|
// distributions of the instructions.
|
||||||
|
//
|
||||||
|
// There's a test + compression benchmarking suite in testing/testmain.cpp; using that needs adding
|
||||||
|
// other files under testing/external to the build too (3rd party code: glslang remapper, Zstd, LZ4).
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// ### LIMITATIONS / TODO:
|
||||||
|
//
|
||||||
|
// - SPIR-V where the words got stored in big-endian layout is not supported yet.
|
||||||
|
// - The whole thing might not work on Big-Endian CPUs. It might, but I'm not 100% sure.
|
||||||
|
// - Not much prevention is done against malformed/corrupted inputs, TODO.
|
||||||
|
// - Out of memory cases are not handled. The code will either throw exception
|
||||||
|
// or crash, depending on your compilation flags.
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <vector>
|
||||||
|
#include <cstddef>
|
||||||
|
|
||||||
|
namespace smolv
|
||||||
|
{
|
||||||
|
typedef std::vector<uint8_t> ByteArray;
|
||||||
|
|
||||||
|
enum EncodeFlags
|
||||||
|
{
|
||||||
|
kEncodeFlagNone = 0,
|
||||||
|
kEncodeFlagStripDebugInfo = (1<<0), // Strip all optional SPIR-V instructions (debug names etc.)
|
||||||
|
};
|
||||||
|
enum DecodeFlags
|
||||||
|
{
|
||||||
|
kDecodeFlagNone = 0,
|
||||||
|
kDecodeFlagUse20160831AsZeroVersion = (1 << 0), // For "version zero" of SMOL-V encoding, use 2016 08 31 code path (this is what happens to be used by Unity 2017-2020)
|
||||||
|
};
|
||||||
|
|
||||||
|
// Preserve *some* OpName debug names.
|
||||||
|
// Return true to preserve, false to strip.
|
||||||
|
// This is really only used to implement a workaround for problems with some Vulkan drivers.
|
||||||
|
typedef bool(*StripOpNameFilterFunc)(const char* name);
|
||||||
|
|
||||||
|
// -------------------------------------------------------------------
|
||||||
|
// Encoding / Decoding
|
||||||
|
|
||||||
|
// Encode SPIR-V into SMOL-V.
|
||||||
|
//
|
||||||
|
// Resulting data is appended to outSmolv array (the array is not cleared).
|
||||||
|
//
|
||||||
|
// flags is bitset of EncodeFlags values.
|
||||||
|
//
|
||||||
|
// Returns false on malformed SPIR-V input; if that happens the output array might get
|
||||||
|
// partial/broken SMOL-V program.
|
||||||
|
bool Encode(const void* spirvData, size_t spirvSize, ByteArray& outSmolv, uint32_t flags = kEncodeFlagNone, StripOpNameFilterFunc stripFilter = 0);
|
||||||
|
|
||||||
|
|
||||||
|
// Decode SMOL-V into SPIR-V.
|
||||||
|
//
|
||||||
|
// Resulting data is written into the passed buffer. Get required buffer space with
|
||||||
|
// GetDecodeBufferSize; this is the size of decoded SPIR-V program.
|
||||||
|
//
|
||||||
|
// flags is bitset of DecodeFlags values.
|
||||||
|
|
||||||
|
// Decoding does no memory allocations.
|
||||||
|
//
|
||||||
|
// Returns false on malformed input; if that happens the output buffer might be only partially
|
||||||
|
// written to.
|
||||||
|
bool Decode(const void* smolvData, size_t smolvSize, void* spirvOutputBuffer, size_t spirvOutputBufferSize, uint32_t flags = kDecodeFlagNone);
|
||||||
|
|
||||||
|
|
||||||
|
// Given a SMOL-V program, get size of the decoded SPIR-V program.
|
||||||
|
// This is the buffer size that Decode expects.
|
||||||
|
//
|
||||||
|
// Returns zero on malformed input (just checks the header, not the full input).
|
||||||
|
size_t GetDecodedBufferSize(const void* smolvData, size_t smolvSize);
|
||||||
|
|
||||||
|
|
||||||
|
// -------------------------------------------------------------------
|
||||||
|
// Computing instruction statistics on SPIR-V/SMOL-V programs
|
||||||
|
|
||||||
|
struct Stats;
|
||||||
|
|
||||||
|
Stats* StatsCreate();
|
||||||
|
void StatsDelete(Stats* s);
|
||||||
|
|
||||||
|
bool StatsCalculate(Stats* stats, const void* spirvData, size_t spirvSize);
|
||||||
|
bool StatsCalculateSmol(Stats* stats, const void* smolvData, size_t smolvSize);
|
||||||
|
void StatsPrint(const Stats* stats);
|
||||||
|
|
||||||
|
} // namespace smolv
|
||||||
|
|
||||||
|
|
||||||
|
// ------------------------------------------------------------------------------
|
||||||
|
// This software is available under 2 licenses -- choose whichever you prefer.
|
||||||
|
// ------------------------------------------------------------------------------
|
||||||
|
// ALTERNATIVE A - MIT License
|
||||||
|
// Copyright (c) 2016-2020 Aras Pranckevicius
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||||
|
// this software and associated documentation files (the "Software"), to deal in
|
||||||
|
// the Software without restriction, including without limitation the rights to
|
||||||
|
// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||||
|
// of the Software, and to permit persons to whom the Software is furnished to do
|
||||||
|
// so, subject to the following conditions:
|
||||||
|
// The above copyright notice and this permission notice shall be included in all
|
||||||
|
// copies or substantial portions of the Software.
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
// SOFTWARE.
|
||||||
|
// ------------------------------------------------------------------------------
|
||||||
|
// ALTERNATIVE B - Public Domain (www.unlicense.org)
|
||||||
|
// This is free and unencumbered software released into the public domain.
|
||||||
|
// Anyone is free to copy, modify, publish, use, compile, sell, or distribute this
|
||||||
|
// software, either in source code form or as a compiled binary, for any purpose,
|
||||||
|
// commercial or non-commercial, and by any means.
|
||||||
|
// In jurisdictions that recognize copyright laws, the author or authors of this
|
||||||
|
// software dedicate any and all copyright interest in the software to the public
|
||||||
|
// domain. We make this dedication for the benefit of the public at large and to
|
||||||
|
// the detriment of our heirs and successors. We intend this dedication to be an
|
||||||
|
// overt act of relinquishment in perpetuity of all present and future rights to
|
||||||
|
// this software under copyright law.
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
// AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||||
|
// ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||||
|
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
// ------------------------------------------------------------------------------
|
Loading…
Reference in a new issue