Hey everyone!
I’ve just released a free open-source native plugin that adds bindless textures to Unity on Vulkan - something the engine doesn’t expose in any form.
What is bindless, in plain words?
Normally, before every draw call the CPU has to tell the GPU exactly which textures that draw is allowed to use: “slot 0 is the albedo, slot 1 is the normal map”. Textures are part of the draw’s state - so every object with a different material needs its own draw call, and the CPU pays for every rebind. Half of what batching systems do is fighting exactly this.
Bindless flips it. All your textures live in one big table on the GPU, bound once. A shader picks any texture at runtime by a simple integer index:
half4 albedo = BINDLESS_SAMPLE(material.albedoSlot, uv);
The texture stops being state and becomes plain data - a number you can store in buffers, pass around, and change per instance.
What can you actually do with it?
- Render thousands of objects with different materials in a single draw call. The GPU reads each object’s texture indices from a buffer and samples the right textures itself. This is the missing companion to indirect rendering - it pairs perfectly with my Multi-Draw Indirect plugin.
- Forget atlases and Texture2DArray restrictions. Any mix of resolutions, formats and compression in one table - and every texture keeps its own sampler (filter/wrap/aniso from its import settings).
- Texture streaming becomes trivial. Registering and unregistering is a cheap descriptor write at runtime - load what the camera needs, evict what it doesn’t. No atlas repacking, no material changes.
- GPU-driven material systems. Materials become plain structs in a
StructuredBufferwith texture indices inside.
Integration is two lines
uint slot = VulkanBindless.Register(texture); // C#: texture goes into the global heap
half4 color = BINDLESS_SAMPLE(slot, uv); // shader: sample it by index
Texture lifetime is handled for you - editor re-imports are picked up automatically, destroyed textures free their slots, and a stale slot samples white instead of crashing. A runnable sample (a cube grid drawn with one RenderMeshIndirect call, every cube with its own texture) ships with the package.
Requirements
- Unity 6000.0+, Vulkan graphics API
- A GPU with descriptor indexing: effectively any desktop GPU from the last decade; on Android - Adreno, or Mali from Valhall on
- Windows and Android binaries included (Linux planned)
Disclaimer
The plugin integrates seamlessly - no engine modifications, your project code only sees a tiny C# API and one shader include. But under the hood it works at a very deep level (it intercepts Unity’s Vulkan device creation and patches pipeline layouts and shader modules on the fly). It’s freshly released and validated on a limited set of hardware so far.
Please don’t ship it in production just yet. Try it in experiments and prototypes, and if something breaks - the plugin has a built-in diagnostics panel and captures its native log, so please open an issue on GitHub with that output. Reports from different GPUs/drivers are the most valuable thing right now.
Feedback, questions and contributions are very welcome!