diff --git a/drivers/d3d12/rendering_device_driver_d3d12.cpp b/drivers/d3d12/rendering_device_driver_d3d12.cpp index 66317a3b88f..8fa0823c60c 100644 --- a/drivers/d3d12/rendering_device_driver_d3d12.cpp +++ b/drivers/d3d12/rendering_device_driver_d3d12.cpp @@ -6129,6 +6129,8 @@ bool RenderingDeviceDriverD3D12::has_feature(Features p_feature) { return true; case SUPPORTS_VULKAN_MEMORY_MODEL: return false; + case SUPPORTS_POINT_SIZE: + return false; default: return false; } diff --git a/drivers/metal/rendering_device_driver_metal.mm b/drivers/metal/rendering_device_driver_metal.mm index 4b729420dfa..a4933c370c1 100644 --- a/drivers/metal/rendering_device_driver_metal.mm +++ b/drivers/metal/rendering_device_driver_metal.mm @@ -2564,6 +2564,8 @@ bool RenderingDeviceDriverMetal::has_feature(Features p_feature) { return device_properties->features.supports_native_image_atomics; case SUPPORTS_VULKAN_MEMORY_MODEL: return true; + case SUPPORTS_POINT_SIZE: + return true; default: return false; } diff --git a/drivers/vulkan/rendering_device_driver_vulkan.cpp b/drivers/vulkan/rendering_device_driver_vulkan.cpp index a324c759319..86b61cb4402 100644 --- a/drivers/vulkan/rendering_device_driver_vulkan.cpp +++ b/drivers/vulkan/rendering_device_driver_vulkan.cpp @@ -6282,6 +6282,8 @@ bool RenderingDeviceDriverVulkan::has_feature(Features p_feature) { return vulkan_memory_model_support && vulkan_memory_model_device_scope_support; case SUPPORTS_FRAMEBUFFER_DEPTH_RESOLVE: return framebuffer_depth_resolve; + case SUPPORTS_POINT_SIZE: + return true; default: return false; } diff --git a/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp b/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp index 10f96eeb060..f0520dab038 100644 --- a/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp +++ b/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp @@ -485,6 +485,8 @@ void RenderForwardClustered::_render_list_template(RenderingDevice::DrawListID p pipeline_key.wireframe = p_params->force_wireframe; pipeline_key.ubershader = 0; + bool emulate_point_size = shader->uses_point_size && scene_shader.emulate_point_size; + const RD::PolygonCullMode cull_mode = shader->get_cull_mode_from_cull_variant(cull_variant); RID vertex_array_rd; RID index_array_rd; @@ -497,9 +499,9 @@ void RenderForwardClustered::_render_list_template(RenderingDevice::DrawListID p bool pipeline_motion_vectors = pipeline_key.color_pass_flags & SceneShaderForwardClustered::PIPELINE_COLOR_PASS_FLAG_MOTION_VECTORS; uint64_t input_mask = shader->get_vertex_input_mask(pipeline_key.version, pipeline_key.color_pass_flags, pipeline_key.ubershader); if (surf->owner->mesh_instance.is_valid()) { - mesh_storage->mesh_instance_surface_get_vertex_arrays_and_format(surf->owner->mesh_instance, surf->surface_index, input_mask, pipeline_motion_vectors, vertex_array_rd, vertex_format); + mesh_storage->mesh_instance_surface_get_vertex_arrays_and_format(surf->owner->mesh_instance, surf->surface_index, input_mask, pipeline_motion_vectors, emulate_point_size, vertex_array_rd, vertex_format); } else { - mesh_storage->mesh_surface_get_vertex_arrays_and_format(mesh_surface, input_mask, pipeline_motion_vectors, vertex_array_rd, vertex_format); + mesh_storage->mesh_surface_get_vertex_arrays_and_format(mesh_surface, input_mask, pipeline_motion_vectors, emulate_point_size, vertex_array_rd, vertex_format); } pipeline_key.vertex_format_id = vertex_format; @@ -534,7 +536,11 @@ void RenderForwardClustered::_render_list_template(RenderingDevice::DrawListID p } if (pipeline_valid) { - index_array_rd = mesh_storage->mesh_surface_get_index_array(mesh_surface, element_info.lod_index); + if (!emulate_point_size) { + index_array_rd = mesh_storage->mesh_surface_get_index_array(mesh_surface, element_info.lod_index); + } else { + index_array_rd = RID(); + } if (prev_vertex_array_rd != vertex_array_rd) { RD::get_singleton()->draw_list_bind_vertex_array(draw_list, vertex_array_rd); @@ -592,7 +598,14 @@ void RenderForwardClustered::_render_list_template(RenderingDevice::DrawListID p instance_count /= surf->owner->trail_steps; } - if (bool(surf->owner->base_flags & INSTANCE_DATA_FLAG_MULTIMESH_INDIRECT)) { + bool indirect = bool(surf->owner->base_flags & INSTANCE_DATA_FLAG_MULTIMESH_INDIRECT); + + if (emulate_point_size) { + if (indirect) { + WARN_PRINT("Indirect draws are not supported when emulating point size."); + } + RD::get_singleton()->draw_list_draw(draw_list, false, mesh_storage->mesh_surface_get_vertex_count(mesh_surface), instance_count * 6); + } else if (indirect) { RD::get_singleton()->draw_list_draw_indirect(draw_list, index_array_rd.is_valid(), mesh_storage->_multimesh_get_command_buffer_rd_rid(surf->owner->data->base), surf->surface_index * sizeof(uint32_t) * mesh_storage->INDIRECT_MULTIMESH_COMMAND_STRIDE, 1, 0); } else { RD::get_singleton()->draw_list_draw(draw_list, index_array_rd.is_valid(), instance_count); @@ -4517,7 +4530,8 @@ void RenderForwardClustered::_mesh_compile_pipeline_for_surface(SceneShaderForwa RendererRD::MeshStorage *mesh_storage = RendererRD::MeshStorage::get_singleton(); uint64_t input_mask = p_shader->get_vertex_input_mask(r_pipeline_key.version, r_pipeline_key.color_pass_flags, p_ubershader); bool pipeline_motion_vectors = r_pipeline_key.color_pass_flags & SceneShaderForwardClustered::PIPELINE_COLOR_PASS_FLAG_MOTION_VECTORS; - r_pipeline_key.vertex_format_id = mesh_storage->mesh_surface_get_vertex_format(p_mesh_surface, input_mask, p_instanced_surface, pipeline_motion_vectors); + bool emulate_point_size = p_shader->uses_point_size && scene_shader.emulate_point_size; + r_pipeline_key.vertex_format_id = mesh_storage->mesh_surface_get_vertex_format(p_mesh_surface, input_mask, p_instanced_surface, pipeline_motion_vectors, emulate_point_size); r_pipeline_key.ubershader = p_ubershader; p_shader->pipeline_hash_map.compile_pipeline(r_pipeline_key, r_pipeline_key.hash(), p_source, p_ubershader); 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 c79c6998272..82a686bd1fd 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 @@ -411,7 +411,14 @@ void SceneShaderForwardClustered::ShaderData::_create_pipeline(PipelineKey p_pip RD::RENDER_PRIMITIVE_TRIANGLE_STRIPS, }; - RD::RenderPrimitive primitive_rd = uses_point_size ? RD::RENDER_PRIMITIVE_POINTS : primitive_rd_table[p_pipeline_key.primitive_type]; + bool emulate_point_size_flag = uses_point_size && SceneShaderForwardClustered::singleton->emulate_point_size; + + RD::RenderPrimitive primitive_rd; + if (uses_point_size) { + primitive_rd = emulate_point_size_flag ? RD::RENDER_PRIMITIVE_TRIANGLES : RD::RENDER_PRIMITIVE_POINTS; + } else { + primitive_rd = primitive_rd_table[p_pipeline_key.primitive_type]; + } RD::PipelineRasterizationState raster_state; raster_state.cull_mode = p_pipeline_key.cull_mode; @@ -479,6 +486,13 @@ void SceneShaderForwardClustered::ShaderData::_create_pipeline(PipelineKey p_pip sc.constant_id = 1; sc.int_value = p_pipeline_key.shader_specialization.packed_1; + sc.type = RD::PIPELINE_SPECIALIZATION_CONSTANT_TYPE_INT; + specialization_constants.push_back(sc); + + sc = {}; // Sanitize value bits. "bool_value" only assigns 8 bits and keeps the remaining bits intact. + sc.constant_id = 2; + sc.bool_value = emulate_point_size_flag; + sc.type = RD::PIPELINE_SPECIALIZATION_CONSTANT_TYPE_BOOL; specialization_constants.push_back(sc); RID shader_rid = get_shader_variant(p_pipeline_key.version, p_pipeline_key.color_pass_flags, p_pipeline_key.ubershader); @@ -621,6 +635,8 @@ SceneShaderForwardClustered::~SceneShaderForwardClustered() { void SceneShaderForwardClustered::init(const String p_defines) { RendererRD::MaterialStorage *material_storage = RendererRD::MaterialStorage::get_singleton(); + emulate_point_size = !RD::get_singleton()->has_feature(RD::SUPPORTS_POINT_SIZE); + { Vector shader_versions; for (uint32_t ubershader = 0; ubershader < 2; ubershader++) { @@ -701,9 +717,9 @@ void SceneShaderForwardClustered::init(const String p_defines) { actions.renames["UV"] = "uv_interp"; actions.renames["UV2"] = "uv2_interp"; actions.renames["COLOR"] = "color_interp"; - actions.renames["POINT_SIZE"] = "gl_PointSize"; - actions.renames["INSTANCE_ID"] = "gl_InstanceIndex"; - actions.renames["VERTEX_ID"] = "gl_VertexIndex"; + actions.renames["POINT_SIZE"] = "point_size"; + actions.renames["INSTANCE_ID"] = "INSTANCE_INDEX"; + actions.renames["VERTEX_ID"] = "VERTEX_INDEX"; actions.renames["Z_CLIP_SCALE"] = "z_clip_scale"; actions.renames["ALPHA_SCISSOR_THRESHOLD"] = "alpha_scissor_threshold"; @@ -748,7 +764,7 @@ void SceneShaderForwardClustered::init(const String p_defines) { actions.renames["AO"] = "ao"; actions.renames["AO_LIGHT_AFFECT"] = "ao_light_affect"; actions.renames["EMISSION"] = "emission"; - actions.renames["POINT_COORD"] = "gl_PointCoord"; + actions.renames["POINT_COORD"] = "point_coord"; actions.renames["INSTANCE_CUSTOM"] = "instance_custom"; actions.renames["SCREEN_UV"] = "screen_uv"; actions.renames["DEPTH"] = "gl_FragDepth"; @@ -829,6 +845,9 @@ void SceneShaderForwardClustered::init(const String p_defines) { actions.usage_defines["MODEL_MATRIX"] = "#define MODEL_MATRIX_USED\n"; + actions.usage_defines["POINT_SIZE"] = "#define POINT_SIZE_USED\n"; + actions.usage_defines["POINT_COORD"] = "#define POINT_COORD_USED\n"; + actions.render_mode_defines["skip_vertex_transform"] = "#define SKIP_TRANSFORM_USED\n"; actions.render_mode_defines["world_vertex_coords"] = "#define VERTEX_WORLD_COORDS_USED\n"; actions.render_mode_defines["ensure_correct_normals"] = "#define ENSURE_CORRECT_NORMALS\n"; @@ -871,7 +890,7 @@ void SceneShaderForwardClustered::init(const String p_defines) { actions.base_texture_binding_index = 1; actions.texture_layout_set = RenderForwardClustered::MATERIAL_UNIFORM_SET; actions.base_uniform_string = "material."; - actions.base_varying_index = 14; + actions.base_varying_index = 15; actions.default_filter = ShaderLanguage::FILTER_LINEAR_MIPMAP; actions.default_repeat = ShaderLanguage::REPEAT_ENABLE; diff --git a/servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.h b/servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.h index f1752af9bc7..c0df98e2f0c 100644 --- a/servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.h +++ b/servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.h @@ -342,6 +342,7 @@ public: SceneForwardClusteredShaderRD shader; ShaderCompiler compiler; + bool emulate_point_size = false; RID default_shader; RID default_material; diff --git a/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp b/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp index 9d5f383561f..dc7e9a8bd34 100644 --- a/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp +++ b/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp @@ -2429,6 +2429,8 @@ void RenderForwardMobile::_render_list_template(RenderingDevice::DrawListID p_dr pipeline_key.render_pass = p_params->subpass; pipeline_key.ubershader = 0; + bool emulate_point_size = shader->uses_point_size && scene_shader.emulate_point_size; + const RD::PolygonCullMode cull_mode = shader->get_cull_mode_from_cull_variant(cull_variant); RD::VertexFormatID vertex_format = -1; RID pipeline_rd; @@ -2440,9 +2442,9 @@ void RenderForwardMobile::_render_list_template(RenderingDevice::DrawListID p_dr // Skeleton and blend shape. uint64_t input_mask = shader->get_vertex_input_mask(pipeline_key.version, pipeline_key.ubershader); if (surf->owner->mesh_instance.is_valid()) { - mesh_storage->mesh_instance_surface_get_vertex_arrays_and_format(surf->owner->mesh_instance, surf->surface_index, input_mask, p_pass_mode == PASS_MODE_MOTION_VECTORS, vertex_array_rd, vertex_format); + mesh_storage->mesh_instance_surface_get_vertex_arrays_and_format(surf->owner->mesh_instance, surf->surface_index, input_mask, p_pass_mode == PASS_MODE_MOTION_VECTORS, emulate_point_size, vertex_array_rd, vertex_format); } else { - mesh_storage->mesh_surface_get_vertex_arrays_and_format(mesh_surface, input_mask, p_pass_mode == PASS_MODE_MOTION_VECTORS, vertex_array_rd, vertex_format); + mesh_storage->mesh_surface_get_vertex_arrays_and_format(mesh_surface, input_mask, p_pass_mode == PASS_MODE_MOTION_VECTORS, emulate_point_size, vertex_array_rd, vertex_format); } pipeline_key.vertex_format_id = vertex_format; @@ -2477,7 +2479,11 @@ void RenderForwardMobile::_render_list_template(RenderingDevice::DrawListID p_dr } if (pipeline_valid) { - index_array_rd = mesh_storage->mesh_surface_get_index_array(mesh_surface, element_info.lod_index); + if (!emulate_point_size) { + index_array_rd = mesh_storage->mesh_surface_get_index_array(mesh_surface, element_info.lod_index); + } else { + index_array_rd = RID(); + } if (prev_vertex_array_rd != vertex_array_rd) { RD::get_singleton()->draw_list_bind_vertex_array(draw_list, vertex_array_rd); @@ -2535,7 +2541,14 @@ void RenderForwardMobile::_render_list_template(RenderingDevice::DrawListID p_dr instance_count /= surf->owner->trail_steps; } - if (bool(surf->owner->base_flags & INSTANCE_DATA_FLAG_MULTIMESH_INDIRECT)) { + bool indirect = bool(surf->owner->base_flags & INSTANCE_DATA_FLAG_MULTIMESH_INDIRECT); + + if (emulate_point_size) { + if (indirect) { + WARN_PRINT("Indirect draws are not supported when emulating point size."); + } + RD::get_singleton()->draw_list_draw(draw_list, false, mesh_storage->mesh_surface_get_vertex_count(mesh_surface), instance_count * 6); + } else if (indirect) { RD::get_singleton()->draw_list_draw_indirect(draw_list, index_array_rd.is_valid(), mesh_storage->_multimesh_get_command_buffer_rd_rid(surf->owner->data->base), surf->surface_index * sizeof(uint32_t) * mesh_storage->INDIRECT_MULTIMESH_COMMAND_STRIDE, 1, 0); } else { RD::get_singleton()->draw_list_draw(draw_list, index_array_rd.is_valid(), instance_count); @@ -3167,7 +3180,8 @@ static RD::FramebufferFormatID _get_shadow_atlas_framebuffer_format_for_pipeline void RenderForwardMobile::_mesh_compile_pipeline_for_surface(SceneShaderForwardMobile::ShaderData *p_shader, void *p_mesh_surface, bool p_instanced_surface, RS::PipelineSource p_source, SceneShaderForwardMobile::ShaderData::PipelineKey &r_pipeline_key, Vector *r_pipeline_pairs) { RendererRD::MeshStorage *mesh_storage = RendererRD::MeshStorage::get_singleton(); uint64_t input_mask = p_shader->get_vertex_input_mask(r_pipeline_key.version, true); - r_pipeline_key.vertex_format_id = mesh_storage->mesh_surface_get_vertex_format(p_mesh_surface, input_mask, p_instanced_surface, false); + bool emulate_point_size = p_shader->uses_point_size && scene_shader.emulate_point_size; + r_pipeline_key.vertex_format_id = mesh_storage->mesh_surface_get_vertex_format(p_mesh_surface, input_mask, p_instanced_surface, false, emulate_point_size); r_pipeline_key.ubershader = true; p_shader->pipeline_hash_map.compile_pipeline(r_pipeline_key, r_pipeline_key.hash(), p_source, r_pipeline_key.ubershader); 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 bb1faa19988..ddbcc4b0ed3 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 @@ -366,7 +366,14 @@ void SceneShaderForwardMobile::ShaderData::_create_pipeline(PipelineKey p_pipeli depth_stencil_state.back_op = op; } - RD::RenderPrimitive primitive_rd = uses_point_size ? RD::RENDER_PRIMITIVE_POINTS : primitive_rd_table[p_pipeline_key.primitive_type]; + bool emulate_point_size_flag = uses_point_size && SceneShaderForwardMobile::singleton->emulate_point_size; + + RD::RenderPrimitive primitive_rd; + if (uses_point_size) { + primitive_rd = emulate_point_size_flag ? RD::RENDER_PRIMITIVE_TRIANGLES : RD::RENDER_PRIMITIVE_POINTS; + } else { + primitive_rd = primitive_rd_table[p_pipeline_key.primitive_type]; + } RD::PipelineRasterizationState raster_state; raster_state.cull_mode = p_pipeline_key.cull_mode; @@ -430,6 +437,12 @@ void SceneShaderForwardMobile::ShaderData::_create_pipeline(PipelineKey p_pipeli sc.type = RD::PIPELINE_SPECIALIZATION_CONSTANT_TYPE_FLOAT; specialization_constants.push_back(sc); + sc = {}; // Sanitize value bits. "bool_value" only assigns 8 bits and keeps the remaining bits intact. + sc.constant_id = 3; + sc.bool_value = emulate_point_size_flag; + sc.type = RD::PIPELINE_SPECIALIZATION_CONSTANT_TYPE_BOOL; + specialization_constants.push_back(sc); + RID shader_rid = get_shader_variant(p_pipeline_key.version, p_pipeline_key.ubershader); ERR_FAIL_COND(shader_rid.is_null()); @@ -559,6 +572,8 @@ void SceneShaderForwardMobile::init(const String p_defines) { // Store whether the shader will prefer using the FP16 variant. use_fp16 = RD::get_singleton()->has_feature(RD::SUPPORTS_HALF_FLOAT); + emulate_point_size = !RD::get_singleton()->has_feature(RD::SUPPORTS_POINT_SIZE); + // Immutable samplers : create the shadow sampler to be passed when creating the pipeline. { RD::SamplerState sampler; @@ -636,9 +651,9 @@ void SceneShaderForwardMobile::init(const String p_defines) { actions.renames["UV"] = "uv_interp"; actions.renames["UV2"] = "uv2_interp"; actions.renames["COLOR"] = "color_highp"; - actions.renames["POINT_SIZE"] = "gl_PointSize"; - actions.renames["INSTANCE_ID"] = "gl_InstanceIndex"; - actions.renames["VERTEX_ID"] = "gl_VertexIndex"; + actions.renames["POINT_SIZE"] = "point_size"; + actions.renames["INSTANCE_ID"] = "INSTANCE_INDEX"; + actions.renames["VERTEX_ID"] = "VERTEX_INDEX"; actions.renames["Z_CLIP_SCALE"] = "z_clip_scale"; actions.renames["ALPHA_SCISSOR_THRESHOLD"] = "alpha_scissor_threshold_highp"; @@ -683,7 +698,7 @@ void SceneShaderForwardMobile::init(const String p_defines) { actions.renames["AO"] = "ao_highp"; actions.renames["AO_LIGHT_AFFECT"] = "ao_light_affect_highp"; actions.renames["EMISSION"] = "emission_highp"; - actions.renames["POINT_COORD"] = "gl_PointCoord"; + actions.renames["POINT_COORD"] = "point_coord"; actions.renames["INSTANCE_CUSTOM"] = "instance_custom"; actions.renames["SCREEN_UV"] = "screen_uv"; actions.renames["DEPTH"] = "gl_FragDepth"; @@ -764,6 +779,9 @@ void SceneShaderForwardMobile::init(const String p_defines) { actions.usage_defines["MODEL_MATRIX"] = "#define MODEL_MATRIX_USED\n"; + actions.usage_defines["POINT_SIZE"] = "#define POINT_SIZE_USED\n"; + actions.usage_defines["POINT_COORD"] = "#define POINT_COORD_USED\n"; + actions.render_mode_defines["skip_vertex_transform"] = "#define SKIP_TRANSFORM_USED\n"; actions.render_mode_defines["world_vertex_coords"] = "#define VERTEX_WORLD_COORDS_USED\n"; actions.render_mode_defines["ensure_correct_normals"] = "#define ENSURE_CORRECT_NORMALS\n"; @@ -805,7 +823,7 @@ void SceneShaderForwardMobile::init(const String p_defines) { actions.base_texture_binding_index = 1; actions.texture_layout_set = RenderForwardMobile::MATERIAL_UNIFORM_SET; actions.base_uniform_string = "material."; - actions.base_varying_index = 14; + actions.base_varying_index = 15; actions.default_filter = ShaderLanguage::FILTER_LINEAR_MIPMAP; actions.default_repeat = ShaderLanguage::REPEAT_ENABLE; diff --git a/servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.h b/servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.h index 6fc033d4337..f1d216ec327 100644 --- a/servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.h +++ b/servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.h @@ -345,6 +345,7 @@ public: SceneForwardMobileShaderRD shader; ShaderCompiler compiler; bool use_fp16 = false; + bool emulate_point_size = false; RID default_shader; RID default_material; diff --git a/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp b/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp index eeb4df1c13d..88cb53cf43f 100644 --- a/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp +++ b/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp @@ -478,9 +478,9 @@ RID RendererCanvasRenderRD::_get_pipeline_specialization_or_ubershader(CanvasSha RendererRD::MeshStorage *mesh_storage = RendererRD::MeshStorage::get_singleton(); uint64_t input_mask = p_shader_data->get_vertex_input_mask(r_pipeline_key.variant, r_pipeline_key.ubershader); if (p_mesh_instance.is_valid()) { - mesh_storage->mesh_instance_surface_get_vertex_arrays_and_format(p_mesh_instance, p_surface_index, input_mask, false, *r_vertex_array, r_pipeline_key.vertex_format_id); + mesh_storage->mesh_instance_surface_get_vertex_arrays_and_format(p_mesh_instance, p_surface_index, input_mask, false, false, *r_vertex_array, r_pipeline_key.vertex_format_id); } else { - mesh_storage->mesh_surface_get_vertex_arrays_and_format(p_surface, input_mask, false, *r_vertex_array, r_pipeline_key.vertex_format_id); + mesh_storage->mesh_surface_get_vertex_arrays_and_format(p_surface, input_mask, false, false, *r_vertex_array, r_pipeline_key.vertex_format_id); } } diff --git a/servers/rendering/renderer_rd/shaders/forward_clustered/scene_forward_clustered.glsl b/servers/rendering/renderer_rd/shaders/forward_clustered/scene_forward_clustered.glsl index 8d9cbc3fd9e..19e90a926d1 100644 --- a/servers/rendering/renderer_rd/shaders/forward_clustered/scene_forward_clustered.glsl +++ b/servers/rendering/renderer_rd/shaders/forward_clustered/scene_forward_clustered.glsl @@ -178,6 +178,11 @@ uint cluster_get_range_clip_mask(uint i, uint z_min, uint z_max) { return bitfieldInsert(uint(0), uint(0xFFFFFFFF), local_min, mask_width); } #endif // !defined(MODE_RENDER_DEPTH) && !defined(MODE_UNSHADED) && defined(USE_VERTEX_LIGHTING) + +#if defined(POINT_SIZE_USED) && defined(POINT_COORD_USED) +layout(location = 14) out vec2 point_coord_interp; +#endif + invariant gl_Position; #GLOBALS @@ -265,7 +270,7 @@ void vertex_shader(vec3 vertex_input, uint trail_size = (instances.data[instance_index].flags >> INSTANCE_FLAGS_PARTICLE_TRAIL_SHIFT) & INSTANCE_FLAGS_PARTICLE_TRAIL_MASK; uint stride = 3 + 1 + 1; //particles always uses this format - uint offset = trail_size * stride * gl_InstanceIndex; + uint offset = trail_size * stride * INSTANCE_INDEX; #ifdef COLOR_USED vec4 pcolor; @@ -307,7 +312,7 @@ void vertex_shader(vec3 vertex_input, #else uint stride = multimesh_stride(); - uint offset = stride * (gl_InstanceIndex + multimesh_offset); + uint offset = stride * (INSTANCE_INDEX + multimesh_offset); if (sc_multimesh_format_2d()) { matrix = mat4(transforms.data[offset + 0], transforms.data[offset + 1], vec4(0.0, 0.0, 1.0, 0.0), vec4(0.0, 0.0, 0.0, 1.0)); @@ -438,6 +443,10 @@ void vertex_shader(vec3 vertex_input, mat3 modelview_normal = mat3(read_view_matrix) * model_normal_matrix; vec2 read_viewport_size = scene_data.viewport_size; +#ifdef POINT_SIZE_USED + float point_size = 1.0; +#endif + { #CODE : VERTEX } @@ -695,6 +704,27 @@ void vertex_shader(vec3 vertex_input, gl_Position.z = mix(gl_Position.w, gl_Position.z, z_clip_scale); } #endif + +#ifdef POINT_SIZE_USED + if (sc_emulate_point_size) { + vec2 point_coords[6] = vec2[]( + vec2(0, 1), + vec2(0, 0), + vec2(1, 1), + vec2(0, 0), + vec2(1, 0), + vec2(1, 1)); + + vec2 point_coord = point_coords[gl_VertexIndex % 6]; + gl_Position.xy += (point_coord * 2.0 - 1.0) * point_size * scene_data.screen_pixel_size * gl_Position.w; + +#ifdef POINT_COORD_USED + point_coord_interp = point_coord; +#endif + } else { + gl_PointSize = point_size; + } +#endif } void _unpack_vertex_attributes(vec4 p_vertex_in, vec3 p_compressed_aabb_position, vec3 p_compressed_aabb_size, @@ -740,7 +770,7 @@ void _unpack_vertex_attributes(vec4 p_vertex_in, vec3 p_compressed_aabb_position void main() { uint instance_index = draw_call.instance_index; if (!sc_multimesh()) { - instance_index += gl_InstanceIndex; + instance_index += INSTANCE_INDEX; } instance_index_interp = instance_index; @@ -967,6 +997,11 @@ ivec2 multiview_uv(ivec2 uv) { layout(location = 12) in vec4 diffuse_light_interp; layout(location = 13) in vec4 specular_light_interp; #endif + +#if defined(POINT_SIZE_USED) && defined(POINT_COORD_USED) +layout(location = 14) in vec2 point_coord_interp; +#endif + //defines to keep compatibility with vertex #ifdef USE_MULTIVIEW @@ -1291,6 +1326,19 @@ void fragment_shader(in SceneData scene_data) { vec4(0.0, 0.0, 0.0, 1.0))); vec2 read_viewport_size = scene_data.viewport_size; +#ifdef POINT_COORD_USED +#ifdef POINT_SIZE_USED + vec2 point_coord; + if (sc_emulate_point_size) { + point_coord = point_coord_interp; + } else { + point_coord = gl_PointCoord; + } +#else // !POINT_SIZE_USED + vec2 point_coord = vec2(0.5); +#endif +#endif + { #CODE : FRAGMENT } diff --git a/servers/rendering/renderer_rd/shaders/forward_clustered/scene_forward_clustered_inc.glsl b/servers/rendering/renderer_rd/shaders/forward_clustered/scene_forward_clustered_inc.glsl index dac841ba0b8..d1eddfac71e 100644 --- a/servers/rendering/renderer_rd/shaders/forward_clustered/scene_forward_clustered_inc.glsl +++ b/servers/rendering/renderer_rd/shaders/forward_clustered/scene_forward_clustered_inc.glsl @@ -142,6 +142,20 @@ float sc_luminance_multiplier() { return 1.0; } +layout(constant_id = 2) const bool sc_emulate_point_size = false; + +#ifdef POINT_SIZE_USED + +#define VERTEX_INDEX (sc_emulate_point_size ? gl_InstanceIndex : gl_VertexIndex) +#define INSTANCE_INDEX (sc_emulate_point_size ? (gl_VertexIndex / 6) : gl_InstanceIndex) + +#else + +#define VERTEX_INDEX gl_VertexIndex +#define INSTANCE_INDEX gl_InstanceIndex + +#endif + #define REFLECTION_MULTIPLIER 1.0 #define SDFGI_MAX_CASCADES 8 diff --git a/servers/rendering/renderer_rd/shaders/forward_mobile/scene_forward_mobile.glsl b/servers/rendering/renderer_rd/shaders/forward_mobile/scene_forward_mobile.glsl index b9f1018ccdb..43277ba3041 100644 --- a/servers/rendering/renderer_rd/shaders/forward_mobile/scene_forward_mobile.glsl +++ b/servers/rendering/renderer_rd/shaders/forward_mobile/scene_forward_mobile.glsl @@ -163,6 +163,10 @@ ivec2 multiview_uv(ivec2 uv) { } #endif // !USE_MULTIVIEW +#if defined(POINT_SIZE_USED) && defined(POINT_COORD_USED) +layout(location = 14) out vec2 point_coord_interp; +#endif + invariant gl_Position; #GLOBALS @@ -305,7 +309,7 @@ void vertex_shader(in vec3 vertex, uint trail_size = (instances.data[instance_index].flags >> INSTANCE_FLAGS_PARTICLE_TRAIL_SHIFT) & INSTANCE_FLAGS_PARTICLE_TRAIL_MASK; uint stride = 3 + 1 + 1; //particles always uses this format - uint offset = trail_size * stride * gl_InstanceIndex; + uint offset = trail_size * stride * INSTANCE_INDEX; #ifdef COLOR_USED vec4 pcolor; @@ -347,7 +351,7 @@ void vertex_shader(in vec3 vertex, #else uint stride = multimesh_stride(); - uint offset = stride * (gl_InstanceIndex + multimesh_offset); + uint offset = stride * (INSTANCE_INDEX + multimesh_offset); if (sc_multimesh_format_2d()) { matrix = mat4(transforms.data[offset + 0], transforms.data[offset + 1], vec4(0.0, 0.0, 1.0, 0.0), vec4(0.0, 0.0, 0.0, 1.0)); @@ -464,6 +468,10 @@ void vertex_shader(in vec3 vertex, mat3 modelview_normal = mat3(read_view_matrix) * model_normal_matrix; vec2 read_viewport_size = scene_data.viewport_size; +#ifdef POINT_SIZE_USED + float point_size = 1.0; +#endif + { #CODE : VERTEX } @@ -665,6 +673,27 @@ void vertex_shader(in vec3 vertex, #ifdef MODE_RENDER_MOTION_VECTORS screen_position_output = gl_Position; #endif // MODE_RENDER_MOTION_VECTORS + +#ifdef POINT_SIZE_USED + if (sc_emulate_point_size) { + vec2 point_coords[6] = vec2[]( + vec2(0, 1), + vec2(0, 0), + vec2(1, 1), + vec2(0, 0), + vec2(1, 0), + vec2(1, 1)); + + vec2 point_coord = point_coords[gl_VertexIndex % 6]; + gl_Position.xy += (point_coord * 2.0 - 1.0) * point_size * scene_data.screen_pixel_size * gl_Position.w; + +#ifdef POINT_COORD_USED + point_coord_interp = point_coord; +#endif + } else { + gl_PointSize = point_size; + } +#endif } void main() { @@ -934,6 +963,10 @@ ivec2 multiview_uv(ivec2 uv) { } #endif // !USE_MULTIVIEW +#if defined(POINT_SIZE_USED) && defined(POINT_COORD_USED) +layout(location = 14) in vec2 point_coord_interp; +#endif + //defines to keep compatibility with vertex #ifdef USE_MULTIVIEW @@ -1211,6 +1244,19 @@ void main() { vec4(0.0, 0.0, 0.0, 1.0))); vec2 read_viewport_size = scene_data.viewport_size; +#ifdef POINT_COORD_USED +#ifdef POINT_SIZE_USED + vec2 point_coord; + if (sc_emulate_point_size) { + point_coord = point_coord_interp; + } else { + point_coord = gl_PointCoord; + } +#else // !POINT_SIZE_USED + vec2 point_coord = vec2(0.5); +#endif +#endif + { #CODE : FRAGMENT } diff --git a/servers/rendering/renderer_rd/shaders/forward_mobile/scene_forward_mobile_inc.glsl b/servers/rendering/renderer_rd/shaders/forward_mobile/scene_forward_mobile_inc.glsl index a96921e68c9..a2eeb339291 100644 --- a/servers/rendering/renderer_rd/shaders/forward_mobile/scene_forward_mobile_inc.glsl +++ b/servers/rendering/renderer_rd/shaders/forward_mobile/scene_forward_mobile_inc.glsl @@ -215,6 +215,20 @@ half sc_luminance_multiplier() { return half(sc_packed_2()); } +layout(constant_id = 3) const bool sc_emulate_point_size = false; + +#ifdef POINT_SIZE_USED + +#define VERTEX_INDEX (sc_emulate_point_size ? gl_InstanceIndex : gl_VertexIndex) +#define INSTANCE_INDEX (sc_emulate_point_size ? (gl_VertexIndex / 6) : gl_InstanceIndex) + +#else + +#define VERTEX_INDEX gl_VertexIndex +#define INSTANCE_INDEX gl_InstanceIndex + +#endif + // Like the luminance multiplier, but it is only for sky and reflection probes // since they are always LDR. #define REFLECTION_MULTIPLIER half(2.0) diff --git a/servers/rendering/renderer_rd/storage_rd/mesh_storage.cpp b/servers/rendering/renderer_rd/storage_rd/mesh_storage.cpp index 5c479d8bed5..189262f4e22 100644 --- a/servers/rendering/renderer_rd/storage_rd/mesh_storage.cpp +++ b/servers/rendering/renderer_rd/storage_rd/mesh_storage.cpp @@ -1259,7 +1259,7 @@ void MeshStorage::update_mesh_instances() { RD::get_singleton()->compute_list_end(); } -RD::VertexFormatID MeshStorage::_mesh_surface_generate_vertex_format(uint64_t p_surface_format, uint64_t p_input_mask, bool p_instanced_surface, bool p_input_motion_vectors, uint32_t &r_position_stride) { +RD::VertexFormatID MeshStorage::_mesh_surface_generate_vertex_format(uint64_t p_surface_format, uint64_t p_input_mask, bool p_instanced_surface, bool p_input_motion_vectors, bool p_point_size_emulated, uint32_t &r_position_stride) { Vector attributes; uint32_t normal_tangent_stride = 0; uint32_t attribute_stride = 0; @@ -1396,6 +1396,10 @@ RD::VertexFormatID MeshStorage::_mesh_surface_generate_vertex_format(uint64_t p_ skin_stride += sizeof(int16_t) * 4; } break; } + + if (p_point_size_emulated) { + vd.frequency = RD::VERTEX_FREQUENCY_INSTANCE; + } } if (!(p_input_mask & (1ULL << i))) { @@ -1447,9 +1451,9 @@ RD::VertexFormatID MeshStorage::_mesh_surface_generate_vertex_format(uint64_t p_ return RD::get_singleton()->vertex_format_create(attributes); } -void MeshStorage::_mesh_surface_generate_version_for_input_mask(Mesh::Surface::Version &v, Mesh::Surface *s, uint64_t p_input_mask, bool p_input_motion_vectors, MeshInstance::Surface *mis, uint32_t p_current_buffer, uint32_t p_previous_buffer) { +void MeshStorage::_mesh_surface_generate_version_for_input_mask(Mesh::Surface::Version &v, Mesh::Surface *s, uint64_t p_input_mask, bool p_input_motion_vectors, bool p_point_size_emulated, MeshInstance::Surface *mis, uint32_t p_current_buffer, uint32_t p_previous_buffer) { uint32_t position_stride = 0; - v.vertex_format = _mesh_surface_generate_vertex_format(s->format, p_input_mask, mis != nullptr, p_input_motion_vectors, position_stride); + v.vertex_format = _mesh_surface_generate_vertex_format(s->format, p_input_mask, mis != nullptr, p_input_motion_vectors, p_point_size_emulated, position_stride); Vector buffers; Vector offsets; @@ -1513,7 +1517,8 @@ void MeshStorage::_mesh_surface_generate_version_for_input_mask(Mesh::Surface::V v.current_buffer = p_current_buffer; v.previous_buffer = p_previous_buffer; v.input_motion_vectors = p_input_motion_vectors; - v.vertex_array = RD::get_singleton()->vertex_array_create(s->vertex_count, v.vertex_format, buffers, offsets); + v.point_size_emulated = p_point_size_emulated; + v.vertex_array = RD::get_singleton()->vertex_array_create(p_point_size_emulated ? 0 : s->vertex_count, v.vertex_format, buffers, offsets); } ////////////////// MULTIMESH diff --git a/servers/rendering/renderer_rd/storage_rd/mesh_storage.h b/servers/rendering/renderer_rd/storage_rd/mesh_storage.h index 5640918b5f0..776c8603d66 100644 --- a/servers/rendering/renderer_rd/storage_rd/mesh_storage.h +++ b/servers/rendering/renderer_rd/storage_rd/mesh_storage.h @@ -100,6 +100,7 @@ private: uint32_t current_buffer = 0; uint32_t previous_buffer = 0; bool input_motion_vectors = false; + bool point_size_emulated = false; RD::VertexFormatID vertex_format = 0; RID vertex_array; }; @@ -208,8 +209,8 @@ private: weight_update_list(this), array_update_list(this) {} }; - RD::VertexFormatID _mesh_surface_generate_vertex_format(uint64_t p_surface_format, uint64_t p_input_mask, bool p_instanced_surface, bool p_input_motion_vectors, uint32_t &r_position_stride); - void _mesh_surface_generate_version_for_input_mask(Mesh::Surface::Version &v, Mesh::Surface *s, uint64_t p_input_mask, bool p_input_motion_vectors, MeshInstance::Surface *mis = nullptr, uint32_t p_current_buffer = 0, uint32_t p_previous_buffer = 0); + RD::VertexFormatID _mesh_surface_generate_vertex_format(uint64_t p_surface_format, uint64_t p_input_mask, bool p_instanced_surface, bool p_input_motion_vectors, bool p_point_size_emulated, uint32_t &r_position_stride); + void _mesh_surface_generate_version_for_input_mask(Mesh::Surface::Version &v, Mesh::Surface *s, uint64_t p_input_mask, bool p_input_motion_vectors, bool p_point_size_emulated, MeshInstance::Surface *mis = nullptr, uint32_t p_current_buffer = 0, uint32_t p_previous_buffer = 0); void _mesh_surface_clear(Mesh *p_mesh, int p_surface); void _mesh_instance_clear(MeshInstance *mi); @@ -445,6 +446,11 @@ public: return surface->primitive; } + _FORCE_INLINE_ uint32_t mesh_surface_get_vertex_count(void *p_surface) { + Mesh::Surface *surface = reinterpret_cast(p_surface); + return surface->vertex_count; + } + _FORCE_INLINE_ bool mesh_surface_has_lod(void *p_surface) const { Mesh::Surface *s = reinterpret_cast(p_surface); return s->lod_count > 0; @@ -500,7 +506,7 @@ public: } } - _FORCE_INLINE_ void mesh_surface_get_vertex_arrays_and_format(void *p_surface, uint64_t p_input_mask, bool p_input_motion_vectors, RID &r_vertex_array_rd, RD::VertexFormatID &r_vertex_format) { + _FORCE_INLINE_ void mesh_surface_get_vertex_arrays_and_format(void *p_surface, uint64_t p_input_mask, bool p_input_motion_vectors, bool p_point_size_emulated, RID &r_vertex_array_rd, RD::VertexFormatID &r_vertex_format) { Mesh::Surface *s = reinterpret_cast(p_surface); s->version_lock.lock(); @@ -508,7 +514,7 @@ public: //there will never be more than, at much, 3 or 4 versions, so iterating is the fastest way for (uint32_t i = 0; i < s->version_count; i++) { - if (s->versions[i].input_mask != p_input_mask || s->versions[i].input_motion_vectors != p_input_motion_vectors) { + if (s->versions[i].input_mask != p_input_mask || s->versions[i].input_motion_vectors != p_input_motion_vectors || s->versions[i].point_size_emulated != p_point_size_emulated) { // Find the version that matches the inputs required. continue; } @@ -524,7 +530,7 @@ public: s->version_count++; s->versions = (Mesh::Surface::Version *)memrealloc(s->versions, sizeof(Mesh::Surface::Version) * s->version_count); - _mesh_surface_generate_version_for_input_mask(s->versions[version], s, p_input_mask, p_input_motion_vectors); + _mesh_surface_generate_version_for_input_mask(s->versions[version], s, p_input_mask, p_input_motion_vectors, p_point_size_emulated); r_vertex_format = s->versions[version].vertex_format; r_vertex_array_rd = s->versions[version].vertex_array; @@ -532,7 +538,7 @@ public: s->version_lock.unlock(); } - _FORCE_INLINE_ void mesh_instance_surface_get_vertex_arrays_and_format(RID p_mesh_instance, uint64_t p_surface_index, uint64_t p_input_mask, bool p_input_motion_vectors, RID &r_vertex_array_rd, RD::VertexFormatID &r_vertex_format) { + _FORCE_INLINE_ void mesh_instance_surface_get_vertex_arrays_and_format(RID p_mesh_instance, uint64_t p_surface_index, uint64_t p_input_mask, bool p_input_motion_vectors, bool p_point_size_emulated, RID &r_vertex_array_rd, RD::VertexFormatID &r_vertex_format) { MeshInstance *mi = mesh_instance_owner.get_or_null(p_mesh_instance); ERR_FAIL_NULL(mi); Mesh *mesh = mi->mesh; @@ -571,7 +577,7 @@ public: mis->version_count++; mis->versions = (Mesh::Surface::Version *)memrealloc(mis->versions, sizeof(Mesh::Surface::Version) * mis->version_count); - _mesh_surface_generate_version_for_input_mask(mis->versions[version], s, p_input_mask, p_input_motion_vectors, mis, current_buffer, previous_buffer); + _mesh_surface_generate_version_for_input_mask(mis->versions[version], s, p_input_mask, p_input_motion_vectors, p_point_size_emulated, mis, current_buffer, previous_buffer); r_vertex_format = mis->versions[version].vertex_format; r_vertex_array_rd = mis->versions[version].vertex_array; @@ -623,10 +629,10 @@ public: return s->particles_render_index; } - _FORCE_INLINE_ RD::VertexFormatID mesh_surface_get_vertex_format(void *p_surface, uint64_t p_input_mask, bool p_instanced_surface, bool p_input_motion_vectors) { + _FORCE_INLINE_ RD::VertexFormatID mesh_surface_get_vertex_format(void *p_surface, uint64_t p_input_mask, bool p_instanced_surface, bool p_input_motion_vectors, bool p_point_size_emulated) { Mesh::Surface *s = reinterpret_cast(p_surface); uint32_t position_stride = 0; - return _mesh_surface_generate_vertex_format(s->format, p_input_mask, p_instanced_surface, p_input_motion_vectors, position_stride); + return _mesh_surface_generate_vertex_format(s->format, p_input_mask, p_instanced_surface, p_input_motion_vectors, p_point_size_emulated, position_stride); } Dependency *mesh_get_dependency(RID p_mesh) const; diff --git a/servers/rendering/rendering_device.cpp b/servers/rendering/rendering_device.cpp index b817536fa42..9e9192d6eeb 100644 --- a/servers/rendering/rendering_device.cpp +++ b/servers/rendering/rendering_device.cpp @@ -5097,10 +5097,6 @@ void RenderingDevice::draw_list_draw(DrawListID p_list, bool p_use_indices, uint uint32_t to_draw; if (p_procedural_vertices > 0) { -#ifdef DEBUG_ENABLED - ERR_FAIL_COND_MSG(draw_list.validation.pipeline_vertex_format != INVALID_ID, - "Procedural vertices requested, but pipeline expects a vertex array."); -#endif to_draw = p_procedural_vertices; } else { #ifdef DEBUG_ENABLED diff --git a/servers/rendering/rendering_device_commons.h b/servers/rendering/rendering_device_commons.h index d168eef7af6..e012e266685 100644 --- a/servers/rendering/rendering_device_commons.h +++ b/servers/rendering/rendering_device_commons.h @@ -973,6 +973,7 @@ public: SUPPORTS_IMAGE_ATOMIC_32_BIT, SUPPORTS_VULKAN_MEMORY_MODEL, SUPPORTS_FRAMEBUFFER_DEPTH_RESOLVE, + SUPPORTS_POINT_SIZE, }; enum SubgroupOperations {