xterm.js icon indicating copy to clipboard operation
xterm.js copied to clipboard

Support multiple textures in webgl and canvas renderer

Open Tyriar opened this issue 3 years ago • 3 comments

VS Code issue: https://github.com/microsoft/vscode/issues/158876

Currently we support a single 1024x1024 texture in the webgl renderer, when it gets filled we clear it and restart. Ideally we would support multiple textures (~4mb each) up to some maximum, this would let us support high dpi displays much better.

The canvas texture atlas has the same issue.

Tyriar avatar Aug 23 '22 14:08 Tyriar

Can just increase the size of the atlas as well, up to gl.getParameter(gl.MAX_TEXTURE_SIZE) (16384 on my macbook). Perhaps increase the size only on reset to keep memory minimal?

Tyriar avatar Aug 28 '22 20:08 Tyriar

Actually I think the reason the texture is small was to keep the uploads on new glyphs shorter.

Tyriar avatar Aug 28 '22 20:08 Tyriar

Just some brainstorming on this (as I have lit. no clue how its organized currently on either webgl or canvas end):

  • Put standard glyphs (as of ASCII print range, maybe enhanced by some additional often occuring chars/interpunction) in a static texture calculated early on startup. This texture never gets altered, but only read from.
  • Put any other glyph in additional textures on the fly. In the beginning those textures are only filling up from more and more chars coming, once the total texture space is taken some eviction (by some "cache rules") takes place.
  • Possible eviction on non static textures:
    • first eviction run - drop all additional textures, recreate them with descending char likelihood (most likely in first non-static texture, least often seen go to last texture)
    • later eviction runs - on default drop and recreate only last texture, once in a while re-eval char-likelihoods (running counters?) and do recreation on earlier textures, if some threshold is hit

The "cache strategy" above would try to order chars on textures based on their occurrences in the past with the assumption, that often seen chars will be more likely in the future as well. This should get pretty stable over time at least for the first non-static textures, later textures will show more changes over time. Maybe this way texture can be kept pretty small to avoid costly recreation?

A slightly more advanced model would "overflow" into the next texture earlier (like when it is only halfway filled) and already re-eval char amounts during this step to get a better initial ordering with less full recreation steps.

jerch avatar Sep 03 '22 13:09 jerch

Put standard glyphs (as of ASCII print range, maybe enhanced by some additional often occuring chars/interpunction) in a static texture calculated early on startup. This texture never gets altered, but only read from.

This is pretty much how it works, just we pack it in the single texture; we warm up the these standard glyphs (part of ascii range, default fg/bg) in idle callbacks. If we wanted to support more than 1 texture I think we should just make the whole system scale out dynamically to n textures. It looks possible, and it was one of my weekend projects a few weeks ago but I got distracted with other stuff 😄

There is also the option of just increasing the texture size which would fix the problem for most users easily, but I've been hesitant to do that since the larger the texture is, the longer it blocks the main thread to initialize and upload. Better might actually be to reduce the texture size when we move to supporting n of textures (from 1024x1024 to 512x512, possibly multiplying by devicePixelRatio?). I think reducing the texture size is a similar idea to your static texture idea by lowering the amount of effort it is to push new textures?

Here's an example of the demo starting up, showing the relative weight of the texture upload:

image

I think the getContext above will also scale depending on how large the texture is.

Possible eviction on non static textures

Eviction always seemed like more effort than it is worth to me, tracking it will end up eating more memory and cpu time and since we already pack the atlas pretty tight, the spots in between would be pretty small. In most real world use cases the user never hits the texture limit as well. The amount of GPU memory we end up consuming is also quite small which is another reason eviction feels like overkill, currently the texture takes 102410244 bytes = 4MB.

Tyriar avatar Oct 24 '22 14:10 Tyriar