msdfgl icon indicating copy to clipboard operation
msdfgl copied to clipboard

Without point primitives or geometry shaders?

Open KTRosenberg opened this issue 4 years ago • 5 comments

Hello. I am interested in using MSDFs on platforms / APIs such as Metal and WebGL that do not support geometry shaders. Would you be able to offer some guidance on how one might transition to just a vertex and fragment shader? It seems that a lot would need to change, though. Alternatively, would you consider exploring how to make a variant of this library for other APIs? Thank you for your time.

KTRosenberg avatar Mar 14 '20 22:03 KTRosenberg

Thanks for your interest!

You are right, currently the geometry shader plays a significant part in the rendering process. To drop the geometry shader from the equation, two options that come to my mind are:

  1. Move the atlas texture entirely onto CPU. This comes with the drawback that we need to perform the calculations to take into account the texture scale, font size, each glyph dimensions, glyph padding sequentially on the CPU. The performance hit would probably be minimal, though, as the amount of calculation done is not huge.
  2. Send each vertex four times, with an additional "binary" vec2 indicating which of the four corners that vertex represents. That would allow for doing the current work of the geometry shader in the vertex shader. Downside here being that we would need to send 6x more vertex data (or 4x + an index buffer) onto the GPU in each call to msdfgl_render. This option would probably be easier to implement at this point, and IMO a bit cleaner as we would still perform all the parallelizable computation in the HW that does it the best. Additionally, we would be able to support both this method and the geometry shader method and share a lot more of the code between the two, compared to the option 1.

I have been considering adding a support for the user to use their own shader program with msdfgl in the future. This feature feels natural to implement together with it. Let's see if Finland goes under quarantine in the following days, I might then have some time to allocate for this project... :sweat_smile:

nyyManni avatar Mar 15 '20 08:03 nyyManni

Option 2 sounds like the better way to go. By the way, looking at the fragment shader there seems to be a lot going on. I thought it was meant to be simple, but are you doing anything special? I am curious whether this could perform well on mobile Android platforms (e.g. mobile VR). A lot more would need to change though. buffer samplers among other features don’t exist in webgl2.

KTRosenberg avatar Mar 15 '20 12:03 KTRosenberg

I assume you are talking about the msdf_fragment-shader, as there are two fragment shaders. msdf_fragment.glsl implements the whole MSDF algorithm in GPU, so it has a lot going on. The idea of msdfgl was to implement the expensive texture generation in the GPU side. The sampler buffers are needed, as we essentially serialize the freetype-data directly onto the GPU. Rendering the distance field of a single glyph requires all of the freetype data to be available for the shader, so it is not feasible to do it with a vertex array. It does not do any magic, per se, it only contains quite a bit more logic compared to a more typical fragment shader. I don't see why it wouldn't be able to run on mobile, as long as the OpenGL implementation supports the required features.

In a more restricted environment, it might make more sense to generate the MSDF texture beforehand, with for example https://github.com/Chlumsky/msdfgen, which runs entirely on the CPU.

The fragment shader used by the font rendering font_fragment.glsl is quite simple, it does a basic anti-aliasing and allows for a customizable font strength.

nyyManni avatar Mar 15 '20 12:03 nyyManni

Ah, I see. Font generation could be done offline. Do you have any tips for using that generator you posted to create something completely compatible with your system? From what I can tell, you need to go a character at a time.

In any case, thanks for your responses.

KTRosenberg avatar Mar 15 '20 13:03 KTRosenberg

I actually played around with a setup like that. I do not have a ready-made implementation, but what you can do is to look into my other side-project at https://github.com/nyyManni/wlterm/commits/opengl, and my fork of msdfgen. Both of which you want to look into the commits far in the past, around https://github.com/nyyManni/wlterm/tree/e04da3ed8d34493f722afade61b567197e9e449b.

There, I generate a similar buffer using a modified version of msdfgen, upload that texture to the GPU and render text with it. The code is definitely not very readable, nor do I expect it to compile on someone else's environment. However, it could give you an idea of how to approach this. The later revisions of that project use msdfgl now.

nyyManni avatar Mar 15 '20 13:03 nyyManni