diff --git a/src/back/glsl/mod.rs b/src/back/glsl/mod.rs index 6c90fcb26d..838b323441 100644 --- a/src/back/glsl/mod.rs +++ b/src/back/glsl/mod.rs @@ -218,6 +218,13 @@ bitflags::bitflags! { /// global variables that are not used in the specified entrypoint (including indirect use), /// all constant declarations, and functions that use excluded global variables. const INCLUDE_UNUSED_ITEMS = 0x4; + /// Emit `PointSize` output builtin to vertex shaders, which is + /// required for drawing with `PointList` topology. + /// + /// https://registry.khronos.org/OpenGL/specs/es/3.2/GLSL_ES_Specification_3.20.html#built-in-language-variables + /// The variable gl_PointSize is intended for a shader to write the size of the point to be rasterized. It is measured in pixels. + /// If gl_PointSize is not written to, its value is undefined in subsequent pipe stages. + const FORCE_POINT_SIZE = 0x10; } } @@ -1978,6 +1985,7 @@ impl<'a, W: Write> Writer<'a, W> { writeln!(self.out, ";")?; } back::FunctionType::EntryPoint(ep_index) => { + let mut has_point_size = false; let ep = &self.module.entry_points[ep_index as usize]; if let Some(ref result) = ep.function.result { let value = value.unwrap(); @@ -2005,11 +2013,18 @@ impl<'a, W: Write> Writer<'a, W> { if let Some(crate::Binding::BuiltIn(builtin)) = member.binding { + has_point_size |= builtin == crate::BuiltIn::PointSize; + match builtin { crate::BuiltIn::ClipDistance - | crate::BuiltIn::CullDistance - | crate::BuiltIn::PointSize => { + | crate::BuiltIn::CullDistance => { if self.options.version.is_es() { + // Note that gl_ClipDistance and gl_CullDistance are listed in the GLSL ES 3.2 spec but shouldn't + // See https://github.com/KhronosGroup/GLSL/issues/132#issuecomment-685818465 + log::warn!( + "{:?} is not part of GLSL ES", + builtin + ); continue; } } @@ -2056,20 +2071,30 @@ impl<'a, W: Write> Writer<'a, W> { } } - if let back::FunctionType::EntryPoint(ep_index) = ctx.ty { - if self.module.entry_points[ep_index as usize].stage - == crate::ShaderStage::Vertex - && self - .options - .writer_flags - .contains(WriterFlags::ADJUST_COORDINATE_SPACE) - { - writeln!( - self.out, - "gl_Position.yz = vec2(-gl_Position.y, gl_Position.z * 2.0 - gl_Position.w);", - )?; - write!(self.out, "{level}")?; - } + let is_vertex_stage = self.module.entry_points[ep_index as usize].stage + == ShaderStage::Vertex; + if is_vertex_stage + && self + .options + .writer_flags + .contains(WriterFlags::ADJUST_COORDINATE_SPACE) + { + writeln!( + self.out, + "gl_Position.yz = vec2(-gl_Position.y, gl_Position.z * 2.0 - gl_Position.w);", + )?; + write!(self.out, "{level}")?; + } + + if is_vertex_stage + && self + .options + .writer_flags + .contains(WriterFlags::FORCE_POINT_SIZE) + && !has_point_size + { + writeln!(self.out, "gl_PointSize = 1.0;")?; + write!(self.out, "{level}")?; } writeln!(self.out, "return;")?; } diff --git a/tests/in/force_point_size_vertex_shader_webgl.param.ron b/tests/in/force_point_size_vertex_shader_webgl.param.ron new file mode 100644 index 0000000000..9499c6b990 --- /dev/null +++ b/tests/in/force_point_size_vertex_shader_webgl.param.ron @@ -0,0 +1,11 @@ +( + glsl: ( + version: Embedded ( + version: 300, + is_webgl: true + ), + writer_flags: (bits: 16), + binding_map: {}, + zero_initialize_workgroup_memory: true, + ), +) diff --git a/tests/in/force_point_size_vertex_shader_webgl.wgsl b/tests/in/force_point_size_vertex_shader_webgl.wgsl new file mode 100644 index 0000000000..001468bd50 --- /dev/null +++ b/tests/in/force_point_size_vertex_shader_webgl.wgsl @@ -0,0 +1,14 @@ +// AUTHOR: REASY +// ISSUE: https://github.com/gfx-rs/wgpu/issues/3179 +// FIX: https://github.com/gfx-rs/wgpu/pull/3440 +@vertex +fn vs_main(@builtin(vertex_index) in_vertex_index: u32) -> @builtin(position) vec4 { + let x = f32(i32(in_vertex_index) - 1); + let y = f32(i32(in_vertex_index & 1u) * 2 - 1); + return vec4(x, y, 0.0, 1.0); +} + +@fragment +fn fs_main() -> @location(0) vec4 { + return vec4(1.0, 0.0, 0.0, 1.0); +} diff --git a/tests/out/glsl/force_point_size_vertex_shader_webgl.fs_main.Fragment.glsl b/tests/out/glsl/force_point_size_vertex_shader_webgl.fs_main.Fragment.glsl new file mode 100644 index 0000000000..5d0f7a8072 --- /dev/null +++ b/tests/out/glsl/force_point_size_vertex_shader_webgl.fs_main.Fragment.glsl @@ -0,0 +1,12 @@ +#version 300 es + +precision highp float; +precision highp int; + +layout(location = 0) out vec4 _fs2p_location0; + +void main() { + _fs2p_location0 = vec4(1.0, 0.0, 0.0, 1.0); + return; +} + diff --git a/tests/out/glsl/force_point_size_vertex_shader_webgl.vs_main.Vertex.glsl b/tests/out/glsl/force_point_size_vertex_shader_webgl.vs_main.Vertex.glsl new file mode 100644 index 0000000000..069595bc81 --- /dev/null +++ b/tests/out/glsl/force_point_size_vertex_shader_webgl.vs_main.Vertex.glsl @@ -0,0 +1,15 @@ +#version 300 es + +precision highp float; +precision highp int; + + +void main() { + uint in_vertex_index = uint(gl_VertexID); + float x = float((int(in_vertex_index) - 1)); + float y = float(((int((in_vertex_index & 1u)) * 2) - 1)); + gl_Position = vec4(x, y, 0.0, 1.0); + gl_PointSize = 1.0; + return; +} + diff --git a/tests/snapshots.rs b/tests/snapshots.rs index 25f307c110..cc2b300558 100644 --- a/tests/snapshots.rs +++ b/tests/snapshots.rs @@ -557,6 +557,7 @@ fn convert_wgsl() { Targets::WGSL | Targets::GLSL | Targets::SPIRV | Targets::HLSL | Targets::METAL, ), ("sprite", Targets::SPIRV), + ("force_point_size_vertex_shader_webgl", Targets::GLSL), ]; for &(name, targets) in inputs.iter() {