icculus / mojoshader

Use Direct3D shaders with other 3D rendering APIs.
https://icculus.org/mojoshader/
zlib License
122 stars 36 forks source link

Add proper support for gl_PointCoord and [[point_coord]] #19

Closed TheSpydog closed 4 years ago

TheSpydog commented 4 years ago

Tested successfully with Flotilla on macOS OpenGL and Metal.

This was actually pretty straightforward to implement, although there is a catch: the current implementation runs the risk of nuking actual uses of TEXCOORD0. If an effect contains any vertex shader with a POINTSIZE attribute, it will search+replace "gl_TexCoord[0]" -> "gl_PointCoord" for all fragment shaders in the effect. This works for Flotilla, but I'm nervous it might screw with other games that use point drawing.

One alternative would be to go through each pass in each technique in each effect and only perform the switcheroo on pixel shaders whose corresponding vertex shader has the point size attribute. But that gets complicated pretty quickly and leads to weird edge cases... I'll experiment with it more when I get the time.

flibitijibibo commented 4 years ago

For us to do this accurately we have to think beyond just Effects - we have to be mindful of the actual HLSL specification and behavior, which is that TEXCOORDs that are specified in the pixel shader but not the vertex shader are treated as point coords, and if it’s not rendering points then the behavior is undefined. So the real fix is in MojoShader’s core, not the effects system.

I’ll try a GLSL variant next week. Odds are MSL will just have to emit two pixel shaders when TEXCOORD0 is active, but I think I can take krolli’s work and make it more reusable.

flibitijibibo commented 4 years ago

Took a crack at this myself... the conclusion I ultimately came to was this:

At this point I'm comfortable pursuing this as a Metal issue only. OpenGL compat works, OpenGL Core works, Vulkan should work, and Metal will cover every existing GLES target except for ANGLE, which is only used "officially" for Xbox. And scarily enough, D3D11 does support point sprites, but with a whole lot of emulation involved... in that case it'd probably be better to make an Xbox-only path of quads in the application. D3D12 goes back to supporting points again, so ideally this problem will just silently go away in the future.

In my experimentation it seems easy enough to check for pshader->has_texcoord0 && !vshader->has_texcoord0 and then use the right pixel shader, how that's stored is up to mojoshader_metal.c... I don't think the core (or public API) will get affected by it, so I was definitely wrong on that part.