From 21ade7f0f76f33214c7c214a3e87f98bdfb94fdb Mon Sep 17 00:00:00 2001 From: clayjohn Date: Fri, 19 Jan 2024 19:19:16 -0800 Subject: [PATCH] Add DummyShader handling to Dummy RenderingServer to ensure shader parameters are saved in headless export --- .../dummy/storage/material_storage.cpp | 136 ++++++++++++++++++ .../dummy/storage/material_storage.h | 28 +++- .../rendering/dummy/storage/mesh_storage.h | 4 +- .../rendering/dummy/storage/texture_storage.h | 4 +- servers/rendering/renderer_scene_cull.cpp | 2 +- 5 files changed, 162 insertions(+), 12 deletions(-) create mode 100644 servers/rendering/dummy/storage/material_storage.cpp diff --git a/servers/rendering/dummy/storage/material_storage.cpp b/servers/rendering/dummy/storage/material_storage.cpp new file mode 100644 index 00000000000..5a2c135ff54 --- /dev/null +++ b/servers/rendering/dummy/storage/material_storage.cpp @@ -0,0 +1,136 @@ +/**************************************************************************/ +/* material_storage.cpp */ +/**************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/**************************************************************************/ +/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ +/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* */ +/* 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 "material_storage.h" + +using namespace RendererDummy; + +MaterialStorage *MaterialStorage::singleton = nullptr; + +MaterialStorage::MaterialStorage() { + singleton = this; + ShaderCompiler::DefaultIdentifierActions actions; + dummy_compiler.initialize(actions); +} + +MaterialStorage::~MaterialStorage() { + singleton = nullptr; +} + +RID MaterialStorage::shader_allocate() { + return shader_owner.allocate_rid(); +} + +void MaterialStorage::shader_initialize(RID p_rid) { + shader_owner.initialize_rid(p_rid, DummyShader()); +} + +void MaterialStorage::shader_free(RID p_rid) { + DummyShader *shader = shader_owner.get_or_null(p_rid); + ERR_FAIL_NULL(shader); + + shader_owner.free(p_rid); +} + +void MaterialStorage::shader_set_code(RID p_shader, const String &p_code) { + DummyShader *shader = shader_owner.get_or_null(p_shader); + ERR_FAIL_NULL(shader); + if (p_code.is_empty()) { + return; + } + + String mode_string = ShaderLanguage::get_shader_type(p_code); + + RS::ShaderMode new_mode; + if (mode_string == "canvas_item") { + new_mode = RS::SHADER_CANVAS_ITEM; + } else if (mode_string == "particles") { + new_mode = RS::SHADER_PARTICLES; + } else if (mode_string == "spatial") { + new_mode = RS::SHADER_SPATIAL; + } else if (mode_string == "sky") { + new_mode = RS::SHADER_SKY; + } else if (mode_string == "fog") { + new_mode = RS::SHADER_FOG; + } else { + new_mode = RS::SHADER_MAX; + } + ShaderCompiler::IdentifierActions actions; + actions.uniforms = &shader->uniforms; + ShaderCompiler::GeneratedCode gen_code; + + Error err = MaterialStorage::get_singleton()->dummy_compiler.compile(new_mode, p_code, &actions, "", gen_code); + ERR_FAIL_COND_MSG(err != OK, "Shader compilation failed."); +} + +void MaterialStorage::get_shader_parameter_list(RID p_shader, List *p_param_list) const { + DummyShader *shader = shader_owner.get_or_null(p_shader); + ERR_FAIL_NULL(shader); + + SortArray, ShaderLanguage::UniformOrderComparator> sorter; + LocalVector> filtered_uniforms; + + for (const KeyValue &E : shader->uniforms) { + if (E.value.scope != ShaderLanguage::ShaderNode::Uniform::SCOPE_LOCAL) { + continue; + } + if (E.value.texture_order >= 0) { + filtered_uniforms.push_back(Pair(E.key, E.value.texture_order + 100000)); + } else { + filtered_uniforms.push_back(Pair(E.key, E.value.order)); + } + } + int uniform_count = filtered_uniforms.size(); + sorter.sort(filtered_uniforms.ptr(), uniform_count); + + String last_group; + for (int i = 0; i < uniform_count; i++) { + const StringName &uniform_name = filtered_uniforms[i].first; + const ShaderLanguage::ShaderNode::Uniform &uniform = shader->uniforms[uniform_name]; + + String group = uniform.group; + if (!uniform.subgroup.is_empty()) { + group += "::" + uniform.subgroup; + } + + if (group != last_group) { + PropertyInfo pi; + pi.usage = PROPERTY_USAGE_GROUP; + pi.name = group; + p_param_list->push_back(pi); + + last_group = group; + } + + PropertyInfo pi = ShaderLanguage::uniform_to_property_info(uniform); + pi.name = uniform_name; + p_param_list->push_back(pi); + } +} diff --git a/servers/rendering/dummy/storage/material_storage.h b/servers/rendering/dummy/storage/material_storage.h index e8766b4a21a..4fd178ac88a 100644 --- a/servers/rendering/dummy/storage/material_storage.h +++ b/servers/rendering/dummy/storage/material_storage.h @@ -31,13 +31,31 @@ #ifndef MATERIAL_STORAGE_DUMMY_H #define MATERIAL_STORAGE_DUMMY_H +#include "servers/rendering/shader_compiler.h" +#include "servers/rendering/shader_language.h" #include "servers/rendering/storage/material_storage.h" #include "servers/rendering/storage/utilities.h" namespace RendererDummy { class MaterialStorage : public RendererMaterialStorage { +private: + static MaterialStorage *singleton; + + struct DummyShader { + HashMap uniforms; + }; + + mutable RID_Owner shader_owner; + + ShaderCompiler dummy_compiler; + public: + static MaterialStorage *get_singleton() { return singleton; } + + MaterialStorage(); + ~MaterialStorage(); + /* GLOBAL SHADER UNIFORM API */ virtual void global_shader_parameter_add(const StringName &p_name, RS::GlobalShaderParameterType p_type, const Variant &p_value) override {} @@ -58,15 +76,15 @@ public: /* SHADER API */ - virtual RID shader_allocate() override { return RID(); } - virtual void shader_initialize(RID p_rid) override {} - virtual void shader_free(RID p_rid) override{}; + virtual RID shader_allocate() override; + virtual void shader_initialize(RID p_rid) override; + virtual void shader_free(RID p_rid) override; - virtual void shader_set_code(RID p_shader, const String &p_code) override {} + virtual void shader_set_code(RID p_shader, const String &p_code) override; virtual void shader_set_path_hint(RID p_shader, const String &p_code) override {} virtual String shader_get_code(RID p_shader) const override { return ""; } - virtual void get_shader_parameter_list(RID p_shader, List *p_param_list) const override {} + virtual void get_shader_parameter_list(RID p_shader, List *p_param_list) const override; virtual void shader_set_default_texture_parameter(RID p_shader, const StringName &p_name, RID p_texture, int p_index) override {} virtual RID shader_get_default_texture_parameter(RID p_shader, const StringName &p_name, int p_index) const override { return RID(); } diff --git a/servers/rendering/dummy/storage/mesh_storage.h b/servers/rendering/dummy/storage/mesh_storage.h index 89cccec54b5..18be9393cc7 100644 --- a/servers/rendering/dummy/storage/mesh_storage.h +++ b/servers/rendering/dummy/storage/mesh_storage.h @@ -51,9 +51,7 @@ private: mutable RID_Owner mesh_owner; public: - static MeshStorage *get_singleton() { - return singleton; - }; + static MeshStorage *get_singleton() { return singleton; } MeshStorage(); ~MeshStorage(); diff --git a/servers/rendering/dummy/storage/texture_storage.h b/servers/rendering/dummy/storage/texture_storage.h index b3a5323e66f..1331ca72c25 100644 --- a/servers/rendering/dummy/storage/texture_storage.h +++ b/servers/rendering/dummy/storage/texture_storage.h @@ -46,9 +46,7 @@ private: mutable RID_PtrOwner texture_owner; public: - static TextureStorage *get_singleton() { - return singleton; - }; + static TextureStorage *get_singleton() { return singleton; } TextureStorage(); ~TextureStorage(); diff --git a/servers/rendering/renderer_scene_cull.cpp b/servers/rendering/renderer_scene_cull.cpp index 73aacf311f9..2f7e4fef06b 100644 --- a/servers/rendering/renderer_scene_cull.cpp +++ b/servers/rendering/renderer_scene_cull.cpp @@ -4071,7 +4071,7 @@ bool RendererSceneCull::free(RID p_rid) { scenario_owner.free(p_rid); RendererSceneOcclusionCull::get_singleton()->remove_scenario(p_rid); - } else if (RendererSceneOcclusionCull::get_singleton()->is_occluder(p_rid)) { + } else if (RendererSceneOcclusionCull::get_singleton() && RendererSceneOcclusionCull::get_singleton()->is_occluder(p_rid)) { RendererSceneOcclusionCull::get_singleton()->free_occluder(p_rid); } else if (instance_owner.owns(p_rid)) { // delete the instance