Skip to content

Commit b607110

Browse files
committed
Merge pull request #102792 from clayjohn/varying-crash
Validate varying count when compiling shaders
2 parents 40ff57e + 3510039 commit b607110

17 files changed

+92
-27
lines changed

drivers/d3d12/rendering_device_driver_d3d12.cpp

+2
Original file line numberDiff line numberDiff line change
@@ -6234,6 +6234,8 @@ uint64_t RenderingDeviceDriverD3D12::limit_get(Limit p_limit) {
62346234
case LIMIT_VRS_MAX_FRAGMENT_WIDTH:
62356235
case LIMIT_VRS_MAX_FRAGMENT_HEIGHT:
62366236
return vrs_capabilities.ss_max_fragment_size;
6237+
case LIMIT_MAX_SHADER_VARYINGS:
6238+
return MIN(D3D12_VS_OUTPUT_REGISTER_COUNT, D3D12_PS_INPUT_REGISTER_COUNT);
62376239
default: {
62386240
#ifdef DEV_ENABLED
62396241
WARN_PRINT("Returning maximum value for unknown limit " + itos(p_limit) + ".");

drivers/gles3/storage/config.cpp

+5
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,11 @@ Config::Config() {
110110
glGetIntegerv(GL_MAX_TEXTURE_SIZE, &max_texture_size);
111111
glGetIntegerv(GL_MAX_VIEWPORT_DIMS, max_viewport_size);
112112
glGetInteger64v(GL_MAX_UNIFORM_BLOCK_SIZE, &max_uniform_buffer_size);
113+
GLint max_vertex_output;
114+
glGetIntegerv(GL_MAX_VERTEX_OUTPUT_COMPONENTS, &max_vertex_output);
115+
GLint max_fragment_input;
116+
glGetIntegerv(GL_MAX_FRAGMENT_INPUT_COMPONENTS, &max_fragment_input);
117+
max_shader_varyings = (uint32_t)MIN(max_vertex_output, max_fragment_input) / 4;
113118

114119
// sanity clamp buffer size to 16K..1MB
115120
max_uniform_buffer_size = CLAMP(max_uniform_buffer_size, 16384, 1048576);

drivers/gles3/storage/config.h

+1
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@ class Config {
6262
GLint max_texture_size = 0;
6363
GLint max_viewport_size[2] = { 0, 0 };
6464
GLint64 max_uniform_buffer_size = 0;
65+
uint32_t max_shader_varyings = 0;
6566

6667
int64_t max_renderable_elements = 0;
6768
int64_t max_renderable_lights = 0;

drivers/gles3/storage/utilities.cpp

+12
Original file line numberDiff line numberDiff line change
@@ -465,4 +465,16 @@ Size2i Utilities::get_maximum_viewport_size() const {
465465
return Size2i(config->max_viewport_size[0], config->max_viewport_size[1]);
466466
}
467467

468+
uint32_t Utilities::get_maximum_shader_varyings() const {
469+
Config *config = Config::get_singleton();
470+
ERR_FAIL_NULL_V(config, 31);
471+
return config->max_shader_varyings;
472+
}
473+
474+
uint64_t Utilities::get_maximum_uniform_buffer_size() const {
475+
Config *config = Config::get_singleton();
476+
ERR_FAIL_NULL_V(config, 65536);
477+
return uint64_t(config->max_uniform_buffer_size);
478+
}
479+
468480
#endif // GLES3_ENABLED

drivers/gles3/storage/utilities.h

+2
Original file line numberDiff line numberDiff line change
@@ -226,6 +226,8 @@ class Utilities : public RendererUtilities {
226226
virtual String get_video_adapter_api_version() const override;
227227

228228
virtual Size2i get_maximum_viewport_size() const override;
229+
virtual uint32_t get_maximum_shader_varyings() const override;
230+
virtual uint64_t get_maximum_uniform_buffer_size() const override;
229231
};
230232

231233
} // namespace GLES3

drivers/metal/metal_device_properties.h

+1
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,7 @@ struct MetalLimits {
124124
uint32_t maxVertexInputBindings;
125125
uint32_t maxVertexInputBindingStride;
126126
uint32_t maxDrawIndexedIndexValue;
127+
uint32_t maxShaderVaryings;
127128

128129
double temporalScalerInputContentMinScale;
129130
double temporalScalerInputContentMaxScale;

drivers/metal/metal_device_properties.mm

+1
Original file line numberDiff line numberDiff line change
@@ -303,6 +303,7 @@
303303
limits.maxVertexInputAttributes = 31;
304304
limits.maxVertexInputBindings = 31;
305305
limits.maxVertexInputBindingStride = (2 * KIBI);
306+
limits.maxShaderVaryings = 31; // Accurate on Apple4 and above. See: https://developer.apple.com/metal/Metal-Feature-Set-Tables.pdf
306307

307308
#if TARGET_OS_IOS && !TARGET_OS_MACCATALYST
308309
limits.minUniformBufferOffsetAlignment = 64;

drivers/metal/rendering_device_driver_metal.mm

+2
Original file line numberDiff line numberDiff line change
@@ -3999,6 +3999,8 @@ bool isArrayTexture(MTLTextureType p_type) {
39993999
return (uint64_t)((1.0 / limits.temporalScalerInputContentMaxScale) * 1000'000);
40004000
case LIMIT_METALFX_TEMPORAL_SCALER_MAX_SCALE:
40014001
return (uint64_t)((1.0 / limits.temporalScalerInputContentMinScale) * 1000'000);
4002+
case LIMIT_MAX_SHADER_VARYINGS:
4003+
return limits.maxShaderVaryings;
40024004
UNKNOWN(LIMIT_VRS_TEXEL_WIDTH);
40034005
UNKNOWN(LIMIT_VRS_TEXEL_HEIGHT);
40044006
UNKNOWN(LIMIT_VRS_MAX_FRAGMENT_WIDTH);

drivers/vulkan/rendering_device_driver_vulkan.cpp

+4
Original file line numberDiff line numberDiff line change
@@ -5886,6 +5886,10 @@ uint64_t RenderingDeviceDriverVulkan::limit_get(Limit p_limit) {
58865886
return vrs_capabilities.max_fragment_size.x;
58875887
case LIMIT_VRS_MAX_FRAGMENT_HEIGHT:
58885888
return vrs_capabilities.max_fragment_size.y;
5889+
case LIMIT_MAX_SHADER_VARYINGS:
5890+
// The Vulkan spec states that built in varyings like gl_FragCoord should count against this, but in
5891+
// practice, that doesn't seem to be the case. The validation layers don't even complain.
5892+
return MIN(limits.maxVertexOutputComponents / 4, limits.maxFragmentInputComponents / 4);
58895893
default:
58905894
ERR_FAIL_V(0);
58915895
}

servers/rendering/dummy/storage/utilities.h

+2
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,8 @@ class Utilities : public RendererUtilities {
9494
virtual String get_video_adapter_api_version() const override { return String(); }
9595

9696
virtual Size2i get_maximum_viewport_size() const override { return Size2i(); }
97+
virtual uint32_t get_maximum_shader_varyings() const override { return 31; } // Fair assumption for everything except old OpenGL-only phones.
98+
virtual uint64_t get_maximum_uniform_buffer_size() const override { return 65536; } // Fair assumption for all devices.
9799
};
98100

99101
} // namespace RendererDummy

servers/rendering/renderer_rd/storage_rd/utilities.cpp

+8
Original file line numberDiff line numberDiff line change
@@ -329,3 +329,11 @@ Size2i Utilities::get_maximum_viewport_size() const {
329329
int max_y = device->limit_get(RenderingDevice::LIMIT_MAX_VIEWPORT_DIMENSIONS_Y);
330330
return Size2i(max_x, max_y);
331331
}
332+
333+
uint32_t Utilities::get_maximum_shader_varyings() const {
334+
return RenderingDevice::get_singleton()->limit_get(RenderingDevice::LIMIT_MAX_SHADER_VARYINGS);
335+
}
336+
337+
uint64_t Utilities::get_maximum_uniform_buffer_size() const {
338+
return RenderingDevice::get_singleton()->limit_get(RenderingDevice::LIMIT_MAX_UNIFORM_BUFFER_SIZE);
339+
}

servers/rendering/renderer_rd/storage_rd/utilities.h

+2
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,8 @@ class Utilities : public RendererUtilities {
117117
virtual String get_video_adapter_api_version() const override;
118118

119119
virtual Size2i get_maximum_viewport_size() const override;
120+
virtual uint32_t get_maximum_shader_varyings() const override;
121+
virtual uint64_t get_maximum_uniform_buffer_size() const override;
120122
};
121123

122124
} // namespace RendererRD

servers/rendering/rendering_device_commons.h

+1
Original file line numberDiff line numberDiff line change
@@ -875,6 +875,7 @@ class RenderingDeviceCommons : public Object {
875875
LIMIT_VRS_MAX_FRAGMENT_HEIGHT,
876876
LIMIT_METALFX_TEMPORAL_SCALER_MIN_SCALE,
877877
LIMIT_METALFX_TEMPORAL_SCALER_MAX_SCALE,
878+
LIMIT_MAX_SHADER_VARYINGS,
878879
};
879880

880881
enum Features {

servers/rendering/shader_compiler.cpp

+2-17
Original file line numberDiff line numberDiff line change
@@ -686,30 +686,14 @@ String ShaderCompiler::_dump_node_code(const SL::Node *p_node, int p_level, Gene
686686
vcode += _prestr(varying.precision, ShaderLanguage::is_float_type(varying.type));
687687
vcode += _typestr(varying.type);
688688
vcode += " " + _mkid(varying_name);
689-
uint32_t inc = 1U;
689+
uint32_t inc = varying.get_size();
690690

691691
if (varying.array_size > 0) {
692-
inc = (uint32_t)varying.array_size;
693-
694692
vcode += "[";
695693
vcode += itos(varying.array_size);
696694
vcode += "]";
697695
}
698696

699-
switch (varying.type) {
700-
case SL::TYPE_MAT2:
701-
inc *= 2U;
702-
break;
703-
case SL::TYPE_MAT3:
704-
inc *= 3U;
705-
break;
706-
case SL::TYPE_MAT4:
707-
inc *= 4U;
708-
break;
709-
default:
710-
break;
711-
}
712-
713697
vcode += ";\n";
714698
// GLSL ES 3.0 does not allow layout qualifiers for varyings
715699
if (!RS::get_singleton()->is_low_end()) {
@@ -1481,6 +1465,7 @@ Error ShaderCompiler::compile(RS::ShaderMode p_mode, const String &p_code, Ident
14811465
info.render_modes = ShaderTypes::get_singleton()->get_modes(p_mode);
14821466
info.shader_types = ShaderTypes::get_singleton()->get_types();
14831467
info.global_shader_uniform_type_func = _get_global_shader_uniform_type;
1468+
info.base_varying_index = actions.base_varying_index;
14841469

14851470
Error err = parser.compile(p_code, info);
14861471

servers/rendering/shader_language.cpp

+21-10
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
#include "core/os/os.h"
3434
#include "core/templates/local_vector.h"
3535
#include "servers/rendering/renderer_compositor.h"
36+
#include "servers/rendering/rendering_server_globals.h"
3637
#include "servers/rendering_server.h"
3738
#include "shader_types.h"
3839

@@ -9111,17 +9112,12 @@ Error ShaderLanguage::_parse_shader(const HashMap<StringName, FunctionInfo> &p_f
91119112
int prop_index = 0;
91129113
#ifdef DEBUG_ENABLED
91139114
uint64_t uniform_buffer_size = 0;
9114-
uint64_t max_uniform_buffer_size = 0;
9115+
uint64_t max_uniform_buffer_size = 65536;
91159116
int uniform_buffer_exceeded_line = -1;
9116-
9117-
bool check_device_limit_warnings = false;
9118-
{
9119-
RenderingDevice *device = RenderingDevice::get_singleton();
9120-
if (device != nullptr) {
9121-
check_device_limit_warnings = check_warnings && HAS_WARNING(ShaderWarning::DEVICE_LIMIT_EXCEEDED_FLAG);
9122-
9123-
max_uniform_buffer_size = device->limit_get(RenderingDevice::LIMIT_MAX_UNIFORM_BUFFER_SIZE);
9124-
}
9117+
bool check_device_limit_warnings = check_warnings && HAS_WARNING(ShaderWarning::DEVICE_LIMIT_EXCEEDED_FLAG);
9118+
// Can be false for internal shaders created in the process of initializing the engine.
9119+
if (RSG::utilities) {
9120+
max_uniform_buffer_size = RSG::utilities->get_maximum_uniform_buffer_size();
91259121
}
91269122
#endif // DEBUG_ENABLED
91279123
ShaderNode::Uniform::Scope uniform_scope = ShaderNode::Uniform::SCOPE_LOCAL;
@@ -10959,13 +10955,27 @@ Error ShaderLanguage::_parse_shader(const HashMap<StringName, FunctionInfo> &p_f
1095910955

1096010956
tk = _get_token();
1096110957
}
10958+
uint32_t varying_index = base_varying_index;
10959+
uint32_t max_varyings = 31;
10960+
// Can be false for internal shaders created in the process of initializing the engine.
10961+
if (RSG::utilities) {
10962+
max_varyings = RSG::utilities->get_maximum_shader_varyings();
10963+
}
1096210964

1096310965
for (const KeyValue<StringName, ShaderNode::Varying> &kv : shader->varyings) {
1096410966
if (kv.value.stage != ShaderNode::Varying::STAGE_FRAGMENT && (kv.value.type > TYPE_BVEC4 && kv.value.type < TYPE_FLOAT) && kv.value.interpolation != INTERPOLATION_FLAT) {
1096510967
_set_tkpos(kv.value.tkpos);
1096610968
_set_error(vformat(RTR("Varying with integer data type must be declared with `%s` interpolation qualifier."), "flat"));
1096710969
return ERR_PARSE_ERROR;
1096810970
}
10971+
10972+
if (varying_index + kv.value.get_size() > max_varyings) {
10973+
_set_tkpos(kv.value.tkpos);
10974+
_set_error(vformat(RTR("Too many varyings used in shader (%d used, maximum supported is %d)."), varying_index + kv.value.get_size(), max_varyings));
10975+
return ERR_PARSE_ERROR;
10976+
}
10977+
10978+
varying_index += kv.value.get_size();
1096910979
}
1097010980

1097110981
#ifdef DEBUG_ENABLED
@@ -11183,6 +11193,7 @@ Error ShaderLanguage::compile(const String &p_code, const ShaderCompileInfo &p_i
1118311193
global_shader_uniform_get_type_func = p_info.global_shader_uniform_type_func;
1118411194

1118511195
varying_function_names = p_info.varying_function_names;
11196+
base_varying_index = p_info.base_varying_index;
1118611197

1118711198
nodes = nullptr;
1118811199

servers/rendering/shader_language.h

+24
Original file line numberDiff line numberDiff line change
@@ -631,6 +631,28 @@ class ShaderLanguage {
631631
int array_size = 0;
632632
TkPos tkpos;
633633

634+
uint32_t get_size() const {
635+
uint32_t size = 1;
636+
if (array_size > 0) {
637+
size = (uint32_t)array_size;
638+
}
639+
640+
switch (type) {
641+
case TYPE_MAT2:
642+
size *= 2;
643+
break;
644+
case TYPE_MAT3:
645+
size *= 3;
646+
break;
647+
case TYPE_MAT4:
648+
size *= 4;
649+
break;
650+
default:
651+
break;
652+
}
653+
return size;
654+
}
655+
634656
Varying() {}
635657
};
636658

@@ -1022,6 +1044,7 @@ class ShaderLanguage {
10221044
String current_uniform_subgroup_name;
10231045

10241046
VaryingFunctionNames varying_function_names;
1047+
uint32_t base_varying_index = 0;
10251048

10261049
TkPos _get_tkpos() {
10271050
TkPos tkp;
@@ -1217,6 +1240,7 @@ class ShaderLanguage {
12171240
HashSet<String> shader_types;
12181241
GlobalShaderUniformGetTypeFunc global_shader_uniform_type_func = nullptr;
12191242
bool is_include = false;
1243+
uint32_t base_varying_index = 0;
12201244
};
12211245

12221246
Error compile(const String &p_code, const ShaderCompileInfo &p_info);

servers/rendering/storage/utilities.h

+2
Original file line numberDiff line numberDiff line change
@@ -184,6 +184,8 @@ class RendererUtilities {
184184
virtual String get_video_adapter_api_version() const = 0;
185185

186186
virtual Size2i get_maximum_viewport_size() const = 0;
187+
virtual uint32_t get_maximum_shader_varyings() const = 0;
188+
virtual uint64_t get_maximum_uniform_buffer_size() const = 0;
187189
};
188190

189191
#endif // RENDERER_UTILITIES_H

0 commit comments

Comments
 (0)