diff --git a/glsl_builders.py b/glsl_builders.py index 05aab3acbb39..b843908892e1 100644 --- a/glsl_builders.py +++ b/glsl_builders.py @@ -128,13 +128,13 @@ def build_rd_header( if header_data.compute_lines: body_parts = [ "static const char _compute_code[] = {\n%s\n\t\t};" % generate_inline_code(header_data.compute_lines), - f'setup(nullptr, nullptr, _compute_code, "{out_file_class}");', + f'setup(nullptr, nullptr, nullptr, nullptr, _compute_code, "{out_file_class}");', ] else: body_parts = [ "static const char _vertex_code[] = {\n%s\n\t\t};" % generate_inline_code(header_data.vertex_lines), "static const char _fragment_code[] = {\n%s\n\t\t};" % generate_inline_code(header_data.fragment_lines), - f'setup(_vertex_code, _fragment_code, nullptr, "{out_file_class}");', + f'setup(_vertex_code, _fragment_code, nullptr, nullptr, nullptr, "{out_file_class}");', ] body_content = "\n\t\t".join(body_parts) diff --git a/servers/rendering/renderer_rd/environment/sky.cpp b/servers/rendering/renderer_rd/environment/sky.cpp index b5d31f541401..de3c21c90097 100644 --- a/servers/rendering/renderer_rd/environment/sky.cpp +++ b/servers/rendering/renderer_rd/environment/sky.cpp @@ -129,7 +129,7 @@ void SkyRD::SkyShaderData::set_code(const String &p_code) { print_line("\n**fragment_globals:\n" + gen_code.stage_globals[ShaderCompiler::STAGE_FRAGMENT]); #endif - scene_singleton->sky.sky_shader.shader.version_set_code(version, gen_code.code, gen_code.uniforms, gen_code.stage_globals[ShaderCompiler::STAGE_VERTEX], gen_code.stage_globals[ShaderCompiler::STAGE_FRAGMENT], gen_code.defines); + scene_singleton->sky.sky_shader.shader.version_set_code(version, gen_code.code, gen_code.uniforms, gen_code.stage_globals[ShaderCompiler::STAGE_VERTEX], gen_code.stage_globals[ShaderCompiler::STAGE_FRAGMENT], gen_code.stage_globals[ShaderCompiler::STAGE_TESSELLATION_CONTROL], gen_code.stage_globals[ShaderCompiler::STAGE_TESSELLATION_EVALUATION], gen_code.defines); ERR_FAIL_COND(!scene_singleton->sky.sky_shader.shader.version_is_valid(version)); ubo_size = gen_code.uniform_total_size; diff --git a/servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.cpp b/servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.cpp index 9e0dacc1f29d..984f665fbe2d 100644 --- a/servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.cpp +++ b/servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.cpp @@ -178,7 +178,7 @@ void SceneShaderForwardClustered::ShaderData::set_code(const String &p_code) { print_line("\n**vertex_globals:\n" + gen_code.stage_globals[ShaderCompiler::STAGE_VERTEX]); print_line("\n**fragment_globals:\n" + gen_code.stage_globals[ShaderCompiler::STAGE_FRAGMENT]); #endif - shader_singleton->shader.version_set_code(version, gen_code.code, gen_code.uniforms, gen_code.stage_globals[ShaderCompiler::STAGE_VERTEX], gen_code.stage_globals[ShaderCompiler::STAGE_FRAGMENT], gen_code.defines); + shader_singleton->shader.version_set_code(version, gen_code.code, gen_code.uniforms, gen_code.stage_globals[ShaderCompiler::STAGE_VERTEX], gen_code.stage_globals[ShaderCompiler::STAGE_FRAGMENT], gen_code.stage_globals[ShaderCompiler::STAGE_TESSELLATION_CONTROL], gen_code.stage_globals[ShaderCompiler::STAGE_TESSELLATION_EVALUATION], gen_code.defines); ERR_FAIL_COND(!shader_singleton->shader.version_is_valid(version)); ubo_size = gen_code.uniform_total_size; diff --git a/servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.cpp b/servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.cpp index dd722cc2ddde..1cfdda1cdf4d 100644 --- a/servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.cpp +++ b/servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.cpp @@ -189,7 +189,7 @@ void SceneShaderForwardMobile::ShaderData::set_code(const String &p_code) { print_line("\n**fragment_globals:\n" + gen_code.stage_globals[ShaderCompiler::STAGE_FRAGMENT]); #endif - shader_singleton->shader.version_set_code(version, gen_code.code, gen_code.uniforms, gen_code.stage_globals[ShaderCompiler::STAGE_VERTEX], gen_code.stage_globals[ShaderCompiler::STAGE_FRAGMENT], gen_code.defines); + shader_singleton->shader.version_set_code(version, gen_code.code, gen_code.uniforms, gen_code.stage_globals[ShaderCompiler::STAGE_VERTEX], gen_code.stage_globals[ShaderCompiler::STAGE_FRAGMENT], gen_code.stage_globals[ShaderCompiler::STAGE_TESSELLATION_CONTROL], gen_code.stage_globals[ShaderCompiler::STAGE_TESSELLATION_EVALUATION], gen_code.defines); ERR_FAIL_COND(!shader_singleton->shader.version_is_valid(version)); ubo_size = gen_code.uniform_total_size; diff --git a/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp b/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp index fa8cf9c0288f..2e319c8e90f3 100644 --- a/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp +++ b/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp @@ -2184,6 +2184,8 @@ void RendererCanvasRenderRD::CanvasShaderData::set_code(const String &p_code) { actions.entry_point_stages["vertex"] = ShaderCompiler::STAGE_VERTEX; actions.entry_point_stages["fragment"] = ShaderCompiler::STAGE_FRAGMENT; actions.entry_point_stages["light"] = ShaderCompiler::STAGE_FRAGMENT; + actions.entry_point_stages["tesselation_control"] = ShaderCompiler::STAGE_TESSELLATION_CONTROL; + actions.entry_point_stages["tesselation_evaluation"] = ShaderCompiler::STAGE_TESSELLATION_EVALUATION; actions.render_mode_values["blend_add"] = Pair(&blend_mode, BLEND_MODE_ADD); actions.render_mode_values["blend_mix"] = Pair(&blend_mode, BLEND_MODE_MIX); @@ -2226,7 +2228,7 @@ void RendererCanvasRenderRD::CanvasShaderData::set_code(const String &p_code) { print_line("\n**vertex_globals:\n" + gen_code.stage_globals[ShaderCompiler::STAGE_VERTEX]); print_line("\n**fragment_globals:\n" + gen_code.stage_globals[ShaderCompiler::STAGE_FRAGMENT]); #endif - canvas_singleton->shader.canvas_shader.version_set_code(version, gen_code.code, gen_code.uniforms, gen_code.stage_globals[ShaderCompiler::STAGE_VERTEX], gen_code.stage_globals[ShaderCompiler::STAGE_FRAGMENT], gen_code.defines); + canvas_singleton->shader.canvas_shader.version_set_code(version, gen_code.code, gen_code.uniforms, gen_code.stage_globals[ShaderCompiler::STAGE_VERTEX], gen_code.stage_globals[ShaderCompiler::STAGE_FRAGMENT], gen_code.stage_globals[ShaderCompiler::STAGE_TESSELLATION_CONTROL], gen_code.stage_globals[ShaderCompiler::STAGE_TESSELLATION_EVALUATION], gen_code.defines); ERR_FAIL_COND(!canvas_singleton->shader.canvas_shader.version_is_valid(version)); ubo_size = gen_code.uniform_total_size; diff --git a/servers/rendering/renderer_rd/shader_rd.cpp b/servers/rendering/renderer_rd/shader_rd.cpp index 1c1b8366e5f6..77e4f237e230 100644 --- a/servers/rendering/renderer_rd/shader_rd.cpp +++ b/servers/rendering/renderer_rd/shader_rd.cpp @@ -61,6 +61,12 @@ void ShaderRD::_add_stage(const char *p_code, StageType p_stage_type) { case STAGE_TYPE_FRAGMENT: chunk.type = StageTemplate::Chunk::TYPE_FRAGMENT_GLOBALS; break; + case STAGE_TYPE_TESSCONTROL: + chunk.type = StageTemplate::Chunk::TYPE_TESSCONTROL_GLOBALS; + break; + case STAGE_TYPE_TESSEVAL: + chunk.type = StageTemplate::Chunk::TYPE_TESSEVAL_GLOBALS; + break; case STAGE_TYPE_COMPUTE: chunk.type = StageTemplate::Chunk::TYPE_COMPUTE_GLOBALS; break; @@ -101,7 +107,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_tesscontrol_code, const char *p_tesseval_code, const char *p_compute_code, const char *p_name) { name = p_name; if (p_compute_code) { @@ -115,6 +121,12 @@ void ShaderRD::setup(const char *p_vertex_code, const char *p_fragment_code, con if (p_fragment_code) { _add_stage(p_fragment_code, STAGE_TYPE_FRAGMENT); } + if (p_tesscontrol_code) { + _add_stage(p_tesscontrol_code, STAGE_TYPE_TESSCONTROL); + } + if (p_tesseval_code) { + _add_stage(p_tesseval_code, STAGE_TYPE_TESSEVAL); + } } StringBuilder tohash; @@ -130,6 +142,10 @@ void ShaderRD::setup(const char *p_vertex_code, const char *p_fragment_code, con tohash.append(p_vertex_code ? p_vertex_code : ""); tohash.append("[Fragment]"); tohash.append(p_fragment_code ? p_fragment_code : ""); + tohash.append("[TessellationControl]"); + tohash.append(p_tesscontrol_code ? p_tesscontrol_code : ""); + tohash.append("[TessellationEvaluation]"); + tohash.append(p_tesseval_code ? p_tesseval_code : ""); tohash.append("[Compute]"); tohash.append(p_compute_code ? p_compute_code : ""); @@ -205,6 +221,12 @@ void ShaderRD::_build_variant_code(StringBuilder &builder, uint32_t p_variant, c case StageTemplate::Chunk::TYPE_FRAGMENT_GLOBALS: { builder.append(p_version->fragment_globals.get_data()); // fragment globals } break; + case StageTemplate::Chunk::TYPE_TESSCONTROL_GLOBALS: { + builder.append(p_version->tesscontrol_globals.get_data()); // tessellation control globals + } break; + case StageTemplate::Chunk::TYPE_TESSEVAL_GLOBALS: { + builder.append(p_version->tesseval_globals.get_data()); // tessellation evaluation globals + } break; case StageTemplate::Chunk::TYPE_COMPUTE_GLOBALS: { builder.append(p_version->compute_globals.get_data()); // compute globals } break; @@ -250,7 +272,45 @@ void ShaderRD::_compile_variant(uint32_t p_variant, const CompileData *p_data) { stages.push_back(stage); } } + + if (!is_compute && build_ok) { + //tessellation control stage + current_stage = RD::SHADER_STAGE_TESSELATION_CONTROL; + /* + StringBuilder builder; + _build_variant_code(builder, p_variant, p_version, stage_templates[STAGE_TYPE_TESSCONTROL]); + + current_source = builder.as_string(); + RD::ShaderStageSPIRVData stage; + stage.spir_v = RD::get_singleton()->shader_compile_spirv_from_source(RD::SHADER_STAGE_TESSELATION_CONTROL, current_source, RD::SHADER_LANGUAGE_GLSL, &error); + if (stage.spir_v.size() == 0) { + build_ok = false; + } else { + stage.shader_stage = RD::SHADER_STAGE_TESSELATION_CONTROL; + stages.push_back(stage); + } + */ + } + if (!is_compute && build_ok) { + //tessellation evaluation stage + current_stage = RD::SHADER_STAGE_TESSELATION_EVALUATION; + /* + StringBuilder builder; + _build_variant_code(builder, p_variant, p_version, stage_templates[STAGE_TYPE_TESSEVAL]); + + current_source = builder.as_string(); + RD::ShaderStageSPIRVData stage; + stage.spir_v = RD::get_singleton()->shader_compile_spirv_from_source(RD::SHADER_STAGE_TESSELATION_EVALUATION, current_source, RD::SHADER_LANGUAGE_GLSL, &error); + if (stage.spir_v.size() == 0) { + build_ok = false; + } else { + stage.shader_stage = RD::SHADER_STAGE_TESSELATION_EVALUATION; + stages.push_back(stage); + } + */ + } + if (!is_compute && build_ok) { //fragment stage current_stage = RD::SHADER_STAGE_FRAGMENT; @@ -371,6 +431,10 @@ String ShaderRD::_version_get_sha1(Version *p_version) const { 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("[tesscontrol_globals]"); + hash_build.append(p_version->tesscontrol_globals.get_data()); + hash_build.append("[tesseval_globals]"); + hash_build.append(p_version->tesseval_globals.get_data()); hash_build.append("[compute_globals]"); hash_build.append(p_version->compute_globals.get_data()); @@ -568,12 +632,14 @@ void ShaderRD::_compile_version(Version *p_version, int p_group) { p_version->valid = true; } -void ShaderRD::version_set_code(RID p_version, const HashMap &p_code, const String &p_uniforms, const String &p_vertex_globals, const String &p_fragment_globals, const Vector &p_custom_defines) { +void ShaderRD::version_set_code(RID p_version, const HashMap &p_code, const String &p_uniforms, const String &p_vertex_globals, const String &p_fragment_globals, const String &p_tesscontrol_globals, const String &p_tesseval_globals, const Vector &p_custom_defines) { ERR_FAIL_COND(is_compute); Version *version = version_owner.get_or_null(p_version); ERR_FAIL_NULL(version); version->vertex_globals = p_vertex_globals.utf8(); + version->tesscontrol_globals = p_tesscontrol_globals.utf8(); + version->tesseval_globals = p_tesseval_globals.utf8(); version->fragment_globals = p_fragment_globals.utf8(); version->uniforms = p_uniforms.utf8(); version->code_sections.clear(); diff --git a/servers/rendering/renderer_rd/shader_rd.h b/servers/rendering/renderer_rd/shader_rd.h index 22a21086af9d..5e22cce97773 100644 --- a/servers/rendering/renderer_rd/shader_rd.h +++ b/servers/rendering/renderer_rd/shader_rd.h @@ -67,6 +67,8 @@ class ShaderRD { CharString vertex_globals; CharString compute_globals; CharString fragment_globals; + CharString tesscontrol_globals; + CharString tesseval_globals; HashMap code_sections; Vector custom_defines; @@ -102,6 +104,8 @@ class ShaderRD { TYPE_VERTEX_GLOBALS, TYPE_FRAGMENT_GLOBALS, TYPE_COMPUTE_GLOBALS, + TYPE_TESSCONTROL_GLOBALS, + TYPE_TESSEVAL_GLOBALS, TYPE_CODE, TYPE_TEXT }; @@ -132,6 +136,8 @@ class ShaderRD { enum StageType { STAGE_TYPE_VERTEX, STAGE_TYPE_FRAGMENT, + STAGE_TYPE_TESSCONTROL, + STAGE_TYPE_TESSEVAL, STAGE_TYPE_COMPUTE, STAGE_TYPE_MAX, }; @@ -150,12 +156,12 @@ class ShaderRD { protected: 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_tesscontrol_code, const char *p_tesseval_code, const char *p_compute_code, const char *p_name); public: RID version_create(); - void version_set_code(RID p_version, const HashMap &p_code, const String &p_uniforms, const String &p_vertex_globals, const String &p_fragment_globals, const Vector &p_custom_defines); + void version_set_code(RID p_version, const HashMap &p_code, const String &p_uniforms, const String &p_vertex_globals, const String &p_fragment_globals, const String &p_tesscontrol_globals, const String &p_tesseval_globals, const Vector &p_custom_defines); void version_set_compute_code(RID p_version, const HashMap &p_code, const String &p_uniforms, const String &p_compute_globals, const Vector &p_custom_defines); _FORCE_INLINE_ RID version_get_shader(RID p_version, int p_variant) { diff --git a/servers/rendering/rendering_device.cpp b/servers/rendering/rendering_device.cpp index 59f7b3d9e160..a7a211e7046e 100644 --- a/servers/rendering/rendering_device.cpp +++ b/servers/rendering/rendering_device.cpp @@ -2749,8 +2749,385 @@ RID RenderingDevice::shader_create_from_bytecode(const Vector &p_shader } } -#ifdef DEV_ENABLED - set_resource_name(id, "RID:" + itos(id.get_id())); + PipelineDepthStencilState depth_stencil_state; + if (p_depth_stencil_state.is_valid()) { + depth_stencil_state = p_depth_stencil_state->base; + } + + PipelineColorBlendState color_blend_state; + if (p_blend_state.is_valid()) { + color_blend_state = p_blend_state->base; + for (int i = 0; i < p_blend_state->attachments.size(); i++) { + Ref attachment = p_blend_state->attachments[i]; + if (attachment.is_valid()) { + color_blend_state.attachments.push_back(attachment->base); + } + } + } + + return render_pipeline_create(p_shader, p_framebuffer_format, p_vertex_format, p_render_primitive, rasterization_state, multisample_state, depth_stencil_state, color_blend_state, p_dynamic_state_flags, p_for_render_pass, _get_spec_constants(p_specialization_constants)); +} + +RID RenderingDevice::_compute_pipeline_create(RID p_shader, const TypedArray &p_specialization_constants = TypedArray()) { + return compute_pipeline_create(p_shader, _get_spec_constants(p_specialization_constants)); +} + +RenderingDevice::DrawListID RenderingDevice::_draw_list_begin(RID p_framebuffer, InitialAction p_initial_color_action, FinalAction p_final_color_action, InitialAction p_initial_depth_action, FinalAction p_final_depth_action, const Vector &p_clear_color_values, float p_clear_depth, uint32_t p_clear_stencil, const Rect2 &p_region, const TypedArray &p_storage_textures) { + Vector stextures; + for (int i = 0; i < p_storage_textures.size(); i++) { + stextures.push_back(p_storage_textures[i]); + } + return draw_list_begin(p_framebuffer, p_initial_color_action, p_final_color_action, p_initial_depth_action, p_final_depth_action, p_clear_color_values, p_clear_depth, p_clear_stencil, p_region, stextures); +} + +Vector RenderingDevice::_draw_list_begin_split(RID p_framebuffer, uint32_t p_splits, InitialAction p_initial_color_action, FinalAction p_final_color_action, InitialAction p_initial_depth_action, FinalAction p_final_depth_action, const Vector &p_clear_color_values, float p_clear_depth, uint32_t p_clear_stencil, const Rect2 &p_region, const TypedArray &p_storage_textures) { + Vector splits; + splits.resize(p_splits); + Vector stextures; + for (int i = 0; i < p_storage_textures.size(); i++) { + stextures.push_back(p_storage_textures[i]); + } + draw_list_begin_split(p_framebuffer, p_splits, splits.ptrw(), p_initial_color_action, p_final_color_action, p_initial_depth_action, p_final_depth_action, p_clear_color_values, p_clear_depth, p_clear_stencil, p_region, stextures); + + Vector split_ids; + split_ids.resize(splits.size()); + for (int i = 0; i < splits.size(); i++) { + split_ids.write[i] = splits[i]; + } + + return split_ids; +} + +Vector RenderingDevice::_draw_list_switch_to_next_pass_split(uint32_t p_splits) { + Vector splits; + splits.resize(p_splits); + + Error err = draw_list_switch_to_next_pass_split(p_splits, splits.ptrw()); + ERR_FAIL_COND_V(err != OK, Vector()); + + Vector split_ids; + split_ids.resize(splits.size()); + for (int i = 0; i < splits.size(); i++) { + split_ids.write[i] = splits[i]; + } + + return split_ids; +} + +void RenderingDevice::_draw_list_set_push_constant(DrawListID p_list, const Vector &p_data, uint32_t p_data_size) { + ERR_FAIL_COND((uint32_t)p_data.size() > p_data_size); + draw_list_set_push_constant(p_list, p_data.ptr(), p_data_size); +} + +void RenderingDevice::_compute_list_set_push_constant(ComputeListID p_list, const Vector &p_data, uint32_t p_data_size) { + ERR_FAIL_COND((uint32_t)p_data.size() > p_data_size); + compute_list_set_push_constant(p_list, p_data.ptr(), p_data_size); +} + +Error RenderingDevice::_reflect_spirv(const Vector &p_spirv, SpirvReflectionData &r_reflection_data) { + r_reflection_data = {}; + + for (int i = 0; i < p_spirv.size(); i++) { + ShaderStage stage = p_spirv[i].shader_stage; + ShaderStage stage_flag = (ShaderStage)(1 << p_spirv[i].shader_stage); + + if (p_spirv[i].shader_stage == SHADER_STAGE_COMPUTE) { + r_reflection_data.is_compute = true; + ERR_FAIL_COND_V_MSG(p_spirv.size() != 1, FAILED, + "Compute shaders can only receive one stage, dedicated to compute."); + } + ERR_FAIL_COND_V_MSG(r_reflection_data.stages_mask.has_flag(stage_flag), FAILED, + "Stage " + String(shader_stage_names[p_spirv[i].shader_stage]) + " submitted more than once."); + + { + SpvReflectShaderModule module; + const uint8_t *spirv = p_spirv[i].spir_v.ptr(); + SpvReflectResult result = spvReflectCreateShaderModule(p_spirv[i].spir_v.size(), spirv, &module); + ERR_FAIL_COND_V_MSG(result != SPV_REFLECT_RESULT_SUCCESS, FAILED, + "Reflection of SPIR-V shader stage '" + String(shader_stage_names[p_spirv[i].shader_stage]) + "' failed parsing shader."); + + if (r_reflection_data.is_compute) { + r_reflection_data.compute_local_size[0] = module.entry_points->local_size.x; + r_reflection_data.compute_local_size[1] = module.entry_points->local_size.y; + r_reflection_data.compute_local_size[2] = module.entry_points->local_size.z; + } + uint32_t binding_count = 0; + result = spvReflectEnumerateDescriptorBindings(&module, &binding_count, nullptr); + ERR_FAIL_COND_V_MSG(result != SPV_REFLECT_RESULT_SUCCESS, FAILED, + "Reflection of SPIR-V shader stage '" + String(shader_stage_names[p_spirv[i].shader_stage]) + "' failed enumerating descriptor bindings."); + + if (binding_count > 0) { + // Parse bindings. + + Vector bindings; + bindings.resize(binding_count); + result = spvReflectEnumerateDescriptorBindings(&module, &binding_count, bindings.ptrw()); + + ERR_FAIL_COND_V_MSG(result != SPV_REFLECT_RESULT_SUCCESS, FAILED, + "Reflection of SPIR-V shader stage '" + String(shader_stage_names[p_spirv[i].shader_stage]) + "' failed getting descriptor bindings."); + + for (uint32_t j = 0; j < binding_count; j++) { + const SpvReflectDescriptorBinding &binding = *bindings[j]; + + SpirvReflectionData::Uniform info{}; + + bool need_array_dimensions = false; + bool need_block_size = false; + bool may_be_writable = false; + + switch (binding.descriptor_type) { + case SPV_REFLECT_DESCRIPTOR_TYPE_SAMPLER: { + info.type = UNIFORM_TYPE_SAMPLER; + need_array_dimensions = true; + } break; + case SPV_REFLECT_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER: { + info.type = UNIFORM_TYPE_SAMPLER_WITH_TEXTURE; + need_array_dimensions = true; + } break; + case SPV_REFLECT_DESCRIPTOR_TYPE_SAMPLED_IMAGE: { + info.type = UNIFORM_TYPE_TEXTURE; + need_array_dimensions = true; + } break; + case SPV_REFLECT_DESCRIPTOR_TYPE_STORAGE_IMAGE: { + info.type = UNIFORM_TYPE_IMAGE; + need_array_dimensions = true; + may_be_writable = true; + } break; + case SPV_REFLECT_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER: { + info.type = UNIFORM_TYPE_TEXTURE_BUFFER; + need_array_dimensions = true; + } break; + case SPV_REFLECT_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER: { + info.type = UNIFORM_TYPE_IMAGE_BUFFER; + need_array_dimensions = true; + may_be_writable = true; + } break; + case SPV_REFLECT_DESCRIPTOR_TYPE_UNIFORM_BUFFER: { + info.type = UNIFORM_TYPE_UNIFORM_BUFFER; + need_block_size = true; + } break; + case SPV_REFLECT_DESCRIPTOR_TYPE_STORAGE_BUFFER: { + info.type = UNIFORM_TYPE_STORAGE_BUFFER; + need_block_size = true; + may_be_writable = true; + } break; + case SPV_REFLECT_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC: { + ERR_PRINT("Dynamic uniform buffer not supported."); + continue; + } break; + case SPV_REFLECT_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC: { + ERR_PRINT("Dynamic storage buffer not supported."); + continue; + } break; + case SPV_REFLECT_DESCRIPTOR_TYPE_INPUT_ATTACHMENT: { + info.type = UNIFORM_TYPE_INPUT_ATTACHMENT; + need_array_dimensions = true; + } break; + case SPV_REFLECT_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR: { + ERR_PRINT("Acceleration structure not supported."); + continue; + } break; + } + + if (need_array_dimensions) { + if (binding.array.dims_count == 0) { + info.length = 1; + } else { + for (uint32_t k = 0; k < binding.array.dims_count; k++) { + if (k == 0) { + info.length = binding.array.dims[0]; + } else { + info.length *= binding.array.dims[k]; + } + } + } + + } else if (need_block_size) { + info.length = binding.block.size; + } else { + info.length = 0; + } + + if (may_be_writable) { + info.writable = !(binding.type_description->decoration_flags & SPV_REFLECT_DECORATION_NON_WRITABLE) && !(binding.block.decoration_flags & SPV_REFLECT_DECORATION_NON_WRITABLE); + } else { + info.writable = false; + } + + info.binding = binding.binding; + uint32_t set = binding.set; + + ERR_FAIL_COND_V_MSG(set >= MAX_UNIFORM_SETS, FAILED, + "On shader stage '" + String(shader_stage_names[stage]) + "', uniform '" + binding.name + "' uses a set (" + itos(set) + ") index larger than what is supported (" + itos(MAX_UNIFORM_SETS) + ")."); + + if (set < (uint32_t)r_reflection_data.uniforms.size()) { + // Check if this already exists. + bool exists = false; + for (int k = 0; k < r_reflection_data.uniforms[set].size(); k++) { + if (r_reflection_data.uniforms[set][k].binding == (uint32_t)info.binding) { + // Already exists, verify that it's the same type. + ERR_FAIL_COND_V_MSG(r_reflection_data.uniforms[set][k].type != info.type, FAILED, + "On shader stage '" + String(shader_stage_names[stage]) + "', uniform '" + binding.name + "' trying to reuse location for set=" + itos(set) + ", binding=" + itos(info.binding) + " with different uniform type."); + + // Also, verify that it's the same size. + ERR_FAIL_COND_V_MSG(r_reflection_data.uniforms[set][k].length != info.length, FAILED, + "On shader stage '" + String(shader_stage_names[stage]) + "', uniform '" + binding.name + "' trying to reuse location for set=" + itos(set) + ", binding=" + itos(info.binding) + " with different uniform size."); + + // Also, verify that it has the same writability. + ERR_FAIL_COND_V_MSG(r_reflection_data.uniforms[set][k].writable != info.writable, FAILED, + "On shader stage '" + String(shader_stage_names[stage]) + "', uniform '" + binding.name + "' trying to reuse location for set=" + itos(set) + ", binding=" + itos(info.binding) + " with different writability."); + + // Just append stage mask and return. + r_reflection_data.uniforms.write[set].write[k].stages_mask.set_flag(stage_flag); + exists = true; + break; + } + } + + if (exists) { + continue; // Merged. + } + } + + info.stages_mask.set_flag(stage_flag); + + if (set >= (uint32_t)r_reflection_data.uniforms.size()) { + r_reflection_data.uniforms.resize(set + 1); + } + + r_reflection_data.uniforms.write[set].push_back(info); + } + } + + { + // Specialization constants. + + uint32_t sc_count = 0; + result = spvReflectEnumerateSpecializationConstants(&module, &sc_count, nullptr); + ERR_FAIL_COND_V_MSG(result != SPV_REFLECT_RESULT_SUCCESS, FAILED, + "Reflection of SPIR-V shader stage '" + String(shader_stage_names[p_spirv[i].shader_stage]) + "' failed enumerating specialization constants."); + + if (sc_count) { + Vector spec_constants; + spec_constants.resize(sc_count); + + result = spvReflectEnumerateSpecializationConstants(&module, &sc_count, spec_constants.ptrw()); + ERR_FAIL_COND_V_MSG(result != SPV_REFLECT_RESULT_SUCCESS, FAILED, + "Reflection of SPIR-V shader stage '" + String(shader_stage_names[p_spirv[i].shader_stage]) + "' failed obtaining specialization constants."); + + for (uint32_t j = 0; j < sc_count; j++) { + int32_t existing = -1; + SpirvReflectionData::SpecializationConstant sconst{}; + SpvReflectSpecializationConstant *spc = spec_constants[j]; + + sconst.constant_id = spc->constant_id; + sconst.int_value = 0; // Clear previous value JIC. + switch (spc->constant_type) { + case SPV_REFLECT_SPECIALIZATION_CONSTANT_BOOL: { + sconst.type = PIPELINE_SPECIALIZATION_CONSTANT_TYPE_BOOL; + sconst.bool_value = spc->default_value.int_bool_value != 0; + } break; + case SPV_REFLECT_SPECIALIZATION_CONSTANT_INT: { + sconst.type = PIPELINE_SPECIALIZATION_CONSTANT_TYPE_INT; + sconst.int_value = spc->default_value.int_bool_value; + } break; + case SPV_REFLECT_SPECIALIZATION_CONSTANT_FLOAT: { + sconst.type = PIPELINE_SPECIALIZATION_CONSTANT_TYPE_FLOAT; + sconst.float_value = spc->default_value.float_value; + } break; + } + sconst.stages_mask.set_flag(stage_flag); + + for (int k = 0; k < r_reflection_data.specialization_constants.size(); k++) { + if (r_reflection_data.specialization_constants[k].constant_id == sconst.constant_id) { + ERR_FAIL_COND_V_MSG(r_reflection_data.specialization_constants[k].type != sconst.type, FAILED, "More than one specialization constant used for id (" + itos(sconst.constant_id) + "), but their types differ."); + ERR_FAIL_COND_V_MSG(r_reflection_data.specialization_constants[k].int_value != sconst.int_value, FAILED, "More than one specialization constant used for id (" + itos(sconst.constant_id) + "), but their default values differ."); + existing = k; + break; + } + } + + if (existing > 0) { + r_reflection_data.specialization_constants.write[existing].stages_mask.set_flag(stage_flag); + } else { + r_reflection_data.specialization_constants.push_back(sconst); + } + } + } + } + + if (stage == SHADER_STAGE_VERTEX) { + uint32_t iv_count = 0; + result = spvReflectEnumerateInputVariables(&module, &iv_count, nullptr); + ERR_FAIL_COND_V_MSG(result != SPV_REFLECT_RESULT_SUCCESS, FAILED, + "Reflection of SPIR-V shader stage '" + String(shader_stage_names[p_spirv[i].shader_stage]) + "' failed enumerating input variables."); + + if (iv_count) { + Vector input_vars; + input_vars.resize(iv_count); + + result = spvReflectEnumerateInputVariables(&module, &iv_count, input_vars.ptrw()); + ERR_FAIL_COND_V_MSG(result != SPV_REFLECT_RESULT_SUCCESS, FAILED, + "Reflection of SPIR-V shader stage '" + String(shader_stage_names[p_spirv[i].shader_stage]) + "' failed obtaining input variables."); + + for (uint32_t j = 0; j < iv_count; j++) { + if (input_vars[j] && input_vars[j]->decoration_flags == 0) { // Regular input. + r_reflection_data.vertex_input_mask |= (1ULL << uint32_t(input_vars[j]->location)); + } + } + } + } + + if (stage == SHADER_STAGE_TESSELATION_CONTROL) { + //TODO + } + + if (stage == SHADER_STAGE_TESSELATION_EVALUATION) { + //TODO + } + + if (stage == SHADER_STAGE_FRAGMENT) { + uint32_t ov_count = 0; + result = spvReflectEnumerateOutputVariables(&module, &ov_count, nullptr); + ERR_FAIL_COND_V_MSG(result != SPV_REFLECT_RESULT_SUCCESS, FAILED, + "Reflection of SPIR-V shader stage '" + String(shader_stage_names[p_spirv[i].shader_stage]) + "' failed enumerating output variables."); + + if (ov_count) { + Vector output_vars; + output_vars.resize(ov_count); + + result = spvReflectEnumerateOutputVariables(&module, &ov_count, output_vars.ptrw()); + ERR_FAIL_COND_V_MSG(result != SPV_REFLECT_RESULT_SUCCESS, FAILED, + "Reflection of SPIR-V shader stage '" + String(shader_stage_names[p_spirv[i].shader_stage]) + "' failed obtaining output variables."); + + for (uint32_t j = 0; j < ov_count; j++) { + const SpvReflectInterfaceVariable *refvar = output_vars[j]; + if (refvar != nullptr && refvar->built_in != SpvBuiltInFragDepth) { + r_reflection_data.fragment_output_mask |= 1 << refvar->location; + } + } + } + } + + uint32_t pc_count = 0; + result = spvReflectEnumeratePushConstantBlocks(&module, &pc_count, nullptr); + ERR_FAIL_COND_V_MSG(result != SPV_REFLECT_RESULT_SUCCESS, FAILED, + "Reflection of SPIR-V shader stage '" + String(shader_stage_names[p_spirv[i].shader_stage]) + "' failed enumerating push constants."); + + if (pc_count) { + ERR_FAIL_COND_V_MSG(pc_count > 1, FAILED, + "Reflection of SPIR-V shader stage '" + String(shader_stage_names[p_spirv[i].shader_stage]) + "': Only one push constant is supported, which should be the same across shader stages."); + + Vector pconstants; + pconstants.resize(pc_count); + result = spvReflectEnumeratePushConstantBlocks(&module, &pc_count, pconstants.ptrw()); + ERR_FAIL_COND_V_MSG(result != SPV_REFLECT_RESULT_SUCCESS, FAILED, + "Reflection of SPIR-V shader stage '" + String(shader_stage_names[p_spirv[i].shader_stage]) + "' failed obtaining push constants."); +#if 0 + if (pconstants[0] == nullptr) { + Ref f = FileAccess::open("res://popo.spv", FileAccess::WRITE); + f->store_buffer((const uint8_t *)&SpirV[0], SpirV.size() * sizeof(uint32_t)); + } #endif return id; } diff --git a/servers/rendering/shader_compiler.cpp b/servers/rendering/shader_compiler.cpp index a4ee33ecc0a2..be446a77e4ca 100644 --- a/servers/rendering/shader_compiler.cpp +++ b/servers/rendering/shader_compiler.cpp @@ -718,6 +718,7 @@ String ShaderCompiler::_dump_node_code(const SL::Node *p_node, int p_level, Gene } r_gen_code.stage_globals[STAGE_VERTEX] += interp_mode + "out " + vcode; r_gen_code.stage_globals[STAGE_FRAGMENT] += interp_mode + "in " + vcode; + //TODO index += inc; } diff --git a/servers/rendering/shader_compiler.h b/servers/rendering/shader_compiler.h index 66106d7eb734..4e811b06b757 100644 --- a/servers/rendering/shader_compiler.h +++ b/servers/rendering/shader_compiler.h @@ -40,6 +40,8 @@ class ShaderCompiler { enum Stage { STAGE_VERTEX, STAGE_FRAGMENT, + STAGE_TESSELLATION_CONTROL, + STAGE_TESSELLATION_EVALUATION, STAGE_COMPUTE, STAGE_MAX }; diff --git a/servers/rendering/shader_language.cpp b/servers/rendering/shader_language.cpp index 5b4931edec5a..b71314e09068 100644 --- a/servers/rendering/shader_language.cpp +++ b/servers/rendering/shader_language.cpp @@ -4559,6 +4559,7 @@ bool ShaderLanguage::_is_operator_assign(Operator p_op) const { } bool ShaderLanguage::_validate_varying_assign(ShaderNode::Varying &p_varying, String *r_message) { + //TODO if (current_function != "vertex" && current_function != "fragment") { *r_message = vformat(RTR("Varying may not be assigned in the '%s' function."), current_function); return false; diff --git a/servers/rendering/shader_language.h b/servers/rendering/shader_language.h index edac819a1e1d..326958e7a847 100644 --- a/servers/rendering/shader_language.h +++ b/servers/rendering/shader_language.h @@ -346,10 +346,14 @@ class ShaderLanguage { StringName fragment; StringName vertex; StringName light; + StringName tesscontrol; + StringName tesseval; VaryingFunctionNames() { fragment = "fragment"; vertex = "vertex"; light = "light"; + tesscontrol = "tesselation_control"; + tesseval = "tesselation_evaluation"; } }; @@ -643,6 +647,8 @@ class ShaderLanguage { STAGE_FRAGMENT, // transition stage to STAGE_FRAGMENT_TO_LIGHT, emits warning if it's not used STAGE_VERTEX_TO_FRAGMENT_LIGHT, STAGE_FRAGMENT_TO_LIGHT, + STAGE_TESSELLATION_CONTROL, + STAGE_TESSELLATION_EVALUATION, }; Stage stage = STAGE_UNKNOWN;