FontStashSharp / FontStashSharp

C# port of https://github.com/memononen/fontstash

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

[BUG] Reused atlases sometimes dont get cleared

Beyley opened this issue · comments

When FSS packs glyphs in the atlas it tends to pack them as tighly as possible, while this is not a problem in a lot of cases, it can cause them to bleed into one another when the characters have a lot of straight lines on the edges, eg. Chinese characters/Japanese Kanji in GNU Unifont
This requires you to use Point filtering when drawing the texture, which does not look as good as bilinear filtering. The solution is to optionally add a pixel between each glyph when packing (maybe in FontSystemSettings?)
This will let bilinear filtering work

This issue also seems to be caused by the same texture being reused by FSS without clearing it out first, which it does not seem to do eg: when FontSystem.Reset(); is called

Heres a screenshot of what my atlases look like after awhile
image

Perhaps there should be a ClearTexture method in ITexture2DManager?

  1. In fact, there is 2-pixel padding for every glyph. Check usage of this constant:

    public const int GlyphPad = 2;

    Though it should be made configurable, ofc.

  2. If you're passing to FSS texture that had been already in use through ITexture2DManager.CreateTexture, then you could clean it there(in CreateTexture).

  1. In fact, there is 2-pixel padding for every glyph. Check usage of this constant:

    public const int GlyphPad = 2;

    Though it should be made configurable, ofc.

  2. If you're passing to FSS texture that had been already in use through ITexture2DManager.CreateTexture, then you could clean it there(in CreateTexture).

oh i wonder if it's just been the 'not clearing' problem and doesn't have to do with packing distance, as i'm not passing in a texture already in use, i'm telling FSS to reset the fontsystem and it seems that it's refilling the texture with glyphs but not clearing it beforehand

This issue also seems to be caused by the same texture being reused by FSS without clearing it out first, which it does not seem to do eg: when FontSystem.Reset(); is called

Heres a screenshot of what my atlases look like after awhile
image

Perhaps there should be a ClearTexture method in ITexture2DManager?

the top left image is the most mangled by this problem, you can see bits and pieces of old glyphs coming through

  1. In fact, there is 2-pixel padding for every glyph. Check usage of this constant:

    public const int GlyphPad = 2;

    Though it should be made configurable, ofc.

  2. If you're passing to FSS texture that had been already in use through ITexture2DManager.CreateTexture, then you could clean it there(in CreateTexture).

oh i wonder if it's just been the 'not clearing' problem and doesn't have to do with packing distance, as i'm not passing in a texture already in use, i'm telling FSS to reset the fontsystem and it seems that it's refilling the texture with glyphs but not clearing it beforehand

I just looked at Reset code and there's a bug. It clears list of atlases, but doesnt set _currentAtlas to 'null'. Hence it continues to being filled.

Fixed the problem and released new version 1.1.8
Please, check wether old textures arent being reused now.

Fixed the problem and released new version 1.1.8 Please, check wether old textures arent being reused now.

just updated, unfortanately does not seem to have fixed the problem, you can see the atlasas in the top right and what the text looks like on the bottom left, with random lines at the edges
https://i.beyleyisnot.moe/J1SGTo.png

Well, I would be grateful if you make minimal sample that reproduces the problem.
There's stock sample TextureAtlasFull. I've slightly updated it by adding a line:

  _fontSystem.CurrentAtlasFull += (s, e) => _fontSystem.Reset();

And it still seems to work fine: the new texture is created after previous runs out of space.

Well, I would be grateful if you make minimal sample that reproduces the problem. There's stock sample TextureAtlasFull. I've slightly updated it by adding a line:

  _fontSystem.CurrentAtlasFull += (s, e) => _fontSystem.Reset();

And it still seems to work fine: the new texture is created after previous runs out of space.

patch file, just spam up and down arrow keys at random at ittl trigger it

kHxoYcs.png

renamed to more accurately represent the issue at hand

Unfortunately I am still unable to reproduce the issue even with the provided patch and instructions.
FSS

Unfortunately I am still unable to reproduce the issue even with the provided patch and instructions.
FSS

very very odd, may it be driver differences? i'm on Linux with Nvidia drivers

I am on win10. Though lemme check in Linux vm...

Couldn't reproduce on Linux VM too

ex.mp4

Not sure why you cant reproduce it, its extremely consistent on my machine, maybe its some weird asyncronous buffer updates in GL land that nvidia freaks out about because its still uploading the data when the texture is cleared to be used again?

you can even see the effects of the bug in this screenshot
https://i.beyleyisnot.moe/LXpFXx8.png

It's important to note, that FSS doesnt clear textures. When you call Reset, it simply deletes all existing atlases. And the new atlas would be created whenever the first symbol would be drawn.

Try explicitly clearing the texture after creation in your implementation of ITexture2DManager.CreateTexture. Maybe that will help.

I've released new FSS 1.2.0, where FontSystem has new property EraseTextureOnCreation(set to false by default) that does exactly what it says.
Can I ask you to set it to 'true' and check if it resolves the issue?

From a quick glance that seems to have fixed it! im going to do a more thourough check first before closing the issue though

Thanks! I'll add EraseTextureOnCreation to FontSystemDefaults in the future version.

On the second thought, I'll make it so the newly created textures will always get erased. After all, seems like we can't guarantee that any driver for any gpu will return clean textures on creation. Hence it'll always get cleared and the new property EraseTextureOnCreation will be removed.

Since the version 1.2.1 the newly created textures are always erased. The property EraseTextureOnCreation was removed.