Ruben Osorio

Ruben Osorio

@osor.io

Senior VFX/Graphics Programmer working @ Rockstar Games All posts/opinions/views my own :) Website at https://osor.io

348 followers91 following65 posts

Hola again graphics peeps! ๐Ÿ˜Š I found myself with enough bits and pieces related to text rendering to warrant a write-up. So here it is! ๐Ÿ˜ฑ osor.io/text Spiced up with direct vector rendering, sub-pixel anti-aliasing, run-time atlas packing, temporal accumulation, and more! I hope you enjoy it! ๐Ÿงก

View full thread

Hola again graphics peeps! ๐Ÿ˜Š I found myself with enough bits and pieces related to text rendering to warrant a write-up. So here it is! ๐Ÿ˜ฑ osor.io/text Spiced up with direct vector rendering, sub-pixel anti-aliasing, run-time atlas packing, temporal accumulation, and more! I hope you enjoy it! ๐Ÿงก

My first one one got an unexpected amount of interest. Huge thanks to everyone who read it! (Especially @jendrikillner.bsky.social since he was probably the biggest reason ๐Ÿ˜„) This topic gets way more coverage but I've never seen it done/presented like this, so trying to make my contribution ๐Ÿ™

Tried a few ways to resolve a visibility buffer as a nightly adventure a few days ago ๐Ÿ˜„ So far my favourite I could come up with is collecting lists of pixels per shader, internally sorted per draw, then a dispatch indirect per shader scalarizing on the draw index. Plus it can have cute bugs! ๐Ÿ™ƒ ๐Ÿงต

View full thread

If you need the correct index per-thread, as you do when you're going to write the samples to the buffer, there's some more wave-ops involved, since you also need to calculate the local offset for each thread on the wave. WaveReadLaneFirst/WavePrefixCountBits sorts you out, here is how it'd look:

The first active thread of the wave does the atomic and retrieves the global offset for the wave, WaveReadLaneFirst then broadcasts it. The local offset within the wave comes from WavePrefixCountBits, since it's just the count of how many threads with a lower index are also writing one element.

Tried a few ways to resolve a visibility buffer as a nightly adventure a few days ago ๐Ÿ˜„ So far my favourite I could come up with is collecting lists of pixels per shader, internally sorted per draw, then a dispatch indirect per shader scalarizing on the draw index. Plus it can have cute bugs! ๐Ÿ™ƒ ๐Ÿงต

View full thread

Paying my respects with a video rendering 10% of the pixels each frame (hacking this in just now so turning all denoising and TAA off, no reprojection of "empty" pixels either ๐Ÿ˜œ). (Prepare for the bsky video butchering though)

Oh! Also worth mentioning. In this sort of system you'll see a lot of contention when writing to shared counters. It's a good idea to minimize this by doing the global write once per wave or group. A neat trick is to also scalarize on the shader/draw for when a wave sees different values there ๐Ÿ™ƒ

Tried a few ways to resolve a visibility buffer as a nightly adventure a few days ago ๐Ÿ˜„ So far my favourite I could come up with is collecting lists of pixels per shader, internally sorted per draw, then a dispatch indirect per shader scalarizing on the draw index. Plus it can have cute bugs! ๐Ÿ™ƒ ๐Ÿงต

View full thread

And because this approach ends up compacting the list of pixels per-draw, it responds really well to scenes with heavy dithering into the visibility buffer. Some of the other tile-based approaches I tried struggled with this, since they'd need to dispatch multiple resolve tiles per tile on-screen.

Tried a few ways to resolve a visibility buffer as a nightly adventure a few days ago ๐Ÿ˜„ So far my favourite I could come up with is collecting lists of pixels per shader, internally sorted per draw, then a dispatch indirect per shader scalarizing on the draw index. Plus it can have cute bugs! ๐Ÿ™ƒ ๐Ÿงต

View full thread

I *really* like the flexibility of this approach while keeping the resolve waves full. With this you can do software VRS easily, both spatially and temporally, which is super cool! You can just write any logic to decide how the visibility buffer values map to a sample to resolve.

Plus you also can select variations of the shaders to further optimize! If a pixel is not seeing any local lights, you can dispatch a version of the resolve shader that has all the local light code compiled out. Or if a pixel is fully in shadow from directional light, nuke all that code too, etc...

Tried a few ways to resolve a visibility buffer as a nightly adventure a few days ago ๐Ÿ˜„ So far my favourite I could come up with is collecting lists of pixels per shader, internally sorted per draw, then a dispatch indirect per shader scalarizing on the draw index. Plus it can have cute bugs! ๐Ÿ™ƒ ๐Ÿงต

View full thread

This can include a lot of data like per-draw transforms, tinting, material stuff, and notoriously also including the bindless texture indices. Nice not to need any of that NonUniformResourceIndex uglyness.

There's only a few waves per-frame that see two or more draws when resolving, which are the only cases where the waves aren't fully utilized. This is as good as it can be anyway, if those waves weren't going to shade another draw, they would have been inactive in a "wave-perfect" resolve anyway.

Tried a few ways to resolve a visibility buffer as a nightly adventure a few days ago ๐Ÿ˜„ So far my favourite I could come up with is collecting lists of pixels per shader, internally sorted per draw, then a dispatch indirect per shader scalarizing on the draw index. Plus it can have cute bugs! ๐Ÿ™ƒ ๐Ÿงต

View full thread

The resolve is dispatched per-shader, not per-draw, so it's still a very manageable amount of dispatch indirect calls. As in, a single one for all your variations of standard, anisotropic, whatever... so there isn't a ton of concerns about empty dispatch indirect arguments.

Because the list is not only sorted per-shader but also per-draw, most of the waves will just see one draw! To take advantage of this, I scalarize based on the draw index, so all of the draw-related data can be uniform and stay in scalar registers. With a noticeable win in occupancy too ๐Ÿ˜Š

Tried a few ways to resolve a visibility buffer as a nightly adventure a few days ago ๐Ÿ˜„ So far my favourite I could come up with is collecting lists of pixels per shader, internally sorted per draw, then a dispatch indirect per shader scalarizing on the draw index. Plus it can have cute bugs! ๐Ÿ™ƒ ๐Ÿงต

To collect the lists, I first count how many pixels each draw and shader want, then allocate space in a big buffer for each shader, then allocate space for each draw within the chunk allocated for their shader. Then repeat the same logic but writing the pixels to the buffer with the right offset.

Tried writing them once unsorted then sorting, but like I imagined, is just too expensive. I do believe you could make something like this work if you tiled the whole resolve and kept the working set of in local memory though. You need enough tiles/work in flight to feed a big GPU though.

Spent a wee bit implementing some ๐Ÿซฐ rich-ish ๐Ÿซฐ text with support for *bold* and _italic_ annotations plus some cheeky line wrapping. Here's the beginning of a possible future post running through it ๐Ÿ“„ Also "Look ma, no textures!" Just tracing them rays agaist them beziers โค๏ธ

๐Ÿชฆ for the 720p video. Bluesky was destroying the small/timeline version of it otherwise. Let's see how a 1440p one shows? ๐Ÿค”

Added a small section to osor.io/OIT about a neat way to avoid self-occlusion when sampling transmittance ๐Ÿ˜Š It came up in conversation enough times that it's worth updating instead of waiting for a new post โค๏ธ Also, some peeps asked for a clip with less & slower spheres intersecting so here it is! ๐Ÿ™

Graphics Programming Conference was incredible โค๏ธ So many notes to go through, ideas to investigate, people to talk to and games to play! ๐Ÿ”ฅ Thank you so much to the organizers and all the attendees, it was such a pleasure to meet you all ๐Ÿ˜Š Can we have Texels sponsor next year though? ๐Ÿป๐Ÿ™ƒ

Hola graphics people! โค๏ธ I've been meaning to do some write-ups that are hopefully useful, so this first one is about my approach to Order-Independent Transparency. osor.io/OIT ๐Ÿ™ŒSuper excited to finally release this!๐Ÿ™Œ I hope you enjoy it!

If anyone stumbles in here, I like to partake in some cheeky programming at home and I would like to share a bit more of it โค๏ธ More than *nothing at all* which is the amount right now ๐Ÿ™ƒ The intention is to do a bit more blogging soon too ๐Ÿคž Here's a old meshlet culling video for eye candy ๐Ÿ˜‚

Happy to see more of the graphics community here ๐Ÿ˜Š Perhaps I should be posting a little bit more, and over the past few days I've been bitten by the text rendering bug again so... here's a video saying hi! ๐Ÿ‘‹๐Ÿ˜„

โŒจ๏ธ๐Ÿ™Œ Hall Effect on an Alice layout! ๐Ÿ™ŒโŒจ๏ธ Seems like hall effect/magnetic keyboards have become all the rage but I was sad that there was no options I could find for my favourite layout. So... here we are making a PCB and writing some firmware ๐Ÿ˜„ ๐Ÿงต๐Ÿงต๐Ÿงต

View full thread

I made it compatible with the Maja V2 case I already loved, but I'm now getting pretty tempted to design a 3D-printable case so I can have more of these ๐Ÿ˜… These SLS prints look very nice. My current keyboard now looks... exactly as it did before! But with different guts ๐Ÿ˜

This is the previous controller I made using hall effect sensors, which is still my preffered way to play fighting games by far! bsky.app/profile/osor...

Ruben Osorio@osor.io

๐ŸŽฎโ„๏ธLate Christmas project post!โ„๏ธ๐ŸŽฎ A controller with hall-effect sensors, custom firmware, PCB and case. With a funky layout too ๐Ÿ™ƒ Been playing fighting games with this since and I've been really enjoying it! Here's some pics ๐Ÿ–ผ๏ธ

โŒจ๏ธ๐Ÿ™Œ Hall Effect on an Alice layout! ๐Ÿ™ŒโŒจ๏ธ Seems like hall effect/magnetic keyboards have become all the rage but I was sad that there was no options I could find for my favourite layout. So... here we are making a PCB and writing some firmware ๐Ÿ˜„ ๐Ÿงต๐Ÿงต๐Ÿงต

Took a few iterations of writing the firmware and testing it to get it feeling well but we got there in the end. These STM microcontrollers have a super nice software stack which makes getting something up and running and testing it very comfortable.

๐ŸŽฎโ„๏ธLate Christmas project post!โ„๏ธ๐ŸŽฎ A controller with hall-effect sensors, custom firmware, PCB and case. With a funky layout too ๐Ÿ™ƒ Been playing fighting games with this since and I've been really enjoying it! Here's some pics ๐Ÿ–ผ๏ธ

View full thread

A good example of this is if you have a key pressed fully, the moment you start releasing it you can send a "release", without it waiting to reach the fully depressed state. Similar to what Wooting does on keyboards that they call "Rapid Trigger" (wooting.io/rapid-trigger)

It gives a sensation of minimal latency that's very satisfying, plus stuff like double taps becomes much more responsive. This is ideal for fighting games, and I was surprised when I didn't find any previous products doing this. I wouldn't be surprised if this became more standard in the future ๐Ÿ˜Š

๐ŸŽฎโ„๏ธLate Christmas project post!โ„๏ธ๐ŸŽฎ A controller with hall-effect sensors, custom firmware, PCB and case. With a funky layout too ๐Ÿ™ƒ Been playing fighting games with this since and I've been really enjoying it! Here's some pics ๐Ÿ–ผ๏ธ

With the hall-effect sensors you can get an analogue value of how much each key is pressed, the right thumb button is bound to what it would be an "up" direction on a joystick for example, with it sending values between 0 and 1 depending on how far pressed it is. This has another really neat usage.

Because you can see how much a key is pressed instead of a binary state (with normal switches), you can register a "press" whenever the user starts pressing the key and a "release" whenever they start releasing it, regardless of how pressed or not the key is.

Hey Bluesky! I guess this is good timing for an introduction ๐Ÿฅฐ I'm a Senior VFX/Graphics Programmer working @ Rockstar North. And I'm also really excited for everyone to see this little thing on December 5th ๐Ÿ˜Š Hope you like it!!

You are up to date.