How do Games Load SO MANY Textures? | Sparse Bindless Texture Arrays

29,639
0
Published 2023-09-23
How do modern video games manage to load hundreds of high resolution textures when OpenGL expects them to limit themselves to 16 or 32 per draw call? In this video, we go over Sparse Bindless Texture Arrays, a collection of advanced graphics programming techniques in OpenGL and Vulkan, which can be used to get the most out of the video memory available. We also cover texture compression and vertex memory layout, two other techniques which can be used to reduce the memory footprint of games.

I'm a University Student in Computer Science, and I'm endeavoring to be an indie developer. I'm creating Zepha, my own voxel engine, which I'm using to create my own game, as well as an extensible, stable modding framework for community creations. I learned about the techniques in this video first-hand from the 4+ years I've spent developing it.

If you're interested in the type of stuff I show in this video, then be sure to subscribe to be notified when I upload more videos like this! I would really appreciate any sort of interaction, as my channel is super small right now and I'm hoping to grow it in anticipation of my game's release :) Otherwise, thanks for watching!!!

My other social medias:

Discord: aurail.us/discord
Twitch: twitch.tv/aurailus
Patreon: patreon.com/aurailus
Tumblr: tumblr.com/zephagame
Livestream VODs: ‪@AurailusVODs‬

Video Chapters:

00:00 - Introduction
02:14 - Sparse Textures
04:10 - Texture Arrays
06:25 - Bindless Textures
07:19 - Texture Compression
08:58 - Vertex Optimization
10:39 - Final Notes
11:07 - Closing Remarks

Music Used:

5PM - Animal Crossing
Tabloid Jargon - Sonic Mania
Pandora Palace - Deltarune
Lights, Camera, Action! - Sonic Mania
CORE - Undertale
7AM - Animal Crossing

Useful resources:

learnopengl.com/
www.gdcvault.com/play/1020791/Approaching-Zero-Dri…
www.khronos.org/opengl/wiki/Array_Texture
registry.khronos.org/OpenGL/extensions/ARB/ARB_spa…
www.khronos.org/opengl/wiki/Bindless_Texture
registry.khronos.org/OpenGL/extensions/ARB/ARB_bin…

#opengl #gamedev #coding

All Comments (21)
  • @fabiangiesen306
    I work on Unreal Engine on numerous things including most of the texture processing/streaming stack, some notes: 1. GL implementation's low texture bind point limitation is really just a GL-ism. For example, on Windows, going back as far as D3D10 (that was 2006!), D3D required support for 128 texture bind points _per shader stage_. So you could have 128 textures for vertex shaders, another 128 for your fragment shaders, all in the same batch. GPU HW has supported way higher limits than GL usually exposes for decades. 2. That said, even though the actual limit is usually way higher than you can access with unextended GL, bind point limits are per-batch. You can change the bound textures for every draw call if you want, and it is in fact completely normal for games to change active texture bindings many thousands of times per frame. This is true for GL as well. 3. For a powers-of-2 size progression, if you don't want mip map filtering (and when you're using pixel art, you probably don't), you could just create a texture array at size say 512x512 with mip maps (which makes it ballpark 33% larger in memory than without) and then mip map 0 of it is a 512x512 texture array, mip map 1 is a 256x256 texture array, and so forth. You can use texture sampling instructions in the shader that specify the mip map explicitly and this will let you collapse a whole stack of texture sizes into a single bind point, if you want to avoid changing bindings frequently. 4. That said, most games don't use texture arrays much. The most common path is still separate 2D textures and changing all texture bindings whenever the material changes between draw calls. 5. Likewise with sparse textures. You need to distinguish between the technique and the actual hardware feature. The actual HW feature (what GL calls "sparse textures") exists but is rarely actually used by games, due to some fundamental problems with how it works. For example, Unreal Engine doesn't use it at all and instead just does it manually in the shader. See e.g. Sean Barrett's "Virtual Textures (aka Megatextures") video on YouTube, a re-recording of a GDC talk he gave in 2008. 2008 was before the dedicated HW feature existed, and most games and engines still use the old all-in-the-shader method. The issue is that the HW method involves manipulating the actual mapping of GPU virtual to physical addresses used by the GPU, which is security-sensitive since there might be data in GPU memory from a different process that you're not allowed to see. (Imagine e.g. a user having a browser tab with their email, a messaging app or their bank app open). So whenever you change the actual GPU virtual->physical mapping, any changes you make need to be vetted by the driver and the OS to ensure you're not trying to gain back-door access to memory you have no business looking at. That makes the "proper" sparse texture mapping update path relatively restricted and slow. The "old school" technique works purely with a manual indirection through your own textures, none of which requires any privileged access or special validation; you're allowed to poke around in your own texture memory, that's fine. So even though it's more work in the shader, updating the mapping can be done from the GPU (the official sparse texture mapping update is CPU-only, since the OS needs to check it) and is much more efficient, and this turns out to be a more important factor in most cases than the higher cost of texture sampling in the shader. 6. Bindless, likewise. This has been around for a while and some games now routinely use it, but most games don't. For example, as of this writing (early Jun 2024), bindless support in Unreal Engine is being worked on but hasn't actually shipped. Currently, most games really just have a bunch of textures around and change bindings more or less every draw call. (These days through somewhat more efficient methods than GL's bind points, but it's still explicit binding.) 7. Texture compression is not really transparent generally. I think some drivers (especially on PC) support creating a texture in a compressed format and then passing in RGB(A) texture data, but this is a convenience thing, not the normal way to use compressed textures, doesn't tend to exist on mobile targets at all, and tends to give pretty poor quality. The normal approach is to compress textures to one of the supported formats off-line using a texture compressor library (these are much slower but higher quality than on-the-fly compression) and then pass that in. 8. DXT3 and DXT5 are the same for the color (RGB) portion and differ only in how they handle A. In practice, ~nobody uses DXT3, and there is not much of a reason to. DXT5 gives better quality pretty much always. 9. One very important thing to keep in mind is how textures are stored in GPU memory. In short, really small textures tend to be incredibly inefficient. It's not rare for texturing HW to require textures (and often individual mip maps) in GPU memory to be a multiple of some relatively large size, often 4kb or even 64kb. This is not a big deal if you're dealing with high-res textures. A 4096x4096 DXT1 texture with mip maps is around 21.3MiB. Rounding that up (even if it happens at the individual mip map level) to multiples of 64k does not change things much. If you're doing pixel art with 16x16 and 32x32 textures though, then even with uncompressed RGBA8, a 32x32 pixel texture is 4kb of payload, and if your GPU requires 64k alignment internally, that means your GPU memory usage is 15/16ths = ~94% wasted space. This is one of the bigger reasons why atlasing and related techniques are so important for pixel art, font rendering and other cases where you have many small images. It's worth noting that texture arrays do not necessarily make this any better. It depends on the GPU, but if you have something like an array of 32x32 images, it's totally possible (and not even uncommon) for the GPU to internally require memory for 64x64 pixels or more per array element. Basically, current GPUs are not built for really small texture sizes, and if that's most of what you use, you need to keep an eye on how much memory that ends up consuming because it can be surprisingly horrible.
  • @dstry_Flightman
    I have no idea what you're talking about but this is very well made.
  • @aarthificial
    Fascinating topic! I've only ever heard about these techniques in the context of raytracing but using them for a voxel engine makes so much sense. (Btw, love the visualizations in your video)
  • @Aurailus
    Corrections and Notes (thanks for putting up with me ♥) - People have informed me that "we're back to ground zero" is a malaphor, and the actual phrase is "we're back to square one". I looked this up and it's actually a pretty widespread phenomena. Is this a mistake, or just language becoming weirder and weirder as we all stumble deeper into insanity? I'll let you decide... - I swapped really abruptly between talking about video memory and bind slots, which might be confusing to some people. Bind slots are not related to video memory, they are effectively a place that you input a texture that already exists in memory to be used for rendering. These slots only really exist in software, limitations are imposed on them by the graphics APIs, not the physical hardware of the card. Video memory, on the other hand, is the stuff that actually stores the texture, which is physically limited by the design of the card. - Some people wished I was more clear that these tips were directed at OpenGL specifically. That's very fair! I have a habit of forgetting how different other graphics APIs are. Vulkan doesn't have the same issues with Bind Slots that OpenGL has, and thus does not need Bindless or Array textures. However, it does, from my understanding, have an understanding of Sparse Textures. It also can benefit from Texture Compression & Vertex Optimization, although the texture compression algorithms might differ, I'm not too sure. As for DirectX, I do not care. Windows specific graphics API bad
  • @meerkat22
    I've worked with all of this techniques. I didn't expect so much insight from the video. Information about this topics usually is kind of dull and limited. However, the explanations are just brilliant, great job.
  • @najunix
    I always love to see how magnificent works of art work under the hood, even though I have barely a grip on the exact science. This video made me connect a lot of computer science dots, especially in graphics processing! Thank you so much for this!
  • @duxtorm
    You deserve way more recognition! That engine you're working on is gorgeous! And this video was very informative, in fact, I've even saved it as a resource for my game-making journey
  • @drgabi18
    6:38 "It turns out that over the last several decades of computer gaming, GPUs have changed a lot. GPUs used to need explicitly bound textures to know what to draw, but that's just not a limitation anymore." This is the knowledge I went with into this video, only knowing just random limited stuff from Acerole and other ppl. I genuinely heard every concept for this video for the first time FROM here. If your ideal viewer who needed techniques was me, this 100% would have helped since it's not regurgitating the many other videos repeating the same stuff. Do what you want with this feedback! Also I'm surprised you didn't just use Renderdoc or that N-Sight to just see what that game dose.
  • @ross_codes
    I liked this video! Good presentation, very easy to understand. It may be worth emphasising the "OpenGLness" of both the problem and solution with regards to binding large numbers of textures. Most AAA games use DX12 or Vulkan which handle all the texture book keeping with descriptor sets (kinda already bindless). You might enjoy Faith Ekstrand's "descriptors are hard" blog post - she's a Linux Vulkan driver developer.
  • @omerfurtun4115
    In the very recently released Unreal Engine 5.4, there's an improvement referred to as "RHI - Bindless Rendering (Experimental)" which is essentially what this video talks about, which is something I didn't know about. I'm not sure if it's the algorithm being spot on or just sheer luck but I was shown this video just today. Subbed!
  • @Clawthorne
    It makes me happy more informational and educational videos on graphics rendering have started popping up since the whole Unity implosion. Your videos are good. Especially enjoyed the animations. They were fun and underlined your points really well. Keep it up!
  • @josephpolon6837
    I cannot believe I stumbled upon a gem of a creator like you at the beginning of you channel. Keep up the good work, you WILL SUCCEED! You are a inspiration congratulations ahead of time.
  • @jordicoma
    Very interesting video. I remember when id first implemented (on software) virtual textures on rage, and then some years ago I read about when they added bindless textures to OpenGL, but never I listened to a simple description why it's so important to have the bindless textures. I thought that was only for performance. Great video.
  • @toffeethedev
    i love your video editing style so much its so fun!!! very cool visualisations, ive done engine graphics programming but i had no idea about some of these features, thanks so much!! 💞
  • @GaleLD
    I love this! Helped me understand why I should use integers whenever possible, rather than floats. I hope to see more of you ❤
  • @WebbstreMain
    This is so useful! I don't know why YouTube decided to grace me by suggesting this video, but you just gained yourself subscriber 144!
  • @hazard-funk
    I am currently just getting started on graphics programming and learning basic stuff on OpenGL. Seeing this video literally made my head spin, but neatly put together tho. And your voxel engine looks cute!
  • Im so happy to have found this channel, when I was younger and tried to delve deeper in this kind of topic, it was really hard to find information that was begginer friendly. Now this niche part of youtube is more active and growing a lot. I hope to be contributing soon too. Good work!
  • @ZalvaTionZ
    Great video! I have no practical use for this knowledge currently, but it's presentation is great! Wish there was more content like this every time I want to dive into some specific techniques.