From aca6a61c3d477c2c9f9acdbe5e4fc66f95da7d90 Mon Sep 17 00:00:00 2001 From: Relintai Date: Mon, 17 May 2021 22:27:10 +0200 Subject: [PATCH] Added a PropTextureCache singleton, and a PropTextureJob class. --- SCsub | 3 + jobs/prop_texture_job.cpp | 174 +++++++++++++++++++++++++++ jobs/prop_texture_job.h | 112 +++++++++++++++++ props/prop_data_entry.cpp | 5 + props/prop_data_entry.h | 5 +- register_types.cpp | 14 +++ singleton/prop_texture_cache.cpp | 199 +++++++++++++++++++++++++++++++ singleton/prop_texture_cache.h | 87 ++++++++++++++ 8 files changed, 595 insertions(+), 4 deletions(-) create mode 100644 jobs/prop_texture_job.cpp create mode 100644 jobs/prop_texture_job.h create mode 100644 singleton/prop_texture_cache.cpp create mode 100644 singleton/prop_texture_cache.h diff --git a/SCsub b/SCsub index 70bb897..9bfeee7 100644 --- a/SCsub +++ b/SCsub @@ -42,11 +42,14 @@ sources = [ "prop_scene_instance.cpp", "singleton/prop_utils.cpp", + "singleton/prop_texture_cache.cpp", "editor/prop_editor_plugin.cpp", "prop_mesher.cpp", + "jobs/prop_texture_job.cpp", + "prop_mesher_job_step.cpp", ] diff --git a/jobs/prop_texture_job.cpp b/jobs/prop_texture_job.cpp new file mode 100644 index 0000000..1021190 --- /dev/null +++ b/jobs/prop_texture_job.cpp @@ -0,0 +1,174 @@ +/* +Copyright (c) 2019-2021 Péter Magyar + +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 "prop_texture_job.h" + +#if TEXTURE_PACKER_PRESENT +#include "../../texture_packer/texture_packer.h" +#endif + +#if TEXTURE_PACKER_PRESENT +Ref PropTextureJob::get_merger() { + return _merger; +} + +void PropTextureJob::set_merger(const Ref &merger) { + _merger = merger; +} +#endif + +void PropTextureJob::_execute() { +#if TEXTURE_PACKER_PRESENT + if (!_merger.is_valid()) { + set_complete(true); + return; + } + + _merger->merge(); +#endif + + set_complete(true); +} + +PropTextureJob::PropTextureJob() { +#if !THREAD_POOL_PRESENT + _complete = true; + _cancelled = false; + + _max_allocated_time = 0; + _start_time = 0; + + _current_run_stage = 0; + _stage = 0; +#endif +} + +PropTextureJob::~PropTextureJob() { +} + +void PropTextureJob::_bind_methods() { +#if TEXTURE_PACKER_PRESENT + ClassDB::bind_method(D_METHOD("get_merger"), &PropTextureJob::get_merger); + ClassDB::bind_method(D_METHOD("set_merger", "value"), &PropTextureJob::set_merger); + ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "merger", PROPERTY_HINT_RESOURCE_TYPE, "TexturePacker"), "set_merger", "get_merger"); +#endif + + ClassDB::bind_method(D_METHOD("_execute"), &PropTextureJob::_execute); + +#if !THREAD_POOL_PRESENT + ClassDB::bind_method(D_METHOD("get_complete"), &PropTextureJob::get_complete); + ClassDB::bind_method(D_METHOD("set_complete", "value"), &PropTextureJob::set_complete); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "complete"), "set_complete", "get_complete"); + + ClassDB::bind_method(D_METHOD("get_start_time"), &PropTextureJob::get_start_time); + ClassDB::bind_method(D_METHOD("set_start_time", "value"), &PropTextureJob::set_start_time); + ADD_PROPERTY(PropertyInfo(Variant::INT, "start_time"), "set_start_time", "get_start_time"); + + ClassDB::bind_method(D_METHOD("get_current_run_stage"), &PropTextureJob::get_current_run_stage); + ClassDB::bind_method(D_METHOD("set_current_run_stage", "value"), &PropTextureJob::set_current_run_stage); + ADD_PROPERTY(PropertyInfo(Variant::INT, "current_run_stage"), "set_current_run_stage", "get_current_run_stage"); + + ClassDB::bind_method(D_METHOD("get_stage"), &PropTextureJob::get_stage); + ClassDB::bind_method(D_METHOD("set_stage", "value"), &PropTextureJob::set_stage); + ADD_PROPERTY(PropertyInfo(Variant::INT, "stage"), "set_stage", "get_stage"); + + ClassDB::bind_method(D_METHOD("get_current_execution_time"), &PropTextureJob::get_current_execution_time); + + ClassDB::bind_method(D_METHOD("should_do", "just_check"), &PropTextureJob::should_do, DEFVAL(false)); + ClassDB::bind_method(D_METHOD("should_return"), &PropTextureJob::should_return); + + BIND_VMETHOD(MethodInfo("_execute")); + ClassDB::bind_method(D_METHOD("execute"), &PropTextureJob::execute); + + ADD_SIGNAL(MethodInfo("completed")); +#endif +} + +#if !THREAD_POOL_PRESENT +bool PropTextureJob::get_complete() const { + return _complete; +} +void PropTextureJob::set_complete(const bool value) { + _complete = value; +} + +bool PropTextureJob::get_cancelled() const { + return _cancelled; +} +void PropTextureJob::set_cancelled(const bool value) { + _cancelled = value; +} + +float PropTextureJob::get_max_allocated_time() const { + return _max_allocated_time; +} +void PropTextureJob::set_max_allocated_time(const float value) { + _max_allocated_time = value; +} + +int PropTextureJob::get_start_time() const { + return _start_time; +} +void PropTextureJob::set_start_time(const int value) { + _start_time = value; +} + +int PropTextureJob::get_current_run_stage() const { + return _current_run_stage; +} +void PropTextureJob::set_current_run_stage(const int value) { + _current_run_stage = value; +} + +int PropTextureJob::get_stage() const { + return _stage; +} +void PropTextureJob::set_stage(const int value) { + _stage = value; +} + +void PropTextureJob::reset_stages() { + _current_run_stage = 0; + _stage = 0; +} + +float PropTextureJob::get_current_execution_time() { + return 0; +} + +bool PropTextureJob::should_do(const bool just_check) { + return true; +} +bool PropTextureJob::should_return() { + if (_cancelled) + return true; + + return false; +} + +void PropTextureJob::execute() { + ERR_FAIL_COND(!has_method("_execute")); + + call("_execute"); +} + +#endif \ No newline at end of file diff --git a/jobs/prop_texture_job.h b/jobs/prop_texture_job.h new file mode 100644 index 0000000..95c3208 --- /dev/null +++ b/jobs/prop_texture_job.h @@ -0,0 +1,112 @@ +/* +Copyright (c) 2019-2021 Péter Magyar + +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 PROP_TEXTURE_JOB +#define PROP_TEXTURE_JOB + +#include "scene/resources/texture.h" + +#if THREAD_POOL_PRESENT +#include "../../thread_pool/thread_pool_job.h" +#endif + +#include "core/version.h" + +#if VERSION_MAJOR > 3 +#include "core/object/reference.h" +#define Texture Texture2D +#else +#include "core/reference.h" +#endif + +#if TEXTURE_PACKER_PRESENT +class TexturePacker; +#endif + +#if THREAD_POOL_PRESENT +class PropTextureJob : public ThreadPoolJob { + GDCLASS(PropTextureJob, ThreadPoolJob); +#else +class PropTextureJob : public Reference { + GDCLASS(PropTextureJob, Reference); +#endif + +public: +#if TEXTURE_PACKER_PRESENT + Ref get_merger(); + void set_merger(const Ref &merger); +#endif + + void _execute(); + + PropTextureJob(); + ~PropTextureJob(); + +protected: + static void _bind_methods(); + +#if TEXTURE_PACKER_PRESENT + Ref _merger; +#endif + +public: +#if !THREAD_POOL_PRESENT + bool get_complete() const; + void set_complete(const bool value); + + bool get_cancelled() const; + void set_cancelled(const bool value); + + float get_max_allocated_time() const; + void set_max_allocated_time(const float value); + + int get_start_time() const; + void set_start_time(const int value); + + int get_current_run_stage() const; + void set_current_run_stage(const int value); + + int get_stage() const; + void set_stage(const int value); + + void reset_stages(); + + float get_current_execution_time(); + + bool should_do(const bool just_check = false); + bool should_return(); + + void execute(); + +private: + bool _complete; + bool _cancelled; + + float _max_allocated_time; + uint64_t _start_time; + + int _current_run_stage; + int _stage; +#endif +}; + +#endif diff --git a/props/prop_data_entry.cpp b/props/prop_data_entry.cpp index 66241d6..0d30d75 100644 --- a/props/prop_data_entry.cpp +++ b/props/prop_data_entry.cpp @@ -33,6 +33,11 @@ SOFTWARE. #define Spatial Node3D #endif +#if TEXTURE_PACKER_PRESENT +#include "../../texture_packer/texture_packer.h" +#endif + + #include "../prop_mesher.h" Transform PropDataEntry::get_transform() const { diff --git a/props/prop_data_entry.h b/props/prop_data_entry.h index cafb28f..88329b6 100644 --- a/props/prop_data_entry.h +++ b/props/prop_data_entry.h @@ -33,12 +33,9 @@ SOFTWARE. #include "core/math/transform.h" -#if TEXTURE_PACKER_PRESENT -#include "../../texture_packer/texture_packer.h" -#endif - class PropData; class PropMesher; +class TexturePacker; class PropDataEntry : public Resource { GDCLASS(PropDataEntry, Resource); diff --git a/register_types.cpp b/register_types.cpp index 072aa1a..8a99f7c 100644 --- a/register_types.cpp +++ b/register_types.cpp @@ -46,10 +46,13 @@ SOFTWARE. #include "prop_instance_job.h" #include "prop_instance_prop_job.h" +#include "jobs/prop_texture_job.h" + #include "prop_scene_instance.h" #include "prop_mesher_job_step.h" +#include "singleton/prop_texture_cache.h" #include "singleton/prop_utils.h" #include "./editor/prop_editor_plugin.h" @@ -57,6 +60,7 @@ SOFTWARE. #include "prop_mesher.h" static PropUtils *prop_utils = NULL; +static PropTextureCache *prop_texture_cache = NULL; void register_props_types() { ClassDB::register_class(); @@ -79,12 +83,18 @@ void register_props_types() { ClassDB::register_class(); ClassDB::register_class(); + ClassDB::register_class(); + ClassDB::register_class(); prop_utils = memnew(PropUtils); ClassDB::register_class(); Engine::get_singleton()->add_singleton(Engine::Singleton("PropUtils", PropUtils::get_singleton())); + prop_texture_cache = memnew(PropTextureCache); + ClassDB::register_class(); + Engine::get_singleton()->add_singleton(Engine::Singleton("PropTextureCache", PropTextureCache::get_singleton())); + Ref light_processor = Ref(memnew(PropDataLight)); PropUtils::add_processor(light_processor); @@ -103,4 +113,8 @@ void unregister_props_types() { if (prop_utils) { memdelete(prop_utils); } + + if (prop_texture_cache) { + memdelete(prop_texture_cache); + } } diff --git a/singleton/prop_texture_cache.cpp b/singleton/prop_texture_cache.cpp new file mode 100644 index 0000000..c02aec0 --- /dev/null +++ b/singleton/prop_texture_cache.cpp @@ -0,0 +1,199 @@ +/* +Copyright (c) 2019-2021 Péter Magyar + +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 "prop_texture_cache.h" + +#include "../props/prop_data.h" +#include "../props/prop_data_entry.h" + +#include "core/version.h" + +#if VERSION_MAJOR > 3 +#include "core/config/engine.h" +#else +#include "core/engine.h" +#endif + +#include "../jobs/prop_texture_job.h" + +#if THREAD_POOL_PRESENT +#include "../../thread_pool/thread_pool.h" +#endif + +#if TEXTURE_PACKER_PRESENT +#include "../../texture_packer/texture_packer.h" +#endif + +PropTextureCache *PropTextureCache::_instance; + +PropTextureCache *PropTextureCache::get_singleton() { + return _instance; +} + +#if TEXTURE_PACKER_PRESENT +bool PropTextureCache::has_texture(const Ref &prop) { + for (int i = 0; i < _entries.size(); ++i) { + if (_entries[i].prop == prop) { + return true; + } + } + + return false; +} + +void PropTextureCache::set_texture(const Ref &prop, const Ref &merger) { + for (int i = 0; i < _entries.size(); ++i) { + PropTextureCacheEntry &e = _entries.write[i]; + + if (e.prop == prop) { + e.merger = merger; + } + } +} + +Ref PropTextureCache::get_texture(const Ref &prop) { + for (int i = 0; i < _entries.size(); ++i) { + PropTextureCacheEntry &e = _entries.write[i]; + + if (e.prop == prop) { + e.refcount++; + + return e.merger; + } + } + + return Ref(); +} + +void PropTextureCache::ref_texture(const Ref &prop) { + for (int i = 0; i < _entries.size(); ++i) { + PropTextureCacheEntry &e = _entries.write[i]; + + if (e.prop == prop) { + e.refcount++; + + return; + } + } +} + +void PropTextureCache::unref_texture(const Ref &prop) { + for (int i = 0; i < _entries.size(); ++i) { + PropTextureCacheEntry &e = _entries.write[i]; + + if (e.prop == prop) { + e.refcount--; + + if (e.refcount <= 0) { + _entries.remove(i); + } + + return; + } + } +} + +Ref PropTextureCache::create_texture(const Ref &prop) { + ERR_FAIL_COND_V(has_texture(prop), Ref()); + + Ref merger; + merger.instance(); + + for (int i = 0; i < prop->get_prop_count(); ++i) { + Ref e = prop->get_prop(i); + + e->add_textures_into(merger); + } + + PropTextureCacheEntry e; + e.merger = merger; + e.prop = prop; + e.refcount = 1; + + _entries.push_back(e); + + return merger; +} + +Ref PropTextureCache::get_or_create_texture_immediate(const Ref &prop) { + if (!has_texture(prop)) { + + Ref merger = create_texture(prop); + + merger->merge(); + + return merger; + } + + return get_texture(prop); +} + +Ref PropTextureCache::get_or_create_texture_threaded(const Ref &prop) { +#if THREAD_POOL_PRESENT + + if (!has_texture(prop)) { + + Ref merger = create_texture(prop); + + Ref job; + job.instance(); + job->set_merger(merger); + ThreadPool::get_singleton()->add_job(job); + + return merger; + } + + return get_texture(prop); + +#else + return get_or_create_texture_immediate(prop); +#endif +} + +#endif + +PropTextureCache::PropTextureCache() { + _instance = this; +} + +PropTextureCache::~PropTextureCache() { + _instance = NULL; +#if TEXTURE_PACKER_PRESENT + _entries.clear(); +#endif +} + +void PropTextureCache::_bind_methods() { +#if TEXTURE_PACKER_PRESENT + ClassDB::bind_method(D_METHOD("has_texture", "prop"), &PropTextureCache::has_texture); + ClassDB::bind_method(D_METHOD("set_texture", "prop", "merger"), &PropTextureCache::set_texture); + + ClassDB::bind_method(D_METHOD("get_texture", "prop"), &PropTextureCache::get_texture); + + ClassDB::bind_method(D_METHOD("ref_texture", "prop"), &PropTextureCache::ref_texture); + ClassDB::bind_method(D_METHOD("unref_texture", "prop"), &PropTextureCache::unref_texture); + + ClassDB::bind_method(D_METHOD("create_texture", "prop"), &PropTextureCache::create_texture); + ClassDB::bind_method(D_METHOD("get_or_create_texture_immediate", "prop"), &PropTextureCache::get_or_create_texture_immediate); + ClassDB::bind_method(D_METHOD("get_or_create_texture_threaded", "prop"), &PropTextureCache::get_or_create_texture_threaded); +#endif +} diff --git a/singleton/prop_texture_cache.h b/singleton/prop_texture_cache.h new file mode 100644 index 0000000..385eadb --- /dev/null +++ b/singleton/prop_texture_cache.h @@ -0,0 +1,87 @@ +/* +Copyright (c) 2019-2021 Péter Magyar + +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 PROP_TEXTURE_CACHE_H +#define PROP_TEXTURE_CACHE_H + +#include "core/version.h" + +#if VERSION_MAJOR > 3 +#include "core/object/object.h" +#include "core/object/reference.h" +#include "core/templates/hash_map.h" +#include "core/templates/vector.h" +#else +#include "core/hash_map.h" +#include "core/object.h" +#include "core/reference.h" +#include "core/vector.h" +#endif + +#include "../props/prop_data.h" + +#if TEXTURE_PACKER_PRESENT +class TexturePacker; +#endif + +class PropTextureCache : public Object { + GDCLASS(PropTextureCache, Object); + +#if TEXTURE_PACKER_PRESENT +public: + struct PropTextureCacheEntry { + int refcount; + Ref merger; + Ref prop; + }; + +public: + static PropTextureCache *get_singleton(); + + bool has_texture(const Ref &prop); + void set_texture(const Ref &prop, const Ref &merger); + + Ref get_texture(const Ref &prop); + + void ref_texture(const Ref &prop); + void unref_texture(const Ref &prop); + + Ref create_texture(const Ref &prop); + Ref get_or_create_texture_immediate(const Ref &prop); + Ref get_or_create_texture_threaded(const Ref &prop); + +private: + Vector _entries; + + static PropTextureCache *_instance; + +#endif + +public: + PropTextureCache(); + ~PropTextureCache(); + +protected: + static void _bind_methods(); +}; + +#endif