summaryrefslogtreecommitdiffstats
path: root/servers
diff options
context:
space:
mode:
authorSpartan322 <Megacake1234@gmail.com>2024-10-22 06:56:34 -0400
committerSpartan322 <Megacake1234@gmail.com>2024-10-22 06:56:34 -0400
commit9a93ab2506a3544bf48ef1c2b2d7e3d6f0dffedb (patch)
tree961ebbb6fed86a794ff4446a848a359a6cd3fd4e /servers
parent9a49cab65c8e8ed8ac5f0613d96ddde403d12728 (diff)
parentb3bcb2dc14691f7729984128dca26a844f662fa1 (diff)
downloadredot-engine-9a93ab2506a3544bf48ef1c2b2d7e3d6f0dffedb.tar.gz
Merge commit godotengine/godot@b3bcb2dc14691f7729984128dca26a844f662fa1
Diffstat (limited to 'servers')
-rw-r--r--servers/display_server.cpp1
-rw-r--r--servers/display_server.h4
-rw-r--r--servers/movie_writer/movie_writer.h1
-rw-r--r--servers/rendering/renderer_rd/renderer_compositor_rd.h1
-rw-r--r--servers/rendering/renderer_rd/renderer_scene_render_rd.cpp1
-rw-r--r--servers/rendering/renderer_rd/shaders/environment/volumetric_fog_process.glsl1
-rw-r--r--servers/rendering/renderer_rd/storage_rd/texture_storage.cpp71
-rw-r--r--servers/rendering/renderer_rd/storage_rd/texture_storage.h5
-rw-r--r--servers/rendering/renderer_scene_cull.cpp3
-rw-r--r--servers/rendering/rendering_device_graph.cpp18
-rw-r--r--servers/rendering/rendering_device_graph.h5
-rw-r--r--servers/rendering/shader_preprocessor.cpp42
-rw-r--r--servers/rendering/shader_preprocessor.h1
-rw-r--r--servers/text_server.h1
14 files changed, 107 insertions, 48 deletions
diff --git a/servers/display_server.cpp b/servers/display_server.cpp
index ab38807378..ca073aefbb 100644
--- a/servers/display_server.cpp
+++ b/servers/display_server.cpp
@@ -1130,6 +1130,7 @@ void DisplayServer::_bind_methods() {
BIND_ENUM_CONSTANT(WINDOW_FLAG_POPUP);
BIND_ENUM_CONSTANT(WINDOW_FLAG_EXTEND_TO_TITLE);
BIND_ENUM_CONSTANT(WINDOW_FLAG_MOUSE_PASSTHROUGH);
+ BIND_ENUM_CONSTANT(WINDOW_FLAG_SHARP_CORNERS);
BIND_ENUM_CONSTANT(WINDOW_FLAG_MAX);
BIND_ENUM_CONSTANT(WINDOW_EVENT_MOUSE_ENTER);
diff --git a/servers/display_server.h b/servers/display_server.h
index 0bf1cdfb4d..dc20337214 100644
--- a/servers/display_server.h
+++ b/servers/display_server.h
@@ -34,6 +34,7 @@
#define DISPLAY_SERVER_H
#include "core/input/input.h"
+#include "core/io/image.h"
#include "core/io/resource.h"
#include "core/os/os.h"
#include "core/variant/callable.h"
@@ -41,7 +42,6 @@
#include "display/native_menu.h"
class Texture2D;
-class Image;
class DisplayServer : public Object {
GDCLASS(DisplayServer, Object)
@@ -383,6 +383,7 @@ public:
WINDOW_FLAG_POPUP,
WINDOW_FLAG_EXTEND_TO_TITLE,
WINDOW_FLAG_MOUSE_PASSTHROUGH,
+ WINDOW_FLAG_SHARP_CORNERS,
WINDOW_FLAG_MAX,
};
@@ -396,6 +397,7 @@ public:
WINDOW_FLAG_POPUP_BIT = (1 << WINDOW_FLAG_POPUP),
WINDOW_FLAG_EXTEND_TO_TITLE_BIT = (1 << WINDOW_FLAG_EXTEND_TO_TITLE),
WINDOW_FLAG_MOUSE_PASSTHROUGH_BIT = (1 << WINDOW_FLAG_MOUSE_PASSTHROUGH),
+ WINDOW_FLAG_SHARP_CORNERS_BIT = (1 << WINDOW_FLAG_SHARP_CORNERS),
};
virtual WindowID create_sub_window(WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Rect2i &p_rect = Rect2i(), bool p_exclusive = false, WindowID p_transient_parent = INVALID_WINDOW_ID);
diff --git a/servers/movie_writer/movie_writer.h b/servers/movie_writer/movie_writer.h
index 73f07a652c..f2087e26ca 100644
--- a/servers/movie_writer/movie_writer.h
+++ b/servers/movie_writer/movie_writer.h
@@ -33,6 +33,7 @@
#ifndef MOVIE_WRITER_H
#define MOVIE_WRITER_H
+#include "core/io/image.h"
#include "core/templates/local_vector.h"
#include "servers/audio/audio_driver_dummy.h"
#include "servers/audio_server.h"
diff --git a/servers/rendering/renderer_rd/renderer_compositor_rd.h b/servers/rendering/renderer_rd/renderer_compositor_rd.h
index 452309aa2e..9cf464bd95 100644
--- a/servers/rendering/renderer_rd/renderer_compositor_rd.h
+++ b/servers/rendering/renderer_rd/renderer_compositor_rd.h
@@ -33,6 +33,7 @@
#ifndef RENDERER_COMPOSITOR_RD_H
#define RENDERER_COMPOSITOR_RD_H
+#include "core/io/image.h"
#include "core/os/os.h"
#include "servers/rendering/renderer_compositor.h"
#include "servers/rendering/renderer_rd/environment/fog.h"
diff --git a/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp b/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp
index 1a235b5073..486917ab0c 100644
--- a/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp
+++ b/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp
@@ -33,6 +33,7 @@
#include "renderer_scene_render_rd.h"
#include "core/config/project_settings.h"
+#include "core/io/image.h"
#include "core/os/os.h"
#include "renderer_compositor_rd.h"
#include "servers/rendering/renderer_rd/environment/fog.h"
diff --git a/servers/rendering/renderer_rd/shaders/environment/volumetric_fog_process.glsl b/servers/rendering/renderer_rd/shaders/environment/volumetric_fog_process.glsl
index a797891ab6..90bbdfe685 100644
--- a/servers/rendering/renderer_rd/shaders/environment/volumetric_fog_process.glsl
+++ b/servers/rendering/renderer_rd/shaders/environment/volumetric_fog_process.glsl
@@ -513,6 +513,7 @@ void main() {
shadow_sample.z = 1.0 + abs(shadow_sample.z);
vec3 pos = vec3(shadow_sample.xy / shadow_sample.z, shadow_len - omni_lights.data[light_index].shadow_bias);
pos.z *= omni_lights.data[light_index].inv_radius;
+ pos.z = 1.0 - pos.z;
pos.xy = pos.xy * 0.5 + 0.5;
pos.xy = uv_rect.xy + pos.xy * uv_rect.zw;
diff --git a/servers/rendering/renderer_rd/storage_rd/texture_storage.cpp b/servers/rendering/renderer_rd/storage_rd/texture_storage.cpp
index 0f48d184f7..7e8c0f28b5 100644
--- a/servers/rendering/renderer_rd/storage_rd/texture_storage.cpp
+++ b/servers/rendering/renderer_rd/storage_rd/texture_storage.cpp
@@ -520,6 +520,32 @@ TextureStorage::TextureStorage() {
rt_sdf.pipelines[i] = RD::get_singleton()->compute_pipeline_create(rt_sdf.shader.version_get_shader(rt_sdf.shader_version, i));
}
}
+
+ // Initialize texture placeholder data for the `texture_*_placeholder_initialize()` methods.
+
+ constexpr int placeholder_size = 4;
+ texture_2d_placeholder = Image::create_empty(placeholder_size, placeholder_size, false, Image::FORMAT_RGBA8);
+ // Draw a magenta/black checkerboard pattern.
+ for (int i = 0; i < placeholder_size * placeholder_size; i++) {
+ const int x = i % placeholder_size;
+ const int y = i / placeholder_size;
+ texture_2d_placeholder->set_pixel(x, y, (x + y) % 2 == 0 ? Color(1, 0, 1) : Color(0, 0, 0));
+ }
+
+ texture_2d_array_placeholder.push_back(texture_2d_placeholder);
+
+ for (int i = 0; i < 6; i++) {
+ cubemap_placeholder.push_back(texture_2d_placeholder);
+ }
+
+ Ref<Image> texture_2d_placeholder_rotated;
+ texture_2d_placeholder_rotated.instantiate();
+ texture_2d_placeholder_rotated->copy_from(texture_2d_placeholder);
+ texture_2d_placeholder_rotated->rotate_90(CLOCKWISE);
+ for (int i = 0; i < 4; i++) {
+ // Alternate checkerboard pattern on odd layers (by using a copy that is rotated 90 degrees).
+ texture_3d_placeholder.push_back(i % 2 == 0 ? texture_2d_placeholder : texture_2d_placeholder_rotated);
+ }
}
TextureStorage::~TextureStorage() {
@@ -1367,46 +1393,19 @@ void TextureStorage::texture_proxy_update(RID p_texture, RID p_proxy_to) {
//these two APIs can be used together or in combination with the others.
void TextureStorage::texture_2d_placeholder_initialize(RID p_texture) {
- //this could be better optimized to reuse an existing image , done this way
- //for now to get it working
- Ref<Image> image = Image::create_empty(4, 4, false, Image::FORMAT_RGBA8);
- image->fill(Color(1, 0, 1, 1));
-
- texture_2d_initialize(p_texture, image);
+ texture_2d_initialize(p_texture, texture_2d_placeholder);
}
void TextureStorage::texture_2d_layered_placeholder_initialize(RID p_texture, RS::TextureLayeredType p_layered_type) {
- //this could be better optimized to reuse an existing image , done this way
- //for now to get it working
- Ref<Image> image = Image::create_empty(4, 4, false, Image::FORMAT_RGBA8);
- image->fill(Color(1, 0, 1, 1));
-
- Vector<Ref<Image>> images;
if (p_layered_type == RS::TEXTURE_LAYERED_2D_ARRAY) {
- images.push_back(image);
+ texture_2d_layered_initialize(p_texture, texture_2d_array_placeholder, p_layered_type);
} else {
- //cube
- for (int i = 0; i < 6; i++) {
- images.push_back(image);
- }
+ texture_2d_layered_initialize(p_texture, cubemap_placeholder, p_layered_type);
}
-
- texture_2d_layered_initialize(p_texture, images, p_layered_type);
}
void TextureStorage::texture_3d_placeholder_initialize(RID p_texture) {
- //this could be better optimized to reuse an existing image , done this way
- //for now to get it working
- Ref<Image> image = Image::create_empty(4, 4, false, Image::FORMAT_RGBA8);
- image->fill(Color(1, 0, 1, 1));
-
- Vector<Ref<Image>> images;
- //cube
- for (int i = 0; i < 4; i++) {
- images.push_back(image);
- }
-
- texture_3d_initialize(p_texture, Image::FORMAT_RGBA8, 4, 4, 4, false, images);
+ texture_3d_initialize(p_texture, Image::FORMAT_RGBA8, 4, 4, 4, false, texture_3d_placeholder);
}
Ref<Image> TextureStorage::texture_2d_get(RID p_texture) const {
@@ -2271,6 +2270,16 @@ void TextureStorage::_texture_format_from_rd(RD::DataFormat p_rd_format, Texture
r_format.swizzle_b = RD::TEXTURE_SWIZZLE_B;
r_format.swizzle_a = RD::TEXTURE_SWIZZLE_A;
} break;
+ case RD::DATA_FORMAT_B8G8R8A8_UNORM:
+ case RD::DATA_FORMAT_B8G8R8A8_SRGB: {
+ r_format.image_format = Image::FORMAT_RGBA8;
+ r_format.rd_format = RD::DATA_FORMAT_B8G8R8A8_UNORM;
+ r_format.rd_format_srgb = RD::DATA_FORMAT_B8G8R8A8_SRGB;
+ r_format.swizzle_r = RD::TEXTURE_SWIZZLE_R;
+ r_format.swizzle_g = RD::TEXTURE_SWIZZLE_G;
+ r_format.swizzle_b = RD::TEXTURE_SWIZZLE_B;
+ r_format.swizzle_a = RD::TEXTURE_SWIZZLE_A;
+ } break;
case RD::DATA_FORMAT_B4G4R4A4_UNORM_PACK16: {
r_format.image_format = Image::FORMAT_RGBA4444;
r_format.rd_format = RD::DATA_FORMAT_B4G4R4A4_UNORM_PACK16;
diff --git a/servers/rendering/renderer_rd/storage_rd/texture_storage.h b/servers/rendering/renderer_rd/storage_rd/texture_storage.h
index f1796e5141..503bb093cf 100644
--- a/servers/rendering/renderer_rd/storage_rd/texture_storage.h
+++ b/servers/rendering/renderer_rd/storage_rd/texture_storage.h
@@ -522,6 +522,11 @@ public:
virtual void texture_external_update(RID p_texture, int p_width, int p_height, uint64_t p_external_buffer) override;
virtual void texture_proxy_update(RID p_proxy, RID p_base) override;
+ Ref<Image> texture_2d_placeholder;
+ Vector<Ref<Image>> texture_2d_array_placeholder;
+ Vector<Ref<Image>> cubemap_placeholder;
+ Vector<Ref<Image>> texture_3d_placeholder;
+
//these two APIs can be used together or in combination with the others.
virtual void texture_2d_placeholder_initialize(RID p_texture) override;
virtual void texture_2d_layered_placeholder_initialize(RID p_texture, RenderingServer::TextureLayeredType p_layered_type) override;
diff --git a/servers/rendering/renderer_scene_cull.cpp b/servers/rendering/renderer_scene_cull.cpp
index 638d97131f..3f385888b2 100644
--- a/servers/rendering/renderer_scene_cull.cpp
+++ b/servers/rendering/renderer_scene_cull.cpp
@@ -2000,6 +2000,9 @@ void RendererSceneCull::_update_instance(Instance *p_instance) {
pair.bvh2 = &p_instance->scenario->indexers[Scenario::INDEXER_VOLUMES];
}
pair.cull_mask = RSG::light_storage->light_get_cull_mask(p_instance->base);
+ } else if (p_instance->base_type == RS::INSTANCE_LIGHTMAP) {
+ pair.pair_mask = RS::INSTANCE_GEOMETRY_MASK;
+ pair.bvh = &p_instance->scenario->indexers[Scenario::INDEXER_GEOMETRY];
} else if (geometry_instance_pair_mask & (1 << RS::INSTANCE_REFLECTION_PROBE) && (p_instance->base_type == RS::INSTANCE_REFLECTION_PROBE)) {
pair.pair_mask = RS::INSTANCE_GEOMETRY_MASK;
pair.bvh = &p_instance->scenario->indexers[Scenario::INDEXER_GEOMETRY];
diff --git a/servers/rendering/rendering_device_graph.cpp b/servers/rendering/rendering_device_graph.cpp
index 2e34f62b19..4a7392a71c 100644
--- a/servers/rendering/rendering_device_graph.cpp
+++ b/servers/rendering/rendering_device_graph.cpp
@@ -36,6 +36,7 @@
#define FORCE_FULL_ACCESS_BITS 0
#define PRINT_RESOURCE_TRACKER_TOTAL 0
#define PRINT_COMMAND_RECORDING 0
+#define INSERT_BREADCRUMBS 1
RenderingDeviceGraph::RenderingDeviceGraph() {
driver_honors_barriers = false;
@@ -440,6 +441,15 @@ void RenderingDeviceGraph::_add_command_to_graph(ResourceTracker **p_resource_tr
// Always update the access of the tracker according to the latest usage.
resource_tracker->usage_access = new_usage_access;
+ // Always accumulate the stages of the tracker with the commands that use it.
+ search_tracker->current_frame_stages = search_tracker->current_frame_stages | r_command->self_stages;
+
+ if (!search_tracker->previous_frame_stages.is_empty()) {
+ // Add to the command the stages the tracker was used on in the previous frame.
+ r_command->previous_stages = r_command->previous_stages | search_tracker->previous_frame_stages;
+ search_tracker->previous_frame_stages.clear();
+ }
+
if (different_usage) {
// Even if the usage of the resource isn't a write usage explicitly, a different usage implies a transition and it should therefore be considered a write.
write_usage = true;
@@ -825,7 +835,7 @@ void RenderingDeviceGraph::_run_render_commands(int32_t p_level, const RecordedC
const RecordedDrawListCommand *draw_list_command = reinterpret_cast<const RecordedDrawListCommand *>(command);
const VectorView clear_values(draw_list_command->clear_values(), draw_list_command->clear_values_count);
-#if defined(DEBUG_ENABLED) || defined(DEV_ENABLED)
+#if INSERT_BREADCRUMBS
driver->command_insert_breadcrumb(r_command_buffer, draw_list_command->breadcrumb);
#endif
driver->command_begin_render_pass(r_command_buffer, draw_list_command->render_pass, draw_list_command->framebuffer, draw_list_command->command_buffer_type, draw_list_command->region, clear_values);
@@ -876,7 +886,7 @@ void RenderingDeviceGraph::_run_label_command_change(RDD::CommandBufferID p_comm
}
if (p_ignore_previous_value || p_new_label_index != r_current_label_index || p_new_level != r_current_label_level) {
- if (!p_ignore_previous_value && (p_use_label_for_empty || r_current_label_index >= 0)) {
+ if (!p_ignore_previous_value && (p_use_label_for_empty || r_current_label_index >= 0 || r_current_label_level >= 0)) {
// End the current label.
driver->command_end_label(p_command_buffer);
}
@@ -890,6 +900,8 @@ void RenderingDeviceGraph::_run_label_command_change(RDD::CommandBufferID p_comm
} else if (p_use_label_for_empty) {
label_name = "Command graph";
label_color = Color(1, 1, 1, 1);
+ } else {
+ return;
}
// Add the level to the name.
@@ -2066,7 +2078,7 @@ void RenderingDeviceGraph::end(bool p_reorder_commands, bool p_full_barriers, RD
}
}
- _run_label_command_change(r_command_buffer, -1, -1, true, false, nullptr, 0, current_label_index, current_label_level);
+ _run_label_command_change(r_command_buffer, -1, -1, false, false, nullptr, 0, current_label_index, current_label_level);
#if PRINT_COMMAND_RECORDING
print_line(vformat("Recorded %d commands", command_count));
diff --git a/servers/rendering/rendering_device_graph.h b/servers/rendering/rendering_device_graph.h
index a120845149..d7b1c2cb61 100644
--- a/servers/rendering/rendering_device_graph.h
+++ b/servers/rendering/rendering_device_graph.h
@@ -153,6 +153,8 @@ public:
struct ResourceTracker {
uint32_t reference_count = 0;
int64_t command_frame = -1;
+ BitField<RDD::PipelineStageBits> previous_frame_stages;
+ BitField<RDD::PipelineStageBits> current_frame_stages;
int32_t read_full_command_list_index = -1;
int32_t read_slice_command_list_index = -1;
int32_t write_command_or_list_index = -1;
@@ -176,8 +178,9 @@ public:
_FORCE_INLINE_ void reset_if_outdated(int64_t new_command_frame) {
if (new_command_frame != command_frame) {
- usage_access.clear();
command_frame = new_command_frame;
+ previous_frame_stages = current_frame_stages;
+ current_frame_stages.clear();
read_full_command_list_index = -1;
read_slice_command_list_index = -1;
write_command_or_list_index = -1;
diff --git a/servers/rendering/shader_preprocessor.cpp b/servers/rendering/shader_preprocessor.cpp
index 3baffbc77d..94d099ac1e 100644
--- a/servers/rendering/shader_preprocessor.cpp
+++ b/servers/rendering/shader_preprocessor.cpp
@@ -395,6 +395,8 @@ void ShaderPreprocessor::process_directive(Tokenizer *p_tokenizer) {
process_else(p_tokenizer);
} else if (directive == "endif") {
process_endif(p_tokenizer);
+ } else if (directive == "error") {
+ process_error(p_tokenizer);
} else if (directive == "define") {
process_define(p_tokenizer);
} else if (directive == "undef") {
@@ -468,7 +470,7 @@ void ShaderPreprocessor::process_elif(Tokenizer *p_tokenizer) {
const int line = p_tokenizer->get_line();
if (state->current_branch == nullptr || state->current_branch->else_defined) {
- set_error(RTR("Unmatched elif."), line);
+ set_error(vformat(RTR("Unmatched '%s' directive."), "elif"), line);
return;
}
if (state->previous_region != nullptr) {
@@ -525,7 +527,7 @@ void ShaderPreprocessor::process_else(Tokenizer *p_tokenizer) {
const int line = p_tokenizer->get_line();
if (state->current_branch == nullptr || state->current_branch->else_defined) {
- set_error(RTR("Unmatched else."), line);
+ set_error(vformat(RTR("Unmatched '%s' directive."), "else"), line);
return;
}
if (state->previous_region != nullptr) {
@@ -533,7 +535,7 @@ void ShaderPreprocessor::process_else(Tokenizer *p_tokenizer) {
}
if (!p_tokenizer->consume_empty_line()) {
- set_error(RTR("Invalid else."), p_tokenizer->get_line());
+ set_error(vformat(RTR("Invalid '%s' directive."), "else"), line);
}
bool skip = false;
@@ -561,7 +563,7 @@ void ShaderPreprocessor::process_endif(Tokenizer *p_tokenizer) {
state->condition_depth--;
if (state->condition_depth < 0) {
- set_error(RTR("Unmatched endif."), line);
+ set_error(vformat(RTR("Unmatched '%s' directive."), "endif"), line);
return;
}
if (state->previous_region != nullptr) {
@@ -570,13 +572,28 @@ void ShaderPreprocessor::process_endif(Tokenizer *p_tokenizer) {
}
if (!p_tokenizer->consume_empty_line()) {
- set_error(RTR("Invalid endif."), line);
+ set_error(vformat(RTR("Invalid '%s' directive."), "endif"), line);
}
state->current_branch = state->current_branch->parent;
state->branches.pop_back();
}
+void ShaderPreprocessor::process_error(Tokenizer *p_tokenizer) {
+ const int line = p_tokenizer->get_line();
+
+ const String body = tokens_to_string(p_tokenizer->advance('\n')).strip_edges();
+ if (body.is_empty()) {
+ set_error(" ", line);
+ } else {
+ set_error(body, line);
+ }
+
+ if (!p_tokenizer->consume_empty_line()) {
+ set_error(vformat(RTR("Invalid '%s' directive."), "error"), line);
+ }
+}
+
void ShaderPreprocessor::process_if(Tokenizer *p_tokenizer) {
const int line = p_tokenizer->get_line();
@@ -628,7 +645,7 @@ void ShaderPreprocessor::process_ifdef(Tokenizer *p_tokenizer) {
}
if (!p_tokenizer->consume_empty_line()) {
- set_error(RTR("Invalid ifdef."), line);
+ set_error(vformat(RTR("Invalid '%s' directive."), "ifdef"), line);
return;
}
@@ -650,7 +667,7 @@ void ShaderPreprocessor::process_ifndef(Tokenizer *p_tokenizer) {
}
if (!p_tokenizer->consume_empty_line()) {
- set_error(RTR("Invalid ifndef."), line);
+ set_error(vformat(RTR("Invalid '%s' directive."), "ifndef"), line);
return;
}
@@ -773,21 +790,21 @@ void ShaderPreprocessor::process_pragma(Tokenizer *p_tokenizer) {
}
if (label.is_empty()) {
- set_error(RTR("Invalid pragma directive."), line);
+ set_error(vformat(RTR("Invalid '%s' directive."), "pragma"), line);
return;
}
- // Rxplicitly handle pragma values here.
+ // Explicitly handle pragma values here.
// If more pragma options are created, then refactor into a more defined structure.
if (label == "disable_preprocessor") {
state->disabled = true;
} else {
- set_error(RTR("Invalid pragma directive."), line);
+ set_error(vformat(RTR("Invalid '%s' directive."), "pragma"), line);
return;
}
if (!p_tokenizer->consume_empty_line()) {
- set_error(RTR("Invalid pragma directive."), line);
+ set_error(vformat(RTR("Invalid '%s' directive."), "pragma"), line);
return;
}
}
@@ -796,7 +813,7 @@ void ShaderPreprocessor::process_undef(Tokenizer *p_tokenizer) {
const int line = p_tokenizer->get_line();
const String label = p_tokenizer->get_identifier();
if (label.is_empty() || !p_tokenizer->consume_empty_line()) {
- set_error(RTR("Invalid undef."), line);
+ set_error(vformat(RTR("Invalid '%s' directive."), "undef"), line);
return;
}
@@ -1385,6 +1402,7 @@ void ShaderPreprocessor::get_keyword_list(List<String> *r_keywords, bool p_inclu
r_keywords->push_back("else");
}
r_keywords->push_back("endif");
+ r_keywords->push_back("error");
if (p_include_shader_keywords) {
r_keywords->push_back("if");
}
diff --git a/servers/rendering/shader_preprocessor.h b/servers/rendering/shader_preprocessor.h
index d770d6223e..92389c28b7 100644
--- a/servers/rendering/shader_preprocessor.h
+++ b/servers/rendering/shader_preprocessor.h
@@ -193,6 +193,7 @@ private:
void process_elif(Tokenizer *p_tokenizer);
void process_else(Tokenizer *p_tokenizer);
void process_endif(Tokenizer *p_tokenizer);
+ void process_error(Tokenizer *p_tokenizer);
void process_if(Tokenizer *p_tokenizer);
void process_ifdef(Tokenizer *p_tokenizer);
void process_ifndef(Tokenizer *p_tokenizer);
diff --git a/servers/text_server.h b/servers/text_server.h
index 3e81107c89..970fde44a2 100644
--- a/servers/text_server.h
+++ b/servers/text_server.h
@@ -33,6 +33,7 @@
#ifndef TEXT_SERVER_H
#define TEXT_SERVER_H
+#include "core/io/image.h"
#include "core/object/ref_counted.h"
#include "core/os/os.h"
#include "core/templates/rid.h"