diff options
25 files changed, 1054 insertions, 43 deletions
diff --git a/core/io/compression.cpp b/core/io/compression.cpp index 6de626db99..ca56509253 100644 --- a/core/io/compression.cpp +++ b/core/io/compression.cpp @@ -238,7 +238,10 @@ int Compression::decompress_dynamic(Vector<uint8_t> *p_dst_vect, int p_max_dst_s case Z_DATA_ERROR: case Z_MEM_ERROR: case Z_STREAM_ERROR: - WARN_PRINT(strm.msg); + case Z_BUF_ERROR: + if (strm.msg) { + WARN_PRINT(strm.msg); + } (void)inflateEnd(&strm); p_dst_vect->resize(0); return ret; diff --git a/core/io/http_client_tcp.cpp b/core/io/http_client_tcp.cpp index f9b3165a07..f291086808 100644 --- a/core/io/http_client_tcp.cpp +++ b/core/io/http_client_tcp.cpp @@ -590,6 +590,7 @@ PackedByteArray HTTPClientTCP::read_response_body_chunk() { } } if (err != OK) { + ret.resize(_offset); break; } } diff --git a/core/io/multiplayer_api.cpp b/core/io/multiplayer_api.cpp index 51ba8800e4..84f3608e0b 100644 --- a/core/io/multiplayer_api.cpp +++ b/core/io/multiplayer_api.cpp @@ -85,7 +85,7 @@ const MultiplayerAPI::RPCConfig _get_rpc_config_by_id(Node *p_node, uint16_t p_i if (id & (1 << 15)) { id = id & ~(1 << 15); config = p_node->get_node_rpc_methods(); - } else { + } else if (p_node->get_script_instance()) { config = p_node->get_script_instance()->get_rpc_methods(); } if (id < config.size()) { diff --git a/doc/classes/PlaneMesh.xml b/doc/classes/PlaneMesh.xml index c95ba29ea2..56bf98772b 100644 --- a/doc/classes/PlaneMesh.xml +++ b/doc/classes/PlaneMesh.xml @@ -12,6 +12,9 @@ <methods> </methods> <members> + <member name="center_offset" type="Vector3" setter="set_center_offset" getter="get_center_offset" default="Vector3(0, 0, 0)"> + Offset of the generated plane. Useful for particles. + </member> <member name="size" type="Vector2" setter="set_size" getter="get_size" default="Vector2(2, 2)"> Size of the generated plane. </member> diff --git a/doc/classes/QuadMesh.xml b/doc/classes/QuadMesh.xml index 94d638888c..4209e3db14 100644 --- a/doc/classes/QuadMesh.xml +++ b/doc/classes/QuadMesh.xml @@ -13,6 +13,9 @@ <methods> </methods> <members> + <member name="center_offset" type="Vector3" setter="set_center_offset" getter="get_center_offset" default="Vector3(0, 0, 0)"> + Offset of the generated Quad. Useful for particles. + </member> <member name="size" type="Vector2" setter="set_size" getter="get_size" default="Vector2(1, 1)"> Size on the X and Y axes. </member> diff --git a/doc/classes/RDPipelineSpecializationConstant.xml b/doc/classes/RDPipelineSpecializationConstant.xml new file mode 100644 index 0000000000..4d9481b846 --- /dev/null +++ b/doc/classes/RDPipelineSpecializationConstant.xml @@ -0,0 +1,19 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<class name="RDPipelineSpecializationConstant" inherits="RefCounted" version="4.0"> + <brief_description> + </brief_description> + <description> + </description> + <tutorials> + </tutorials> + <methods> + </methods> + <members> + <member name="constant_id" type="int" setter="set_constant_id" getter="get_constant_id" default="0"> + </member> + <member name="value" type="Variant" setter="set_value" getter="get_value"> + </member> + </members> + <constants> + </constants> +</class> diff --git a/doc/classes/RenderingDevice.xml b/doc/classes/RenderingDevice.xml index f2b22af8c6..901a985961 100644 --- a/doc/classes/RenderingDevice.xml +++ b/doc/classes/RenderingDevice.xml @@ -140,6 +140,8 @@ </return> <argument index="0" name="shader" type="RID"> </argument> + <argument index="1" name="specialization_constants" type="RDPipelineSpecializationConstant[]" default="[]"> + </argument> <description> </description> </method> @@ -580,6 +582,8 @@ </argument> <argument index="9" name="for_render_pass" type="int" default="0"> </argument> + <argument index="10" name="specialization_constants" type="RDPipelineSpecializationConstant[]" default="[]"> + </argument> <description> </description> </method> @@ -1709,6 +1713,12 @@ </constant> <constant name="SHADER_LANGUAGE_HLSL" value="1" enum="ShaderLanguage"> </constant> + <constant name="PIPELINE_SPECIALIZATION_CONSTANT_TYPE_BOOL" value="0" enum="PipelineSpecializationConstantType"> + </constant> + <constant name="PIPELINE_SPECIALIZATION_CONSTANT_TYPE_INT" value="1" enum="PipelineSpecializationConstantType"> + </constant> + <constant name="PIPELINE_SPECIALIZATION_CONSTANT_TYPE_FLOAT" value="2" enum="PipelineSpecializationConstantType"> + </constant> <constant name="LIMIT_MAX_BOUND_UNIFORM_SETS" value="0" enum="Limit"> </constant> <constant name="LIMIT_MAX_FRAMEBUFFER_COLOR_ATTACHMENTS" value="1" enum="Limit"> diff --git a/drivers/vulkan/rendering_device_vulkan.cpp b/drivers/vulkan/rendering_device_vulkan.cpp index 6c1f1e4852..d3d49503d8 100644 --- a/drivers/vulkan/rendering_device_vulkan.cpp +++ b/drivers/vulkan/rendering_device_vulkan.cpp @@ -4374,6 +4374,8 @@ RID RenderingDeviceVulkan::shader_create(const Vector<ShaderStageData> &p_stages uint32_t stages_processed = 0; + Vector<Shader::SpecializationConstant> specialization_constants; + bool is_compute = false; uint32_t compute_local_size[3] = { 0, 0, 0 }; @@ -4560,6 +4562,62 @@ RID RenderingDeviceVulkan::shader_create(const Vector<ShaderStageData> &p_stages } } + { + //specialization constants + + uint32_t sc_count = 0; + result = spvReflectEnumerateSpecializationConstants(&module, &sc_count, nullptr); + ERR_FAIL_COND_V_MSG(result != SPV_REFLECT_RESULT_SUCCESS, RID(), + "Reflection of SPIR-V shader stage '" + String(shader_stage_names[p_stages[i].shader_stage]) + "' failed enumerating specialization constants."); + + if (sc_count) { + Vector<SpvReflectSpecializationConstant *> 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, RID(), + "Reflection of SPIR-V shader stage '" + String(shader_stage_names[p_stages[i].shader_stage]) + "' failed obtaining specialization constants."); + + for (uint32_t j = 0; j < sc_count; j++) { + int32_t existing = -1; + Shader::SpecializationConstant sconst; + sconst.constant.constant_id = spec_constants[j]->constant_id; + switch (spec_constants[j]->constant_type) { + case SPV_REFLECT_SPECIALIZATION_CONSTANT_BOOL: { + sconst.constant.type = PIPELINE_SPECIALIZATION_CONSTANT_TYPE_BOOL; + sconst.constant.bool_value = spec_constants[j]->default_value.int_bool_value != 0; + } break; + case SPV_REFLECT_SPECIALIZATION_CONSTANT_INT: { + sconst.constant.type = PIPELINE_SPECIALIZATION_CONSTANT_TYPE_INT; + sconst.constant.int_value = spec_constants[j]->default_value.int_bool_value; + } break; + case SPV_REFLECT_SPECIALIZATION_CONSTANT_FLOAT: { + sconst.constant.type = PIPELINE_SPECIALIZATION_CONSTANT_TYPE_FLOAT; + sconst.constant.float_value = spec_constants[j]->default_value.float_value; + } break; + } + sconst.stage_flags = 1 << p_stages[i].shader_stage; + + print_line("spec constant " + itos(i) + ": " + String(spec_constants[j]->name) + " type " + itos(spec_constants[j]->constant_type) + " id " + itos(spec_constants[j]->constant_id)); + + for (int k = 0; k < specialization_constants.size(); k++) { + if (specialization_constants[k].constant.constant_id == sconst.constant.constant_id) { + ERR_FAIL_COND_V_MSG(specialization_constants[k].constant.type != sconst.constant.type, RID(), "More than one specialization constant used for id (" + itos(sconst.constant.constant_id) + "), but their types differ."); + ERR_FAIL_COND_V_MSG(specialization_constants[k].constant.int_value != sconst.constant.int_value, RID(), "More than one specialization constant used for id (" + itos(sconst.constant.constant_id) + "), but their default values differ."); + existing = k; + break; + } + } + + if (existing > 0) { + specialization_constants.write[existing].stage_flags |= sconst.stage_flags; + } else { + specialization_constants.push_back(sconst); + } + } + } + } + if (stage == SHADER_STAGE_VERTEX) { uint32_t iv_count = 0; result = spvReflectEnumerateInputVariables(&module, &iv_count, nullptr); @@ -4656,6 +4714,7 @@ RID RenderingDeviceVulkan::shader_create(const Vector<ShaderStageData> &p_stages shader.compute_local_size[0] = compute_local_size[0]; shader.compute_local_size[1] = compute_local_size[1]; shader.compute_local_size[2] = compute_local_size[2]; + shader.specialization_constants = specialization_constants; String error_text; @@ -5651,7 +5710,7 @@ Vector<uint8_t> RenderingDeviceVulkan::buffer_get_data(RID p_buffer) { /**** RENDER PIPELINE ****/ /*************************/ -RID RenderingDeviceVulkan::render_pipeline_create(RID p_shader, FramebufferFormatID p_framebuffer_format, VertexFormatID p_vertex_format, RenderPrimitive p_render_primitive, const PipelineRasterizationState &p_rasterization_state, const PipelineMultisampleState &p_multisample_state, const PipelineDepthStencilState &p_depth_stencil_state, const PipelineColorBlendState &p_blend_state, int p_dynamic_state_flags, uint32_t p_for_render_pass) { +RID RenderingDeviceVulkan::render_pipeline_create(RID p_shader, FramebufferFormatID p_framebuffer_format, VertexFormatID p_vertex_format, RenderPrimitive p_render_primitive, const PipelineRasterizationState &p_rasterization_state, const PipelineMultisampleState &p_multisample_state, const PipelineDepthStencilState &p_depth_stencil_state, const PipelineColorBlendState &p_blend_state, int p_dynamic_state_flags, uint32_t p_for_render_pass, const Vector<PipelineSpecializationConstant> &p_specialization_constants) { _THREAD_SAFE_METHOD_ //needs a shader @@ -5969,8 +6028,63 @@ RID RenderingDeviceVulkan::render_pipeline_create(RID p_shader, FramebufferForma graphics_pipeline_create_info.pNext = nullptr; graphics_pipeline_create_info.flags = 0; - graphics_pipeline_create_info.stageCount = shader->pipeline_stages.size(); - graphics_pipeline_create_info.pStages = shader->pipeline_stages.ptr(); + Vector<VkPipelineShaderStageCreateInfo> pipeline_stages = shader->pipeline_stages; + Vector<VkSpecializationInfo> specialization_info; + Vector<Vector<VkSpecializationMapEntry>> specialization_map_entries; + Vector<uint32_t> specialization_constant_data; + + if (shader->specialization_constants.size()) { + specialization_constant_data.resize(shader->specialization_constants.size()); + uint32_t *data_ptr = specialization_constant_data.ptrw(); + specialization_info.resize(pipeline_stages.size()); + specialization_map_entries.resize(pipeline_stages.size()); + for (int i = 0; i < shader->specialization_constants.size(); i++) { + //see if overriden + const Shader::SpecializationConstant &sc = shader->specialization_constants[i]; + data_ptr[i] = sc.constant.int_value; //just copy the 32 bits + + for (int j = 0; j < p_specialization_constants.size(); j++) { + const PipelineSpecializationConstant &psc = p_specialization_constants[j]; + if (psc.constant_id == sc.constant.constant_id) { + ERR_FAIL_COND_V_MSG(psc.type != sc.constant.type, RID(), "Specialization constant provided for id (" + itos(sc.constant.constant_id) + ") is of the wrong type."); + data_ptr[i] = sc.constant.int_value; + break; + } + } + + VkSpecializationMapEntry entry; + + entry.constantID = sc.constant.constant_id; + entry.offset = i * sizeof(uint32_t); + entry.size = sizeof(uint32_t); + + for (int j = 0; j < SHADER_STAGE_MAX; j++) { + if (sc.stage_flags & (1 << j)) { + VkShaderStageFlagBits stage = shader_stage_masks[j]; + for (int k = 0; k < pipeline_stages.size(); k++) { + if (pipeline_stages[k].stage == stage) { + specialization_map_entries.write[k].push_back(entry); + } + } + } + } + } + + for (int k = 0; k < pipeline_stages.size(); k++) { + if (specialization_map_entries[k].size()) { + specialization_info.write[k].dataSize = specialization_constant_data.size() * sizeof(uint32_t); + specialization_info.write[k].pData = data_ptr; + specialization_info.write[k].mapEntryCount = specialization_map_entries[k].size(); + specialization_info.write[k].pMapEntries = specialization_map_entries[k].ptr(); + + pipeline_stages.write[k].pSpecializationInfo = specialization_info.ptr(); + } + } + } + + graphics_pipeline_create_info.stageCount = pipeline_stages.size(); + graphics_pipeline_create_info.pStages = pipeline_stages.ptr(); + graphics_pipeline_create_info.pVertexInputState = &pipeline_vertex_input_state_create_info; graphics_pipeline_create_info.pInputAssemblyState = &input_assembly_create_info; graphics_pipeline_create_info.pTessellationState = &tessellation_create_info; @@ -6039,7 +6153,7 @@ bool RenderingDeviceVulkan::render_pipeline_is_valid(RID p_pipeline) { /**** COMPUTE PIPELINE ****/ /**************************/ -RID RenderingDeviceVulkan::compute_pipeline_create(RID p_shader) { +RID RenderingDeviceVulkan::compute_pipeline_create(RID p_shader, const Vector<PipelineSpecializationConstant> &p_specialization_constants) { _THREAD_SAFE_METHOD_ //needs a shader @@ -6061,6 +6175,44 @@ RID RenderingDeviceVulkan::compute_pipeline_create(RID p_shader) { compute_pipeline_create_info.basePipelineHandle = VK_NULL_HANDLE; compute_pipeline_create_info.basePipelineIndex = 0; + VkSpecializationInfo specialization_info; + Vector<VkSpecializationMapEntry> specialization_map_entries; + Vector<uint32_t> specialization_constant_data; + + if (shader->specialization_constants.size()) { + specialization_constant_data.resize(shader->specialization_constants.size()); + uint32_t *data_ptr = specialization_constant_data.ptrw(); + for (int i = 0; i < shader->specialization_constants.size(); i++) { + //see if overriden + const Shader::SpecializationConstant &sc = shader->specialization_constants[i]; + data_ptr[i] = sc.constant.int_value; //just copy the 32 bits + + for (int j = 0; j < p_specialization_constants.size(); j++) { + const PipelineSpecializationConstant &psc = p_specialization_constants[j]; + if (psc.constant_id == sc.constant.constant_id) { + ERR_FAIL_COND_V_MSG(psc.type != sc.constant.type, RID(), "Specialization constant provided for id (" + itos(sc.constant.constant_id) + ") is of the wrong type."); + data_ptr[i] = sc.constant.int_value; + break; + } + } + + VkSpecializationMapEntry entry; + + entry.constantID = sc.constant.constant_id; + entry.offset = i * sizeof(uint32_t); + entry.size = sizeof(uint32_t); + + specialization_map_entries.push_back(entry); + } + + specialization_info.dataSize = specialization_constant_data.size() * sizeof(uint32_t); + specialization_info.pData = data_ptr; + specialization_info.mapEntryCount = specialization_map_entries.size(); + specialization_info.pMapEntries = specialization_map_entries.ptr(); + + compute_pipeline_create_info.stage.pSpecializationInfo = &specialization_info; + } + ComputePipeline pipeline; VkResult err = vkCreateComputePipelines(device, VK_NULL_HANDLE, 1, &compute_pipeline_create_info, nullptr, &pipeline.pipeline); ERR_FAIL_COND_V_MSG(err, RID(), "vkCreateComputePipelines failed with error " + itos(err) + "."); diff --git a/drivers/vulkan/rendering_device_vulkan.h b/drivers/vulkan/rendering_device_vulkan.h index ff9ad71268..8b95ff43b8 100644 --- a/drivers/vulkan/rendering_device_vulkan.h +++ b/drivers/vulkan/rendering_device_vulkan.h @@ -623,11 +623,17 @@ class RenderingDeviceVulkan : public RenderingDevice { uint32_t compute_local_size[3] = { 0, 0, 0 }; + struct SpecializationConstant { + PipelineSpecializationConstant constant; + uint32_t stage_flags = 0; + }; + bool is_compute = false; int max_output = 0; Vector<Set> sets; Vector<uint32_t> set_formats; Vector<VkPipelineShaderStageCreateInfo> pipeline_stages; + Vector<SpecializationConstant> specialization_constants; VkPipelineLayout pipeline_layout = VK_NULL_HANDLE; }; @@ -1100,14 +1106,14 @@ public: /**** RENDER PIPELINE ****/ /*************************/ - virtual RID render_pipeline_create(RID p_shader, FramebufferFormatID p_framebuffer_format, VertexFormatID p_vertex_format, RenderPrimitive p_render_primitive, const PipelineRasterizationState &p_rasterization_state, const PipelineMultisampleState &p_multisample_state, const PipelineDepthStencilState &p_depth_stencil_state, const PipelineColorBlendState &p_blend_state, int p_dynamic_state_flags = 0, uint32_t p_for_render_pass = 0); + virtual RID render_pipeline_create(RID p_shader, FramebufferFormatID p_framebuffer_format, VertexFormatID p_vertex_format, RenderPrimitive p_render_primitive, const PipelineRasterizationState &p_rasterization_state, const PipelineMultisampleState &p_multisample_state, const PipelineDepthStencilState &p_depth_stencil_state, const PipelineColorBlendState &p_blend_state, int p_dynamic_state_flags = 0, uint32_t p_for_render_pass = 0, const Vector<PipelineSpecializationConstant> &p_specialization_constants = Vector<PipelineSpecializationConstant>()); virtual bool render_pipeline_is_valid(RID p_pipeline); /**************************/ /**** COMPUTE PIPELINE ****/ /**************************/ - virtual RID compute_pipeline_create(RID p_shader); + virtual RID compute_pipeline_create(RID p_shader, const Vector<PipelineSpecializationConstant> &p_specialization_constants = Vector<PipelineSpecializationConstant>()); virtual bool compute_pipeline_is_valid(RID p_pipeline); /****************/ diff --git a/editor/icons/ImmediateMesh.svg b/editor/icons/ImmediateMesh.svg new file mode 100644 index 0000000000..9521530876 --- /dev/null +++ b/editor/icons/ImmediateMesh.svg @@ -0,0 +1 @@ +<svg height="16" viewBox="0 0 14.999999 14.999999" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m2 2v2h5v-2zm5 2v3h2v-3zm2-2v2h5v-2zm-2 7v3h2v-3zm-5 3v2h5v-2zm7 0v2h5v-2z" fill="#ffca5f" transform="scale(.93749994)"/></svg> diff --git a/editor/plugins/visual_shader_editor_plugin.cpp b/editor/plugins/visual_shader_editor_plugin.cpp index 94863bf722..30643b7ecd 100644 --- a/editor/plugins/visual_shader_editor_plugin.cpp +++ b/editor/plugins/visual_shader_editor_plugin.cpp @@ -110,6 +110,7 @@ void VisualShaderGraphPlugin::_bind_methods() { ClassDB::bind_method("set_uniform_name", &VisualShaderGraphPlugin::set_uniform_name); ClassDB::bind_method("set_expression", &VisualShaderGraphPlugin::set_expression); ClassDB::bind_method("update_curve", &VisualShaderGraphPlugin::update_curve); + ClassDB::bind_method("update_curve3", &VisualShaderGraphPlugin::update_curve3); ClassDB::bind_method("update_constant", &VisualShaderGraphPlugin::update_constant); } @@ -211,9 +212,19 @@ void VisualShaderGraphPlugin::set_uniform_name(VisualShader::Type p_type, int p_ } void VisualShaderGraphPlugin::update_curve(int p_node_id) { - if (links.has(p_node_id) && links[p_node_id].curve_editor) { + if (links.has(p_node_id) && links[p_node_id].curve_editors[0]) { if (((VisualShaderNodeCurveTexture *)links[p_node_id].visual_node)->get_texture().is_valid()) { - links[p_node_id].curve_editor->set_curve(((VisualShaderNodeCurveTexture *)links[p_node_id].visual_node)->get_texture()->get_curve()); + links[p_node_id].curve_editors[0]->set_curve(((VisualShaderNodeCurveTexture *)links[p_node_id].visual_node)->get_texture()->get_curve()); + } + } +} + +void VisualShaderGraphPlugin::update_curve3(int p_node_id) { + if (links.has(p_node_id) && links[p_node_id].curve_editors[0] && links[p_node_id].curve_editors[1] && links[p_node_id].curve_editors[2]) { + if (((VisualShaderNodeCurve3Texture *)links[p_node_id].visual_node)->get_texture().is_valid()) { + links[p_node_id].curve_editors[0]->set_curve(((VisualShaderNodeCurve3Texture *)links[p_node_id].visual_node)->get_texture()->get_curve_x()); + links[p_node_id].curve_editors[1]->set_curve(((VisualShaderNodeCurve3Texture *)links[p_node_id].visual_node)->get_texture()->get_curve_y()); + links[p_node_id].curve_editors[2]->set_curve(((VisualShaderNodeCurve3Texture *)links[p_node_id].visual_node)->get_texture()->get_curve_z()); } } } @@ -265,8 +276,8 @@ void VisualShaderGraphPlugin::register_expression_edit(int p_node_id, CodeEdit * links[p_node_id].expression_edit = p_expression_edit; } -void VisualShaderGraphPlugin::register_curve_editor(int p_node_id, CurveEditor *p_curve_editor) { - links[p_node_id].curve_editor = p_curve_editor; +void VisualShaderGraphPlugin::register_curve_editor(int p_node_id, int p_index, CurveEditor *p_curve_editor) { + links[p_node_id].curve_editors[p_index] = p_curve_editor; } void VisualShaderGraphPlugin::update_uniform_refs() { @@ -312,7 +323,7 @@ void VisualShaderGraphPlugin::make_dirty(bool p_enabled) { } void VisualShaderGraphPlugin::register_link(VisualShader::Type p_type, int p_id, VisualShaderNode *p_visual_node, GraphNode *p_graph_node) { - links.insert(p_id, { p_type, p_visual_node, p_graph_node, p_visual_node->get_output_port_for_preview() != -1, -1, Map<int, InputPort>(), Map<int, Port>(), nullptr, nullptr, nullptr, nullptr, nullptr }); + links.insert(p_id, { p_type, p_visual_node, p_graph_node, p_visual_node->get_output_port_for_preview() != -1, -1, Map<int, InputPort>(), Map<int, Port>(), nullptr, nullptr, nullptr, nullptr, { nullptr, nullptr, nullptr } }); } void VisualShaderGraphPlugin::register_output_port(int p_node_id, int p_port, TextureButton *p_button) { @@ -472,6 +483,18 @@ void VisualShaderGraphPlugin::add_node(VisualShader::Type p_type, int p_id) { custom_editor = hbox; } + Ref<VisualShaderNodeCurve3Texture> curve3 = vsnode; + if (curve3.is_valid()) { + if (curve3->get_texture().is_valid() && !curve3->get_texture()->is_connected("changed", callable_mp(VisualShaderEditor::get_singleton()->get_graph_plugin(), &VisualShaderGraphPlugin::update_curve3))) { + curve3->get_texture()->connect("changed", callable_mp(VisualShaderEditor::get_singleton()->get_graph_plugin(), &VisualShaderGraphPlugin::update_curve3), varray(p_id)); + } + + HBoxContainer *hbox = memnew(HBoxContainer); + custom_editor->set_h_size_flags(Control::SIZE_EXPAND_FILL); + hbox->add_child(custom_editor); + custom_editor = hbox; + } + Ref<VisualShaderNodeFloatConstant> float_const = vsnode; if (float_const.is_valid()) { HBoxContainer *hbox = memnew(HBoxContainer); @@ -495,19 +518,12 @@ void VisualShaderGraphPlugin::add_node(VisualShader::Type p_type, int p_id) { port_offset++; node->add_child(custom_editor); - if (curve.is_valid()) { + bool is_curve = curve.is_valid() || curve3.is_valid(); + + if (is_curve) { VisualShaderEditor::get_singleton()->graph->add_child(node); VisualShaderEditor::get_singleton()->_update_created_node(node); - CurveEditor *curve_editor = memnew(CurveEditor); - node->add_child(curve_editor); - register_curve_editor(p_id, curve_editor); - curve_editor->set_custom_minimum_size(Size2(300, 0)); - curve_editor->set_h_size_flags(Control::SIZE_EXPAND_FILL); - if (curve->get_texture().is_valid()) { - curve_editor->set_curve(curve->get_texture()->get_curve()); - } - TextureButton *preview = memnew(TextureButton); preview->set_toggle_mode(true); preview->set_normal_texture(VisualShaderEditor::get_singleton()->get_theme_icon("GuiVisibilityHidden", "EditorIcons")); @@ -519,12 +535,59 @@ void VisualShaderGraphPlugin::add_node(VisualShader::Type p_type, int p_id) { preview->connect("pressed", callable_mp(VisualShaderEditor::get_singleton(), &VisualShaderEditor::_preview_select_port), varray(p_id, 0), CONNECT_DEFERRED); custom_editor->add_child(preview); + if (vsnode->get_output_port_for_preview() >= 0) { + show_port_preview(p_type, p_id, vsnode->get_output_port_for_preview()); + } + } + + if (curve.is_valid()) { + CurveEditor *curve_editor = memnew(CurveEditor); + node->add_child(curve_editor); + register_curve_editor(p_id, 0, curve_editor); + curve_editor->set_custom_minimum_size(Size2(300, 0)); + curve_editor->set_h_size_flags(Control::SIZE_EXPAND_FILL); + if (curve->get_texture().is_valid()) { + curve_editor->set_curve(curve->get_texture()->get_curve()); + } + } + + if (curve3.is_valid()) { + CurveEditor *curve_editor_x = memnew(CurveEditor); + node->add_child(curve_editor_x); + register_curve_editor(p_id, 0, curve_editor_x); + curve_editor_x->set_custom_minimum_size(Size2(300, 0)); + curve_editor_x->set_h_size_flags(Control::SIZE_EXPAND_FILL); + if (curve3->get_texture().is_valid()) { + curve_editor_x->set_curve(curve3->get_texture()->get_curve_x()); + } + + CurveEditor *curve_editor_y = memnew(CurveEditor); + node->add_child(curve_editor_y); + register_curve_editor(p_id, 1, curve_editor_y); + curve_editor_y->set_custom_minimum_size(Size2(300, 0)); + curve_editor_y->set_h_size_flags(Control::SIZE_EXPAND_FILL); + if (curve3->get_texture().is_valid()) { + curve_editor_y->set_curve(curve3->get_texture()->get_curve_y()); + } + + CurveEditor *curve_editor_z = memnew(CurveEditor); + node->add_child(curve_editor_z); + register_curve_editor(p_id, 2, curve_editor_z); + curve_editor_z->set_custom_minimum_size(Size2(300, 0)); + curve_editor_z->set_h_size_flags(Control::SIZE_EXPAND_FILL); + if (curve3->get_texture().is_valid()) { + curve_editor_z->set_curve(curve3->get_texture()->get_curve_z()); + } + } + + if (is_curve) { VisualShaderNode::PortType port_left = vsnode->get_input_port_type(0); VisualShaderNode::PortType port_right = vsnode->get_output_port_type(0); node->set_slot(0, true, port_left, type_color[port_left], true, port_right, type_color[port_right]); VisualShaderEditor::get_singleton()->call_deferred("_set_node_size", (int)p_type, p_id, size); } + if (vsnode->is_use_prop_slots()) { return; } @@ -2387,6 +2450,11 @@ void VisualShaderEditor::_add_node(int p_idx, int p_op_idx, String p_resource_pa graph_plugin->call_deferred("update_curve", id_to_use); } + VisualShaderNodeCurve3Texture *curve3 = Object::cast_to<VisualShaderNodeCurve3Texture>(vsnode.ptr()); + if (curve3) { + graph_plugin->call_deferred("update_curve3", id_to_use); + } + if (p_resource_path.is_empty()) { undo_redo->commit_action(); } else { @@ -2395,7 +2463,7 @@ void VisualShaderEditor::_add_node(int p_idx, int p_op_idx, String p_resource_pa VisualShaderNodeTexture *texture2d = Object::cast_to<VisualShaderNodeTexture>(vsnode.ptr()); VisualShaderNodeTexture3D *texture3d = Object::cast_to<VisualShaderNodeTexture3D>(vsnode.ptr()); - if (texture2d || texture3d || curve) { + if (texture2d || texture3d || curve || curve3) { undo_redo->add_do_method(vsnode.ptr(), "set_texture", ResourceLoader::load(p_resource_path)); return; } @@ -3590,6 +3658,10 @@ void VisualShaderEditor::drop_data_fw(const Point2 &p_point, const Variant &p_da saved_node_pos = p_point + Vector2(0, i * 250 * EDSCALE); saved_node_pos_dirty = true; _add_node(curve_node_option_idx, -1, arr[i], i); + } else if (type == "Curve3Texture") { + saved_node_pos = p_point + Vector2(0, i * 250 * EDSCALE); + saved_node_pos_dirty = true; + _add_node(curve3_node_option_idx, -1, arr[i], i); } else if (ClassDB::get_parent_class(type) == "Texture2D") { saved_node_pos = p_point + Vector2(0, i * 250 * EDSCALE); saved_node_pos_dirty = true; @@ -4311,6 +4383,8 @@ VisualShaderEditor::VisualShaderEditor() { add_options.push_back(AddOption("CubeMap", "Textures", "Functions", "VisualShaderNodeCubemap", TTR("Perform the cubic texture lookup."), -1, -1)); curve_node_option_idx = add_options.size(); add_options.push_back(AddOption("CurveTexture", "Textures", "Functions", "VisualShaderNodeCurveTexture", TTR("Perform the curve texture lookup."), -1, -1)); + curve3_node_option_idx = add_options.size(); + add_options.push_back(AddOption("CurveTexture3", "Textures", "Functions", "VisualShaderNodeCurve3Texture", TTR("Perform the ternary curve texture lookup."), -1, -1)); texture2d_node_option_idx = add_options.size(); add_options.push_back(AddOption("Texture2D", "Textures", "Functions", "VisualShaderNodeTexture", TTR("Perform the 2D texture lookup."), -1, -1)); texture2d_array_node_option_idx = add_options.size(); diff --git a/editor/plugins/visual_shader_editor_plugin.h b/editor/plugins/visual_shader_editor_plugin.h index d549a35306..2b354db7b3 100644 --- a/editor/plugins/visual_shader_editor_plugin.h +++ b/editor/plugins/visual_shader_editor_plugin.h @@ -75,7 +75,7 @@ private: LineEdit *uniform_name = nullptr; OptionButton *const_op = nullptr; CodeEdit *expression_edit = nullptr; - CurveEditor *curve_editor = nullptr; + CurveEditor *curve_editors[3] = { nullptr, nullptr, nullptr }; }; Ref<VisualShader> visual_shader; @@ -97,7 +97,7 @@ public: void register_default_input_button(int p_node_id, int p_port_id, Button *p_button); void register_constant_option_btn(int p_node_id, OptionButton *p_button); void register_expression_edit(int p_node_id, CodeEdit *p_expression_edit); - void register_curve_editor(int p_node_id, CurveEditor *p_curve_editor); + void register_curve_editor(int p_node_id, int p_index, CurveEditor *p_curve_editor); void clear_links(); void set_shader_type(VisualShader::Type p_type); bool is_preview_visible(int p_id) const; @@ -117,6 +117,7 @@ public: void update_uniform_refs(); void set_uniform_name(VisualShader::Type p_type, int p_node_id, const String &p_name); void update_curve(int p_node_id); + void update_curve3(int p_node_id); void update_constant(VisualShader::Type p_type, int p_node_id); void set_expression(VisualShader::Type p_type, int p_node_id, const String &p_expression); int get_constant_index(float p_constant) const; @@ -289,6 +290,7 @@ class VisualShaderEditor : public VBoxContainer { int texture3d_node_option_idx; int custom_node_option_idx; int curve_node_option_idx; + int curve3_node_option_idx; List<String> keyword_list; List<VisualShaderNodeUniformRef> uniform_refs; diff --git a/scene/register_scene_types.cpp b/scene/register_scene_types.cpp index 24a9b12733..ea0df685a1 100644 --- a/scene/register_scene_types.cpp +++ b/scene/register_scene_types.cpp @@ -586,6 +586,7 @@ void register_scene_types() { ClassDB::register_class<VisualShaderNodeTransformDecompose>(); ClassDB::register_class<VisualShaderNodeTexture>(); ClassDB::register_class<VisualShaderNodeCurveTexture>(); + ClassDB::register_class<VisualShaderNodeCurve3Texture>(); ClassDB::register_virtual_class<VisualShaderNodeSample3D>(); ClassDB::register_class<VisualShaderNodeTexture2DArray>(); ClassDB::register_class<VisualShaderNodeTexture3D>(); diff --git a/scene/resources/primitive_meshes.cpp b/scene/resources/primitive_meshes.cpp index cc3346d182..dfa45cc810 100644 --- a/scene/resources/primitive_meshes.cpp +++ b/scene/resources/primitive_meshes.cpp @@ -714,7 +714,7 @@ int BoxMesh::get_subdivide_depth() const { BoxMesh::BoxMesh() {} /** - CylinderMesh + CylinderMesh */ void CylinderMesh::_create_mesh_array(Array &p_arr) const { @@ -955,7 +955,7 @@ void PlaneMesh::_create_mesh_array(Array &p_arr) const { u /= (subdivide_w + 1.0); v /= (subdivide_d + 1.0); - points.push_back(Vector3(-x, 0.0, -z)); + points.push_back(Vector3(-x, 0.0, -z) + center_offset); normals.push_back(Vector3(0.0, 1.0, 0.0)); ADD_TANGENT(1.0, 0.0, 0.0, 1.0); uvs.push_back(Vector2(1.0 - u, 1.0 - v)); /* 1.0 - uv to match orientation with Quad */ @@ -993,10 +993,13 @@ void PlaneMesh::_bind_methods() { ClassDB::bind_method(D_METHOD("get_subdivide_width"), &PlaneMesh::get_subdivide_width); ClassDB::bind_method(D_METHOD("set_subdivide_depth", "subdivide"), &PlaneMesh::set_subdivide_depth); ClassDB::bind_method(D_METHOD("get_subdivide_depth"), &PlaneMesh::get_subdivide_depth); + ClassDB::bind_method(D_METHOD("set_center_offset", "offset"), &PlaneMesh::set_center_offset); + ClassDB::bind_method(D_METHOD("get_center_offset"), &PlaneMesh::get_center_offset); ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "size"), "set_size", "get_size"); ADD_PROPERTY(PropertyInfo(Variant::INT, "subdivide_width", PROPERTY_HINT_RANGE, "0,100,1,or_greater"), "set_subdivide_width", "get_subdivide_width"); ADD_PROPERTY(PropertyInfo(Variant::INT, "subdivide_depth", PROPERTY_HINT_RANGE, "0,100,1,or_greater"), "set_subdivide_depth", "get_subdivide_depth"); + ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "center_offset"), "set_center_offset", "get_center_offset"); } void PlaneMesh::set_size(const Size2 &p_size) { @@ -1026,6 +1029,15 @@ int PlaneMesh::get_subdivide_depth() const { return subdivide_d; } +void PlaneMesh::set_center_offset(const Vector3 p_offset) { + center_offset = p_offset; + _request_update(); +} + +Vector3 PlaneMesh::get_center_offset() const { + return center_offset; +} + PlaneMesh::PlaneMesh() {} /** @@ -1326,10 +1338,10 @@ void QuadMesh::_create_mesh_array(Array &p_arr) const { Vector2 _size = Vector2(size.x / 2.0f, size.y / 2.0f); Vector3 quad_faces[4] = { - Vector3(-_size.x, -_size.y, 0), - Vector3(-_size.x, _size.y, 0), - Vector3(_size.x, _size.y, 0), - Vector3(_size.x, -_size.y, 0), + Vector3(-_size.x, -_size.y, 0) + center_offset, + Vector3(-_size.x, _size.y, 0) + center_offset, + Vector3(_size.x, _size.y, 0) + center_offset, + Vector3(_size.x, -_size.y, 0) + center_offset, }; static const int indices[6] = { @@ -1365,7 +1377,11 @@ void QuadMesh::_create_mesh_array(Array &p_arr) const { void QuadMesh::_bind_methods() { ClassDB::bind_method(D_METHOD("set_size", "size"), &QuadMesh::set_size); ClassDB::bind_method(D_METHOD("get_size"), &QuadMesh::get_size); + ClassDB::bind_method(D_METHOD("set_center_offset", "center_offset"), &QuadMesh::set_center_offset); + ClassDB::bind_method(D_METHOD("get_center_offset"), &QuadMesh::get_center_offset); + ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "size"), "set_size", "get_size"); + ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "center_offset"), "set_center_offset", "get_center_offset"); } QuadMesh::QuadMesh() { @@ -1381,6 +1397,15 @@ Size2 QuadMesh::get_size() const { return size; } +void QuadMesh::set_center_offset(Vector3 p_center_offset) { + center_offset = p_center_offset; + _request_update(); +} + +Vector3 QuadMesh::get_center_offset() const { + return center_offset; +} + /** SphereMesh */ diff --git a/scene/resources/primitive_meshes.h b/scene/resources/primitive_meshes.h index bd6f94921e..a3de34d3e3 100644 --- a/scene/resources/primitive_meshes.h +++ b/scene/resources/primitive_meshes.h @@ -211,6 +211,7 @@ private: Size2 size = Size2(2.0, 2.0); int subdivide_w = 0; int subdivide_d = 0; + Vector3 center_offset; protected: static void _bind_methods(); @@ -226,6 +227,9 @@ public: void set_subdivide_depth(const int p_divisions); int get_subdivide_depth() const; + void set_center_offset(const Vector3 p_offset); + Vector3 get_center_offset() const; + PlaneMesh(); }; @@ -274,6 +278,7 @@ class QuadMesh : public PrimitiveMesh { private: Size2 size = Size2(1.0, 1.0); + Vector3 center_offset; protected: static void _bind_methods(); @@ -284,6 +289,9 @@ public: void set_size(const Size2 &p_size); Size2 get_size() const; + + void set_center_offset(const Vector3 p_offset); + Vector3 get_center_offset() const; }; /** diff --git a/scene/resources/visual_shader_nodes.cpp b/scene/resources/visual_shader_nodes.cpp index d3b094de31..4e73b8db44 100644 --- a/scene/resources/visual_shader_nodes.cpp +++ b/scene/resources/visual_shader_nodes.cpp @@ -805,7 +805,7 @@ void VisualShaderNodeTexture::_bind_methods() { VisualShaderNodeTexture::VisualShaderNodeTexture() { } -////////////// Curve +////////////// CurveTexture String VisualShaderNodeCurveTexture::get_caption() const { return "CurveTexture"; @@ -889,6 +889,90 @@ VisualShaderNodeCurveTexture::VisualShaderNodeCurveTexture() { allow_v_resize = false; } +////////////// Curve3Texture + +String VisualShaderNodeCurve3Texture::get_caption() const { + return "Curve3Texture"; +} + +int VisualShaderNodeCurve3Texture::get_input_port_count() const { + return 1; +} + +VisualShaderNodeCurve3Texture::PortType VisualShaderNodeCurve3Texture::get_input_port_type(int p_port) const { + return PORT_TYPE_SCALAR; +} + +String VisualShaderNodeCurve3Texture::get_input_port_name(int p_port) const { + return String(); +} + +int VisualShaderNodeCurve3Texture::get_output_port_count() const { + return 1; +} + +VisualShaderNodeCurve3Texture::PortType VisualShaderNodeCurve3Texture::get_output_port_type(int p_port) const { + return PORT_TYPE_VECTOR; +} + +String VisualShaderNodeCurve3Texture::get_output_port_name(int p_port) const { + return String(); +} + +void VisualShaderNodeCurve3Texture::set_texture(Ref<Curve3Texture> p_texture) { + texture = p_texture; + emit_changed(); +} + +Ref<Curve3Texture> VisualShaderNodeCurve3Texture::get_texture() const { + return texture; +} + +Vector<StringName> VisualShaderNodeCurve3Texture::get_editable_properties() const { + Vector<StringName> props; + props.push_back("texture"); + return props; +} + +String VisualShaderNodeCurve3Texture::generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const { + return "uniform sampler2D " + make_unique_id(p_type, p_id, "curve3d") + ";\n"; +} + +String VisualShaderNodeCurve3Texture::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview) const { + if (p_input_vars[0] == String()) { + return "\t" + p_output_vars[0] + " = vec3(0.0);\n"; + } + String id = make_unique_id(p_type, p_id, "curve3d"); + String code; + code += "\t" + p_output_vars[0] + " = texture(" + id + ", vec2(" + p_input_vars[0] + ")).rgb;\n"; + return code; +} + +Vector<VisualShader::DefaultTextureParam> VisualShaderNodeCurve3Texture::get_default_texture_parameters(VisualShader::Type p_type, int p_id) const { + VisualShader::DefaultTextureParam dtp; + dtp.name = make_unique_id(p_type, p_id, "curve3d"); + dtp.param = texture; + Vector<VisualShader::DefaultTextureParam> ret; + ret.push_back(dtp); + return ret; +} + +void VisualShaderNodeCurve3Texture::_bind_methods() { + ClassDB::bind_method(D_METHOD("set_texture", "texture"), &VisualShaderNodeCurve3Texture::set_texture); + ClassDB::bind_method(D_METHOD("get_texture"), &VisualShaderNodeCurve3Texture::get_texture); + + ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "texture", PROPERTY_HINT_RESOURCE_TYPE, "Curve3Texture"), "set_texture", "get_texture"); +} + +bool VisualShaderNodeCurve3Texture::is_use_prop_slots() const { + return true; +} + +VisualShaderNodeCurve3Texture::VisualShaderNodeCurve3Texture() { + simple_decl = true; + allow_v_resize = false; +} + ////////////// Sample3D int VisualShaderNodeSample3D::get_input_port_count() const { diff --git a/scene/resources/visual_shader_nodes.h b/scene/resources/visual_shader_nodes.h index 5b44e9f776..3ae79723e9 100644 --- a/scene/resources/visual_shader_nodes.h +++ b/scene/resources/visual_shader_nodes.h @@ -338,6 +338,39 @@ public: /////////////////////////////////////// +class VisualShaderNodeCurve3Texture : public VisualShaderNodeResizableBase { + GDCLASS(VisualShaderNodeCurve3Texture, VisualShaderNodeResizableBase); + Ref<Curve3Texture> texture; + +protected: + static void _bind_methods(); + +public: + virtual String get_caption() const override; + + virtual int get_input_port_count() const override; + virtual PortType get_input_port_type(int p_port) const override; + virtual String get_input_port_name(int p_port) const override; + + virtual int get_output_port_count() const override; + virtual PortType get_output_port_type(int p_port) const override; + virtual String get_output_port_name(int p_port) const override; + + virtual Vector<VisualShader::DefaultTextureParam> get_default_texture_parameters(VisualShader::Type p_type, int p_id) const override; + virtual String generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const override; + virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview = false) const override; + + void set_texture(Ref<Curve3Texture> p_value); + Ref<Curve3Texture> get_texture() const; + + virtual Vector<StringName> get_editable_properties() const override; + virtual bool is_use_prop_slots() const override; + + VisualShaderNodeCurve3Texture(); +}; + +/////////////////////////////////////// + class VisualShaderNodeSample3D : public VisualShaderNode { GDCLASS(VisualShaderNodeSample3D, VisualShaderNode); diff --git a/servers/register_server_types.cpp b/servers/register_server_types.cpp index 2118dca015..ef82ce5cae 100644 --- a/servers/register_server_types.cpp +++ b/servers/register_server_types.cpp @@ -207,6 +207,7 @@ void register_server_types() { ClassDB::register_class<RDShaderSource>(); ClassDB::register_class<RDShaderBytecode>(); ClassDB::register_class<RDShaderFile>(); + ClassDB::register_class<RDPipelineSpecializationConstant>(); ClassDB::register_class<CameraFeed>(); diff --git a/servers/rendering/rendering_device.cpp b/servers/rendering/rendering_device.cpp index 9f586b29fc..3594939362 100644 --- a/servers/rendering/rendering_device.cpp +++ b/servers/rendering/rendering_device.cpp @@ -221,7 +221,36 @@ Error RenderingDevice::_buffer_update(RID p_buffer, uint32_t p_offset, uint32_t return buffer_update(p_buffer, p_offset, p_size, p_data.ptr(), p_post_barrier); } -RID RenderingDevice::_render_pipeline_create(RID p_shader, FramebufferFormatID p_framebuffer_format, VertexFormatID p_vertex_format, RenderPrimitive p_render_primitive, const Ref<RDPipelineRasterizationState> &p_rasterization_state, const Ref<RDPipelineMultisampleState> &p_multisample_state, const Ref<RDPipelineDepthStencilState> &p_depth_stencil_state, const Ref<RDPipelineColorBlendState> &p_blend_state, int p_dynamic_state_flags, uint32_t p_for_render_pass) { +static Vector<RenderingDevice::PipelineSpecializationConstant> _get_spec_constants(const TypedArray<RDPipelineSpecializationConstant> &p_constants) { + Vector<RenderingDevice::PipelineSpecializationConstant> ret; + ret.resize(p_constants.size()); + for (int i = 0; i < p_constants.size(); i++) { + Ref<RDPipelineSpecializationConstant> c = p_constants[i]; + ERR_CONTINUE(c.is_null()); + RenderingDevice::PipelineSpecializationConstant &sc = ret.write[i]; + Variant value = c->get_value(); + switch (value.get_type()) { + case Variant::BOOL: { + sc.type = RD::PIPELINE_SPECIALIZATION_CONSTANT_TYPE_BOOL; + sc.bool_value = value; + } break; + case Variant::INT: { + sc.type = RD::PIPELINE_SPECIALIZATION_CONSTANT_TYPE_INT; + sc.int_value = value; + } break; + case Variant::FLOAT: { + sc.type = RD::PIPELINE_SPECIALIZATION_CONSTANT_TYPE_FLOAT; + sc.float_value = value; + } break; + default: { + } + } + + sc.constant_id = c->get_constant_id(); + } + return ret; +} +RID RenderingDevice::_render_pipeline_create(RID p_shader, FramebufferFormatID p_framebuffer_format, VertexFormatID p_vertex_format, RenderPrimitive p_render_primitive, const Ref<RDPipelineRasterizationState> &p_rasterization_state, const Ref<RDPipelineMultisampleState> &p_multisample_state, const Ref<RDPipelineDepthStencilState> &p_depth_stencil_state, const Ref<RDPipelineColorBlendState> &p_blend_state, int p_dynamic_state_flags, uint32_t p_for_render_pass, const TypedArray<RDPipelineSpecializationConstant> &p_specialization_constants) { PipelineRasterizationState rasterization_state; if (p_rasterization_state.is_valid()) { rasterization_state = p_rasterization_state->base; @@ -252,7 +281,11 @@ RID RenderingDevice::_render_pipeline_create(RID p_shader, FramebufferFormatID p } } - 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); + 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<RDPipelineSpecializationConstant> &p_specialization_constants = TypedArray<RDPipelineSpecializationConstant>()) { + return compute_pipeline_create(p_shader, _get_spec_constants(p_specialization_constants)); } Vector<int64_t> 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<Color> &p_clear_color_values, float p_clear_depth, uint32_t p_clear_stencil, const Rect2 &p_region, const TypedArray<RID> &p_storage_textures) { @@ -348,10 +381,10 @@ void RenderingDevice::_bind_methods() { ClassDB::bind_method(D_METHOD("buffer_clear", "buffer", "offset", "size_bytes", "post_barrier"), &RenderingDevice::buffer_clear, DEFVAL(BARRIER_MASK_ALL)); ClassDB::bind_method(D_METHOD("buffer_get_data", "buffer"), &RenderingDevice::buffer_get_data); - ClassDB::bind_method(D_METHOD("render_pipeline_create", "shader", "framebuffer_format", "vertex_format", "primitive", "rasterization_state", "multisample_state", "stencil_state", "color_blend_state", "dynamic_state_flags", "for_render_pass"), &RenderingDevice::_render_pipeline_create, DEFVAL(0), DEFVAL(0)); + ClassDB::bind_method(D_METHOD("render_pipeline_create", "shader", "framebuffer_format", "vertex_format", "primitive", "rasterization_state", "multisample_state", "stencil_state", "color_blend_state", "dynamic_state_flags", "for_render_pass", "specialization_constants"), &RenderingDevice::_render_pipeline_create, DEFVAL(0), DEFVAL(0), DEFVAL(TypedArray<RDPipelineSpecializationConstant>())); ClassDB::bind_method(D_METHOD("render_pipeline_is_valid", "render_pipeline"), &RenderingDevice::render_pipeline_is_valid); - ClassDB::bind_method(D_METHOD("compute_pipeline_create", "shader"), &RenderingDevice::compute_pipeline_create); + ClassDB::bind_method(D_METHOD("compute_pipeline_create", "shader", "specialization_constants"), &RenderingDevice::_compute_pipeline_create, DEFVAL(TypedArray<RDPipelineSpecializationConstant>())); ClassDB::bind_method(D_METHOD("compute_pipeline_is_valid", "compute_pieline"), &RenderingDevice::compute_pipeline_is_valid); ClassDB::bind_method(D_METHOD("screen_get_width", "screen"), &RenderingDevice::screen_get_width, DEFVAL(DisplayServer::MAIN_WINDOW_ID)); @@ -853,6 +886,10 @@ void RenderingDevice::_bind_methods() { BIND_ENUM_CONSTANT(SHADER_LANGUAGE_GLSL); BIND_ENUM_CONSTANT(SHADER_LANGUAGE_HLSL); + BIND_ENUM_CONSTANT(PIPELINE_SPECIALIZATION_CONSTANT_TYPE_BOOL); + BIND_ENUM_CONSTANT(PIPELINE_SPECIALIZATION_CONSTANT_TYPE_INT); + BIND_ENUM_CONSTANT(PIPELINE_SPECIALIZATION_CONSTANT_TYPE_FLOAT); + BIND_ENUM_CONSTANT(LIMIT_MAX_BOUND_UNIFORM_SETS); BIND_ENUM_CONSTANT(LIMIT_MAX_FRAMEBUFFER_COLOR_ATTACHMENTS); BIND_ENUM_CONSTANT(LIMIT_MAX_TEXTURES_PER_UNIFORM_SET); diff --git a/servers/rendering/rendering_device.h b/servers/rendering/rendering_device.h index 0ca84bd79e..9a154ef7e9 100644 --- a/servers/rendering/rendering_device.h +++ b/servers/rendering/rendering_device.h @@ -48,6 +48,7 @@ class RDPipelineMultisampleState; class RDPipelineDepthStencilState; class RDPipelineColorBlendState; class RDFramebufferPass; +class RDPipelineSpecializationConstant; class RenderingDevice : public Object { GDCLASS(RenderingDevice, Object) @@ -722,6 +723,32 @@ public: virtual Error buffer_clear(RID p_buffer, uint32_t p_offset, uint32_t p_size, uint32_t p_post_barrier = BARRIER_MASK_ALL) = 0; virtual Vector<uint8_t> buffer_get_data(RID p_buffer) = 0; //this causes stall, only use to retrieve large buffers for saving + /******************************************/ + /**** PIPELINE SPECIALIZATION CONSTANT ****/ + /******************************************/ + + enum PipelineSpecializationConstantType { + PIPELINE_SPECIALIZATION_CONSTANT_TYPE_BOOL, + PIPELINE_SPECIALIZATION_CONSTANT_TYPE_INT, + PIPELINE_SPECIALIZATION_CONSTANT_TYPE_FLOAT, + }; + + struct PipelineSpecializationConstant { + PipelineSpecializationConstantType type; + uint32_t constant_id; + union { + uint32_t int_value; + float float_value; + bool bool_value; + }; + + PipelineSpecializationConstant() { + type = PIPELINE_SPECIALIZATION_CONSTANT_TYPE_BOOL; + constant_id = 0; + int_value = 0; + } + }; + /*************************/ /**** RENDER PIPELINE ****/ /*************************/ @@ -978,13 +1005,13 @@ public: }; virtual bool render_pipeline_is_valid(RID p_pipeline) = 0; - virtual RID render_pipeline_create(RID p_shader, FramebufferFormatID p_framebuffer_format, VertexFormatID p_vertex_format, RenderPrimitive p_render_primitive, const PipelineRasterizationState &p_rasterization_state, const PipelineMultisampleState &p_multisample_state, const PipelineDepthStencilState &p_depth_stencil_state, const PipelineColorBlendState &p_blend_state, int p_dynamic_state_flags = 0, uint32_t p_for_render_pass = 0) = 0; + virtual RID render_pipeline_create(RID p_shader, FramebufferFormatID p_framebuffer_format, VertexFormatID p_vertex_format, RenderPrimitive p_render_primitive, const PipelineRasterizationState &p_rasterization_state, const PipelineMultisampleState &p_multisample_state, const PipelineDepthStencilState &p_depth_stencil_state, const PipelineColorBlendState &p_blend_state, int p_dynamic_state_flags = 0, uint32_t p_for_render_pass = 0, const Vector<PipelineSpecializationConstant> &p_specialization_constants = Vector<PipelineSpecializationConstant>()) = 0; /**************************/ /**** COMPUTE PIPELINE ****/ /**************************/ - virtual RID compute_pipeline_create(RID p_shader) = 0; + virtual RID compute_pipeline_create(RID p_shader, const Vector<PipelineSpecializationConstant> &p_specialization_constants = Vector<PipelineSpecializationConstant>()) = 0; virtual bool compute_pipeline_is_valid(RID p_pipeline) = 0; /****************/ @@ -1173,7 +1200,8 @@ protected: Error _buffer_update(RID p_buffer, uint32_t p_offset, uint32_t p_size, const Vector<uint8_t> &p_data, uint32_t p_post_barrier = BARRIER_MASK_ALL); - RID _render_pipeline_create(RID p_shader, FramebufferFormatID p_framebuffer_format, VertexFormatID p_vertex_format, RenderPrimitive p_render_primitive, const Ref<RDPipelineRasterizationState> &p_rasterization_state, const Ref<RDPipelineMultisampleState> &p_multisample_state, const Ref<RDPipelineDepthStencilState> &p_depth_stencil_state, const Ref<RDPipelineColorBlendState> &p_blend_state, int p_dynamic_state_flags = 0, uint32_t p_for_render_pass = 0); + RID _render_pipeline_create(RID p_shader, FramebufferFormatID p_framebuffer_format, VertexFormatID p_vertex_format, RenderPrimitive p_render_primitive, const Ref<RDPipelineRasterizationState> &p_rasterization_state, const Ref<RDPipelineMultisampleState> &p_multisample_state, const Ref<RDPipelineDepthStencilState> &p_depth_stencil_state, const Ref<RDPipelineColorBlendState> &p_blend_state, int p_dynamic_state_flags, uint32_t p_for_render_pass, const TypedArray<RDPipelineSpecializationConstant> &p_specialization_constants); + RID _compute_pipeline_create(RID p_shader, const TypedArray<RDPipelineSpecializationConstant> &p_specialization_constants); Vector<int64_t> _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<Color> &p_clear_color_values = Vector<Color>(), float p_clear_depth = 1.0, uint32_t p_clear_stencil = 0, const Rect2 &p_region = Rect2(), const TypedArray<RID> &p_storage_textures = TypedArray<RID>()); void _draw_list_set_push_constant(DrawListID p_list, const Vector<uint8_t> &p_data, uint32_t p_data_size); @@ -1205,6 +1233,7 @@ VARIANT_ENUM_CAST(RenderingDevice::LogicOperation) VARIANT_ENUM_CAST(RenderingDevice::BlendFactor) VARIANT_ENUM_CAST(RenderingDevice::BlendOperation) VARIANT_ENUM_CAST(RenderingDevice::PipelineDynamicStateFlags) +VARIANT_ENUM_CAST(RenderingDevice::PipelineSpecializationConstantType) VARIANT_ENUM_CAST(RenderingDevice::InitialAction) VARIANT_ENUM_CAST(RenderingDevice::FinalAction) VARIANT_ENUM_CAST(RenderingDevice::Limit) diff --git a/servers/rendering/rendering_device_binds.h b/servers/rendering/rendering_device_binds.h index dc59568ce9..1af427b356 100644 --- a/servers/rendering/rendering_device_binds.h +++ b/servers/rendering/rendering_device_binds.h @@ -452,6 +452,41 @@ protected: ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "_ids", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_INTERNAL), "_set_ids", "get_ids"); } }; + +class RDPipelineSpecializationConstant : public RefCounted { + GDCLASS(RDPipelineSpecializationConstant, RefCounted) + friend class RenderingDevice; + + Variant value = false; + uint32_t constant_id; + +public: + void set_value(const Variant &p_value) { + ERR_FAIL_COND(p_value.get_type() != Variant::BOOL && p_value.get_type() != Variant::INT && p_value.get_type() != Variant::FLOAT); + value = p_value; + } + Variant get_value() const { return value; } + + void set_constant_id(uint32_t p_id) { + constant_id = p_id; + } + uint32_t get_constant_id() const { + return constant_id; + } + +protected: + static void _bind_methods() { + ClassDB::bind_method(D_METHOD("set_value", "value"), &RDPipelineSpecializationConstant::set_value); + ClassDB::bind_method(D_METHOD("get_value"), &RDPipelineSpecializationConstant::get_value); + + ClassDB::bind_method(D_METHOD("set_constant_id", "constant_id"), &RDPipelineSpecializationConstant::set_constant_id); + ClassDB::bind_method(D_METHOD("get_constant_id"), &RDPipelineSpecializationConstant::get_constant_id); + + ADD_PROPERTY(PropertyInfo(Variant::NIL, "value", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NIL_IS_VARIANT), "set_value", "get_value"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "constant_id", PROPERTY_HINT_RANGE, "0,65535,0"), "set_constant_id", "get_constant_id"); + } +}; + class RDPipelineRasterizationState : public RefCounted { GDCLASS(RDPipelineRasterizationState, RefCounted) friend class RenderingDevice; diff --git a/thirdparty/README.md b/thirdparty/README.md index 03a2ddf5e4..31e88180d0 100644 --- a/thirdparty/README.md +++ b/thirdparty/README.md @@ -616,6 +616,11 @@ Files extracted from upstream source: - `include` folder - `LICENSE` +Some downstream changes have been made and are identified by +`// -- GODOT begin --` and `// -- GODOT end --` comments. +They can be reapplied using the patch included in the `patches` +folder. + ## squish diff --git a/thirdparty/spirv-reflect/patches/specialization-constants.patch b/thirdparty/spirv-reflect/patches/specialization-constants.patch new file mode 100644 index 0000000000..8ff1dcc2e5 --- /dev/null +++ b/thirdparty/spirv-reflect/patches/specialization-constants.patch @@ -0,0 +1,293 @@ +diff --git a/thirdparty/spirv-reflect/spirv_reflect.c b/thirdparty/spirv-reflect/spirv_reflect.c +index 0fc979a8a4..3e3643717a 100644 +--- a/thirdparty/spirv-reflect/spirv_reflect.c ++++ b/thirdparty/spirv-reflect/spirv_reflect.c +@@ -124,6 +124,9 @@ typedef struct Decorations { + NumberDecoration location; + NumberDecoration offset; + NumberDecoration uav_counter_buffer; ++// -- GODOT begin -- ++ NumberDecoration specialization_constant; ++// -- GODOT end -- + StringDecoration semantic; + uint32_t array_stride; + uint32_t matrix_stride; +@@ -610,6 +613,9 @@ static SpvReflectResult ParseNodes(Parser* p_parser) + p_parser->nodes[i].decorations.offset.value = (uint32_t)INVALID_VALUE; + p_parser->nodes[i].decorations.uav_counter_buffer.value = (uint32_t)INVALID_VALUE; + p_parser->nodes[i].decorations.built_in = (SpvBuiltIn)INVALID_VALUE; ++// -- GODOT begin -- ++ p_parser->nodes[i].decorations.specialization_constant.value = (SpvBuiltIn)INVALID_VALUE; ++// -- GODOT end -- + } + // Mark source file id node + p_parser->source_file_id = (uint32_t)INVALID_VALUE; +@@ -800,10 +806,16 @@ static SpvReflectResult ParseNodes(Parser* p_parser) + CHECKED_READU32(p_parser, p_node->word_offset + 2, p_node->result_id); + } + break; +- ++// -- GODOT begin -- + case SpvOpSpecConstantTrue: + case SpvOpSpecConstantFalse: +- case SpvOpSpecConstant: ++ case SpvOpSpecConstant: { ++ CHECKED_READU32(p_parser, p_node->word_offset + 1, p_node->result_type_id); ++ CHECKED_READU32(p_parser, p_node->word_offset + 2, p_node->result_id); ++ p_node->is_type = true; ++ } ++ break; ++// -- GODOT end -- + case SpvOpSpecConstantComposite: + case SpvOpSpecConstantOp: { + CHECKED_READU32(p_parser, p_node->word_offset + 1, p_node->result_type_id); +@@ -1309,6 +1321,9 @@ static SpvReflectResult ParseDecorations(Parser* p_parser) + skip = true; + } + break; ++// -- GODOT begin -- ++ case SpvDecorationSpecId: ++// -- GODOT end -- + case SpvDecorationBlock: + case SpvDecorationBufferBlock: + case SpvDecorationColMajor: +@@ -1441,7 +1456,14 @@ static SpvReflectResult ParseDecorations(Parser* p_parser) + p_target_decorations->input_attachment_index.word_offset = word_offset; + } + break; +- ++// -- GODOT begin -- ++ case SpvDecorationSpecId: { ++ uint32_t word_offset = p_node->word_offset + member_offset+ 3; ++ CHECKED_READU32(p_parser, word_offset, p_target_decorations->specialization_constant.value); ++ p_target_decorations->specialization_constant.word_offset = word_offset; ++ } ++ break; ++// -- GODOT end -- + case SpvReflectDecorationHlslCounterBufferGOOGLE: { + uint32_t word_offset = p_node->word_offset + member_offset+ 3; + CHECKED_READU32(p_parser, word_offset, p_target_decorations->uav_counter_buffer.value); +@@ -1731,6 +1753,13 @@ static SpvReflectResult ParseType( + p_type->type_flags |= SPV_REFLECT_TYPE_FLAG_EXTERNAL_ACCELERATION_STRUCTURE; + } + break; ++// -- GODOT begin -- ++ case SpvOpSpecConstantTrue: ++ case SpvOpSpecConstantFalse: ++ case SpvOpSpecConstant: { ++ } ++ break; ++// -- GODOT end -- + } + + if (result == SPV_REFLECT_RESULT_SUCCESS) { +@@ -3187,6 +3216,69 @@ static SpvReflectResult ParseExecutionModes(Parser* p_parser, SpvReflectShaderMo + return SPV_REFLECT_RESULT_SUCCESS; + } + ++// -- GODOT begin -- ++static SpvReflectResult ParseSpecializationConstants(Parser* p_parser, SpvReflectShaderModule* p_module) ++{ ++ p_module->specialization_constant_count = 0; ++ p_module->specialization_constants = NULL; ++ for (size_t i = 0; i < p_parser->node_count; ++i) { ++ Node* p_node = &(p_parser->nodes[i]); ++ if (p_node->op == SpvOpSpecConstantTrue || p_node->op == SpvOpSpecConstantFalse || p_node->op == SpvOpSpecConstant) { ++ p_module->specialization_constant_count++; ++ } ++ } ++ ++ if (p_module->specialization_constant_count == 0) { ++ return SPV_REFLECT_RESULT_SUCCESS; ++ } ++ ++ p_module->specialization_constants = (SpvReflectSpecializationConstant*)calloc(p_module->specialization_constant_count, sizeof(SpvReflectSpecializationConstant)); ++ ++ uint32_t index = 0; ++ ++ for (size_t i = 0; i < p_parser->node_count; ++i) { ++ Node* p_node = &(p_parser->nodes[i]); ++ switch(p_node->op) { ++ default: continue; ++ case SpvOpSpecConstantTrue: { ++ p_module->specialization_constants[index].constant_type = SPV_REFLECT_SPECIALIZATION_CONSTANT_BOOL; ++ p_module->specialization_constants[index].default_value.int_bool_value = 1; ++ } break; ++ case SpvOpSpecConstantFalse: { ++ p_module->specialization_constants[index].constant_type = SPV_REFLECT_SPECIALIZATION_CONSTANT_BOOL; ++ p_module->specialization_constants[index].default_value.int_bool_value = 0; ++ } break; ++ case SpvOpSpecConstant: { ++ SpvReflectResult result = SPV_REFLECT_RESULT_SUCCESS; ++ uint32_t element_type_id = (uint32_t)INVALID_VALUE; ++ uint32_t default_value = 0; ++ IF_READU32(result, p_parser, p_node->word_offset + 1, element_type_id); ++ IF_READU32(result, p_parser, p_node->word_offset + 3, default_value); ++ ++ Node* p_next_node = FindNode(p_parser, element_type_id); ++ ++ if (p_next_node->op == SpvOpTypeInt) { ++ p_module->specialization_constants[index].constant_type = SPV_REFLECT_SPECIALIZATION_CONSTANT_INT; ++ } else if (p_next_node->op == SpvOpTypeFloat) { ++ p_module->specialization_constants[index].constant_type = SPV_REFLECT_SPECIALIZATION_CONSTANT_FLOAT; ++ } else { ++ return SPV_REFLECT_RESULT_ERROR_PARSE_FAILED; ++ } ++ ++ p_module->specialization_constants[index].default_value.int_bool_value = default_value; //bits are the same for int and float ++ } break; ++ } ++ ++ p_module->specialization_constants[index].name = p_node->name; ++ p_module->specialization_constants[index].constant_id = p_node->decorations.specialization_constant.value; ++ p_module->specialization_constants[index].spirv_id = p_node->result_id; ++ index++; ++ } ++ ++ return SPV_REFLECT_RESULT_SUCCESS; ++} ++// -- GODOT end -- ++ + static SpvReflectResult ParsePushConstantBlocks(Parser* p_parser, SpvReflectShaderModule* p_module) + { + for (size_t i = 0; i < p_parser->node_count; ++i) { +@@ -3562,6 +3654,12 @@ SpvReflectResult spvReflectCreateShaderModule( + result = ParsePushConstantBlocks(&parser, p_module); + SPV_REFLECT_ASSERT(result == SPV_REFLECT_RESULT_SUCCESS); + } ++// -- GODOT begin -- ++ if (result == SPV_REFLECT_RESULT_SUCCESS) { ++ result = ParseSpecializationConstants(&parser, p_module); ++ SPV_REFLECT_ASSERT(result == SPV_REFLECT_RESULT_SUCCESS); ++ } ++// -- GODOT end -- + if (result == SPV_REFLECT_RESULT_SUCCESS) { + result = ParseEntryPoints(&parser, p_module); + SPV_REFLECT_ASSERT(result == SPV_REFLECT_RESULT_SUCCESS); +@@ -3691,6 +3789,9 @@ void spvReflectDestroyShaderModule(SpvReflectShaderModule* p_module) + SafeFree(p_entry->used_push_constants); + } + SafeFree(p_module->entry_points); ++// -- GODOT begin -- ++ SafeFree(p_module->specialization_constants); ++// -- GODOT end -- + + // Push constants + for (size_t i = 0; i < p_module->push_constant_block_count; ++i) { +@@ -3959,6 +4060,38 @@ SpvReflectResult spvReflectEnumerateEntryPointInterfaceVariables( + return SPV_REFLECT_RESULT_SUCCESS; + } + ++// -- GODOT begin -- ++SpvReflectResult spvReflectEnumerateSpecializationConstants( ++ const SpvReflectShaderModule* p_module, ++ uint32_t* p_count, ++ SpvReflectSpecializationConstant** pp_constants ++) ++{ ++ if (IsNull(p_module)) { ++ return SPV_REFLECT_RESULT_ERROR_NULL_POINTER; ++ } ++ if (IsNull(p_count)) { ++ return SPV_REFLECT_RESULT_ERROR_NULL_POINTER; ++ } ++ ++ if (IsNotNull(pp_constants)) { ++ if (*p_count != p_module->specialization_constant_count) { ++ return SPV_REFLECT_RESULT_ERROR_COUNT_MISMATCH; ++ } ++ ++ for (uint32_t index = 0; index < *p_count; ++index) { ++ SpvReflectSpecializationConstant *p_const = &p_module->specialization_constants[index]; ++ pp_constants[index] = p_const; ++ } ++ } ++ else { ++ *p_count = p_module->specialization_constant_count; ++ } ++ ++ return SPV_REFLECT_RESULT_SUCCESS; ++} ++// -- GODOT end -- ++ + SpvReflectResult spvReflectEnumerateInputVariables( + const SpvReflectShaderModule* p_module, + uint32_t* p_count, +diff --git a/thirdparty/spirv-reflect/spirv_reflect.h b/thirdparty/spirv-reflect/spirv_reflect.h +index a5a956e9e8..21f8160770 100644 +--- a/thirdparty/spirv-reflect/spirv_reflect.h ++++ b/thirdparty/spirv-reflect/spirv_reflect.h +@@ -292,6 +292,28 @@ typedef struct SpvReflectTypeDescription { + struct SpvReflectTypeDescription* members; + } SpvReflectTypeDescription; + ++// -- GODOT begin -- ++/*! @struct SpvReflectSpecializationConstant ++ ++*/ ++ ++typedef enum SpvReflectSpecializationConstantType { ++ SPV_REFLECT_SPECIALIZATION_CONSTANT_BOOL = 0, ++ SPV_REFLECT_SPECIALIZATION_CONSTANT_INT = 1, ++ SPV_REFLECT_SPECIALIZATION_CONSTANT_FLOAT = 2, ++} SpvReflectSpecializationConstantType; ++ ++typedef struct SpvReflectSpecializationConstant { ++ const char* name; ++ uint32_t spirv_id; ++ uint32_t constant_id; ++ SpvReflectSpecializationConstantType constant_type; ++ union { ++ float float_value; ++ uint32_t int_bool_value; ++ } default_value; ++} SpvReflectSpecializationConstant; ++// -- GODOT end -- + + /*! @struct SpvReflectInterfaceVariable + +@@ -439,6 +461,10 @@ typedef struct SpvReflectShaderModule { + SpvReflectInterfaceVariable* interface_variables; + uint32_t push_constant_block_count; + SpvReflectBlockVariable* push_constant_blocks; ++ // -- GODOT begin -- ++ uint32_t specialization_constant_count; ++ SpvReflectSpecializationConstant* specialization_constants; ++ // -- GODOT end -- + + struct Internal { + size_t spirv_size; +@@ -694,6 +720,33 @@ SpvReflectResult spvReflectEnumerateInputVariables( + SpvReflectInterfaceVariable** pp_variables + ); + ++// -- GOODT begin -- ++/*! @fn spvReflectEnumerateSpecializationConstants ++ @brief If the module contains multiple entry points, this will only get ++ the specialization constants for the first one. ++ @param p_module Pointer to an instance of SpvReflectShaderModule. ++ @param p_count If pp_constants is NULL, the module's specialization constant ++ count will be stored here. ++ If pp_variables is not NULL, *p_count must contain ++ the module's specialization constant count. ++ @param pp_variables If NULL, the module's specialization constant count will be ++ written to *p_count. ++ If non-NULL, pp_constants must point to an array with ++ *p_count entries, where pointers to the module's ++ specialization constants will be written. The caller must not ++ free the specialization constants written to this array. ++ @return If successful, returns SPV_REFLECT_RESULT_SUCCESS. ++ Otherwise, the error code indicates the cause of the ++ failure. ++ ++*/ ++SpvReflectResult spvReflectEnumerateSpecializationConstants( ++ const SpvReflectShaderModule* p_module, ++ uint32_t* p_count, ++ SpvReflectSpecializationConstant** pp_constants ++); ++// -- GODOT end -- ++ + /*! @fn spvReflectEnumerateEntryPointInputVariables + @brief Enumerate the input variables for a given entry point. + @param entry_point The name of the entry point to get the input variables for. diff --git a/thirdparty/spirv-reflect/spirv_reflect.c b/thirdparty/spirv-reflect/spirv_reflect.c index 0fc979a8a4..8f614c8874 100644 --- a/thirdparty/spirv-reflect/spirv_reflect.c +++ b/thirdparty/spirv-reflect/spirv_reflect.c @@ -124,6 +124,9 @@ typedef struct Decorations { NumberDecoration location; NumberDecoration offset; NumberDecoration uav_counter_buffer; +// -- GODOT begin -- + NumberDecoration specialization_constant; +// -- GODOT end -- StringDecoration semantic; uint32_t array_stride; uint32_t matrix_stride; @@ -610,6 +613,9 @@ static SpvReflectResult ParseNodes(Parser* p_parser) p_parser->nodes[i].decorations.offset.value = (uint32_t)INVALID_VALUE; p_parser->nodes[i].decorations.uav_counter_buffer.value = (uint32_t)INVALID_VALUE; p_parser->nodes[i].decorations.built_in = (SpvBuiltIn)INVALID_VALUE; +// -- GODOT begin -- + p_parser->nodes[i].decorations.specialization_constant.value = (SpvBuiltIn)INVALID_VALUE; +// -- GODOT end -- } // Mark source file id node p_parser->source_file_id = (uint32_t)INVALID_VALUE; @@ -800,10 +806,16 @@ static SpvReflectResult ParseNodes(Parser* p_parser) CHECKED_READU32(p_parser, p_node->word_offset + 2, p_node->result_id); } break; - +// -- GODOT begin -- case SpvOpSpecConstantTrue: case SpvOpSpecConstantFalse: - case SpvOpSpecConstant: + case SpvOpSpecConstant: { + CHECKED_READU32(p_parser, p_node->word_offset + 1, p_node->result_type_id); + CHECKED_READU32(p_parser, p_node->word_offset + 2, p_node->result_id); + p_node->is_type = true; + } + break; +// -- GODOT end -- case SpvOpSpecConstantComposite: case SpvOpSpecConstantOp: { CHECKED_READU32(p_parser, p_node->word_offset + 1, p_node->result_type_id); @@ -1309,6 +1321,9 @@ static SpvReflectResult ParseDecorations(Parser* p_parser) skip = true; } break; +// -- GODOT begin -- + case SpvDecorationSpecId: +// -- GODOT end -- case SpvDecorationBlock: case SpvDecorationBufferBlock: case SpvDecorationColMajor: @@ -1441,7 +1456,14 @@ static SpvReflectResult ParseDecorations(Parser* p_parser) p_target_decorations->input_attachment_index.word_offset = word_offset; } break; - +// -- GODOT begin -- + case SpvDecorationSpecId: { + uint32_t word_offset = p_node->word_offset + member_offset+ 3; + CHECKED_READU32(p_parser, word_offset, p_target_decorations->specialization_constant.value); + p_target_decorations->specialization_constant.word_offset = word_offset; + } + break; +// -- GODOT end -- case SpvReflectDecorationHlslCounterBufferGOOGLE: { uint32_t word_offset = p_node->word_offset + member_offset+ 3; CHECKED_READU32(p_parser, word_offset, p_target_decorations->uav_counter_buffer.value); @@ -1731,6 +1753,13 @@ static SpvReflectResult ParseType( p_type->type_flags |= SPV_REFLECT_TYPE_FLAG_EXTERNAL_ACCELERATION_STRUCTURE; } break; +// -- GODOT begin -- + case SpvOpSpecConstantTrue: + case SpvOpSpecConstantFalse: + case SpvOpSpecConstant: { + } + break; +// -- GODOT end -- } if (result == SPV_REFLECT_RESULT_SUCCESS) { @@ -3187,6 +3216,69 @@ static SpvReflectResult ParseExecutionModes(Parser* p_parser, SpvReflectShaderMo return SPV_REFLECT_RESULT_SUCCESS; } +// -- GODOT begin -- +static SpvReflectResult ParseSpecializationConstants(Parser* p_parser, SpvReflectShaderModule* p_module) +{ + p_module->specialization_constant_count = 0; + p_module->specialization_constants = NULL; + for (size_t i = 0; i < p_parser->node_count; ++i) { + Node* p_node = &(p_parser->nodes[i]); + if (p_node->op == SpvOpSpecConstantTrue || p_node->op == SpvOpSpecConstantFalse || p_node->op == SpvOpSpecConstant) { + p_module->specialization_constant_count++; + } + } + + if (p_module->specialization_constant_count == 0) { + return SPV_REFLECT_RESULT_SUCCESS; + } + + p_module->specialization_constants = (SpvReflectSpecializationConstant*)calloc(p_module->specialization_constant_count, sizeof(SpvReflectSpecializationConstant)); + + uint32_t index = 0; + + for (size_t i = 0; i < p_parser->node_count; ++i) { + Node* p_node = &(p_parser->nodes[i]); + switch(p_node->op) { + default: continue; + case SpvOpSpecConstantTrue: { + p_module->specialization_constants[index].constant_type = SPV_REFLECT_SPECIALIZATION_CONSTANT_BOOL; + p_module->specialization_constants[index].default_value.int_bool_value = 1; + } break; + case SpvOpSpecConstantFalse: { + p_module->specialization_constants[index].constant_type = SPV_REFLECT_SPECIALIZATION_CONSTANT_BOOL; + p_module->specialization_constants[index].default_value.int_bool_value = 0; + } break; + case SpvOpSpecConstant: { + SpvReflectResult result = SPV_REFLECT_RESULT_SUCCESS; + uint32_t element_type_id = (uint32_t)INVALID_VALUE; + uint32_t default_value = 0; + IF_READU32(result, p_parser, p_node->word_offset + 1, element_type_id); + IF_READU32(result, p_parser, p_node->word_offset + 3, default_value); + + Node* p_next_node = FindNode(p_parser, element_type_id); + + if (p_next_node->op == SpvOpTypeInt) { + p_module->specialization_constants[index].constant_type = SPV_REFLECT_SPECIALIZATION_CONSTANT_INT; + } else if (p_next_node->op == SpvOpTypeFloat) { + p_module->specialization_constants[index].constant_type = SPV_REFLECT_SPECIALIZATION_CONSTANT_FLOAT; + } else { + return SPV_REFLECT_RESULT_ERROR_PARSE_FAILED; + } + + p_module->specialization_constants[index].default_value.int_bool_value = default_value; //bits are the same for int and float + } break; + } + + p_module->specialization_constants[index].name = p_node->name; + p_module->specialization_constants[index].constant_id = p_node->decorations.specialization_constant.value; + p_module->specialization_constants[index].spirv_id = p_node->result_id; + index++; + } + + return SPV_REFLECT_RESULT_SUCCESS; +} +// -- GODOT end -- + static SpvReflectResult ParsePushConstantBlocks(Parser* p_parser, SpvReflectShaderModule* p_module) { for (size_t i = 0; i < p_parser->node_count; ++i) { @@ -3562,6 +3654,12 @@ SpvReflectResult spvReflectCreateShaderModule( result = ParsePushConstantBlocks(&parser, p_module); SPV_REFLECT_ASSERT(result == SPV_REFLECT_RESULT_SUCCESS); } +// -- GODOT begin -- + if (result == SPV_REFLECT_RESULT_SUCCESS) { + result = ParseSpecializationConstants(&parser, p_module); + SPV_REFLECT_ASSERT(result == SPV_REFLECT_RESULT_SUCCESS); + } +// -- GODOT end -- if (result == SPV_REFLECT_RESULT_SUCCESS) { result = ParseEntryPoints(&parser, p_module); SPV_REFLECT_ASSERT(result == SPV_REFLECT_RESULT_SUCCESS); @@ -3691,6 +3789,9 @@ void spvReflectDestroyShaderModule(SpvReflectShaderModule* p_module) SafeFree(p_entry->used_push_constants); } SafeFree(p_module->entry_points); +// -- GODOT begin -- + SafeFree(p_module->specialization_constants); +// -- GODOT end -- // Push constants for (size_t i = 0; i < p_module->push_constant_block_count; ++i) { @@ -3959,6 +4060,38 @@ SpvReflectResult spvReflectEnumerateEntryPointInterfaceVariables( return SPV_REFLECT_RESULT_SUCCESS; } +// -- GODOT begin -- +SpvReflectResult spvReflectEnumerateSpecializationConstants( + const SpvReflectShaderModule* p_module, + uint32_t* p_count, + SpvReflectSpecializationConstant** pp_constants +) +{ + if (IsNull(p_module)) { + return SPV_REFLECT_RESULT_ERROR_NULL_POINTER; + } + if (IsNull(p_count)) { + return SPV_REFLECT_RESULT_ERROR_NULL_POINTER; + } + + if (IsNotNull(pp_constants)) { + if (*p_count != p_module->specialization_constant_count) { + return SPV_REFLECT_RESULT_ERROR_COUNT_MISMATCH; + } + + for (uint32_t index = 0; index < *p_count; ++index) { + SpvReflectSpecializationConstant *p_const = &p_module->specialization_constants[index]; + pp_constants[index] = p_const; + } + } + else { + *p_count = p_module->specialization_constant_count; + } + + return SPV_REFLECT_RESULT_SUCCESS; +} +// -- GODOT end -- + SpvReflectResult spvReflectEnumerateInputVariables( const SpvReflectShaderModule* p_module, uint32_t* p_count, diff --git a/thirdparty/spirv-reflect/spirv_reflect.h b/thirdparty/spirv-reflect/spirv_reflect.h index a5a956e9e8..21f8160770 100644 --- a/thirdparty/spirv-reflect/spirv_reflect.h +++ b/thirdparty/spirv-reflect/spirv_reflect.h @@ -292,6 +292,28 @@ typedef struct SpvReflectTypeDescription { struct SpvReflectTypeDescription* members; } SpvReflectTypeDescription; +// -- GODOT begin -- +/*! @struct SpvReflectSpecializationConstant + +*/ + +typedef enum SpvReflectSpecializationConstantType { + SPV_REFLECT_SPECIALIZATION_CONSTANT_BOOL = 0, + SPV_REFLECT_SPECIALIZATION_CONSTANT_INT = 1, + SPV_REFLECT_SPECIALIZATION_CONSTANT_FLOAT = 2, +} SpvReflectSpecializationConstantType; + +typedef struct SpvReflectSpecializationConstant { + const char* name; + uint32_t spirv_id; + uint32_t constant_id; + SpvReflectSpecializationConstantType constant_type; + union { + float float_value; + uint32_t int_bool_value; + } default_value; +} SpvReflectSpecializationConstant; +// -- GODOT end -- /*! @struct SpvReflectInterfaceVariable @@ -439,6 +461,10 @@ typedef struct SpvReflectShaderModule { SpvReflectInterfaceVariable* interface_variables; uint32_t push_constant_block_count; SpvReflectBlockVariable* push_constant_blocks; + // -- GODOT begin -- + uint32_t specialization_constant_count; + SpvReflectSpecializationConstant* specialization_constants; + // -- GODOT end -- struct Internal { size_t spirv_size; @@ -694,6 +720,33 @@ SpvReflectResult spvReflectEnumerateInputVariables( SpvReflectInterfaceVariable** pp_variables ); +// -- GOODT begin -- +/*! @fn spvReflectEnumerateSpecializationConstants + @brief If the module contains multiple entry points, this will only get + the specialization constants for the first one. + @param p_module Pointer to an instance of SpvReflectShaderModule. + @param p_count If pp_constants is NULL, the module's specialization constant + count will be stored here. + If pp_variables is not NULL, *p_count must contain + the module's specialization constant count. + @param pp_variables If NULL, the module's specialization constant count will be + written to *p_count. + If non-NULL, pp_constants must point to an array with + *p_count entries, where pointers to the module's + specialization constants will be written. The caller must not + free the specialization constants written to this array. + @return If successful, returns SPV_REFLECT_RESULT_SUCCESS. + Otherwise, the error code indicates the cause of the + failure. + +*/ +SpvReflectResult spvReflectEnumerateSpecializationConstants( + const SpvReflectShaderModule* p_module, + uint32_t* p_count, + SpvReflectSpecializationConstant** pp_constants +); +// -- GODOT end -- + /*! @fn spvReflectEnumerateEntryPointInputVariables @brief Enumerate the input variables for a given entry point. @param entry_point The name of the entry point to get the input variables for. |