Implement point size emulation in the forward shader for D3D12.

This commit is contained in:
Skyth 2025-10-28 17:21:34 +03:00
parent f5918a9d35
commit ba556ebe03
18 changed files with 249 additions and 46 deletions

View file

@ -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;
}

View file

@ -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;
}

View file

@ -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;
}

View file

@ -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);

View file

@ -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<ShaderRD::VariantDefine> 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;

View file

@ -342,6 +342,7 @@ public:
SceneForwardClusteredShaderRD shader;
ShaderCompiler compiler;
bool emulate_point_size = false;
RID default_shader;
RID default_material;

View file

@ -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<ShaderPipelinePair> *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);

View file

@ -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;

View file

@ -345,6 +345,7 @@ public:
SceneForwardMobileShaderRD shader;
ShaderCompiler compiler;
bool use_fp16 = false;
bool emulate_point_size = false;
RID default_shader;
RID default_material;

View file

@ -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);
}
}

View file

@ -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
}

View file

@ -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

View file

@ -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
}

View file

@ -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)

View file

@ -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<RD::VertexAttribute> 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<RID> buffers;
Vector<uint64_t> 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

View file

@ -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<Mesh::Surface *>(p_surface);
return surface->vertex_count;
}
_FORCE_INLINE_ bool mesh_surface_has_lod(void *p_surface) const {
Mesh::Surface *s = reinterpret_cast<Mesh::Surface *>(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<Mesh::Surface *>(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<Mesh::Surface *>(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;

View file

@ -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

View file

@ -973,6 +973,7 @@ public:
SUPPORTS_IMAGE_ATOMIC_32_BIT,
SUPPORTS_VULKAN_MEMORY_MODEL,
SUPPORTS_FRAMEBUFFER_DEPTH_RESOLVE,
SUPPORTS_POINT_SIZE,
};
enum SubgroupOperations {