uniform Node* u_nodes;
void main(){
Node node = u_nodes[gl_DrawID];
vec3 pos = node.position[gl_VertexID];
vec2 uv = node.uv[gl_VertexID];
...
}
I just wish there was more literature about this, especially about perf implications. Also synchronization is very painful, which may be why this is hard to do on a driver level inside OpenGL
But I haven’t written OpenGL since Metal debuted over a decade ago.
If you are using Slang, then you just access everything as standard pointers to chunks of GPU memory.
And it's mostly Intel and mobile dragging their feet on VK_EXT_descriptor_buffer ...
If you want that extension you're going to have better luck convincing the Zink folks:
https://docs.mesa3d.org/drivers/zink.html "The Zink driver is a Gallium driver that emits Vulkan API calls instead of targeting a specific GPU architecture. This can be used to get full desktop OpenGL support on devices that only support Vulkan."
However, you're still probably going to have to come off of GLSL and use Slang or HLSL. The features you want are simply not going to get developed in the GLSL compiler at this point.
They exist in GLSL on Nvidia devices. If other vendors refuse to implement them, then I will be an Nvidia-only developer. Fine by me. I no longer care about other vendors if they completely ignore massive quality of life features.
(3) "Do we allow arrays of shader storage blocks?
RESOLVED: Yes; we already allow arrays of uniform blocks, where each
block instance has an identical layout but is backed by a separate
buffer object. It seems like we should do this here for consistency.
PS: You could also access data through bindless textures, though you would need to deal with ugly wrappers to unpack structs from image formats.Regarding bindless textures, they're really ugly to use. Shader buffer load is so much better, being able to access everything with simple pointers.
I wanted to say that with some compiler hacking it should be possible to lower SPIR-V using GL_EXT_buffer_reference into bindless image loads, but SPIR-V doesn't have standardized bindless texture, duh!
Also I wish that GL_LINES was open-sourced for other platforms. Maybe it is in the OpenGL spec and I just haven't looked. I've attempted some other techniques like having the fragment shader draw a border around each triangle, but they all have their drawbacks.
This works for most other regular shapes too, like a relatively tight bounding box for circles if you're drawing a bunch of them.
Draw in screen space based on projected points in world space.
set gl_Color to your desired color vec and bam, line.
As far as other platforms, there's VK_EXT_line_rasterization which is a port of opengl line drawing functionality to vulkan.
https://github.com/mattdesl/webgl-lines
https://hundredrabbits.itch.io/verreciel
PS— I still play Retro, and dream of resuscitating it :)
nvidium is using GL_NV_mesh_shader which is only available for nVIDIA cards. This mod is the only game/mod I know of that uses mesh shaders & is OpenGL. & so the new gl extension will let users of other vendors use the mod if it gets updated to use the new extension.
What is the current state of OpenGL, I thought it had faded away?
Can you provide a reference for this? I work in the GPU driver space (not on either of these apis), but from my understanding Vulkan wasn't meant to replace OpenGL, it was only introduced to give developers the chance at getting lower level in the hardware (still agnostic from the hardware, at least compared to compiling PTX/CUDA or against AMD's PAL directly, many still think they failed.) I would still highly advocate for developers using OpenGL or dx11 if their game/software doesn't need the capabilities of Vulkan or dx12. And even if you did, you might be able to get away with interop and do small parts with the lower api and leave everything else in the higher api.
I will admit I don't like the trend of all the fancy new features only getting introduced into Vulkan and dx12, but I'm not sure how to change that trend.
Those are the main reasons IMO why most people say it's deprecated.
Closer to the hardware, more control, fewer workarounds because the driver is doing something "clever" hidden behind the scenes. The tradeoff is greater complexity.
Mere mortals are supposed to use a game engine, or a scene graph library (e.g. VulkanSceneGraph), or stick with OpenGL for now.
The long-term future for OpenGL is to be implemented on top of Vulkan (specifically the Mesa Zink driver that the blog post author is the main developer of).
To what hardware? Ancient desktop GPUs vs modern desktop GPUs? Ancient smartphones? Modern smartphones? Consoles? Vulkan is an abstraction of a huge set of diverging hardware architectures.
And a pretty bad one, on my opinion. If you need to make an abstraction due to fundamentally different hardware, then at least make an abstraction that isn't terribly overengineered for little to no gain.
Hence why on Android, even with Google nowadays enforcing Vulkan, if you want to deal with a less painful experience in driver bugs, better stick with OpenGL ES, outside Pixel and Samsung phones.
I fully expect it to be split into Vulkan ES sooner or later.
I would be very surprised if current Vulkan drivers are any different in this regard, and if yes then probably only because Vulkan isn't as popular as D3D for PC games.
Vulkan is in a weird place that it promised a low-level explicit API close to the hardware, but then still doesn't really match any concrete GPU architecture and it still needs to abstract over very different GPU architectures.
At the very least there should have been different APIs for desktop and mobile GPUs (not that the GL vs GLES split was great, but at least that way the requirements for mobile GPUs don't hold back the desktop API).
And then there's the issue that also ruined OpenGL: the vendor extension mess.
The last OpenGL release 4.6 was in 2017... I think that speaks for itself ;)
And at least on macOS, OpenGL is officially deprecated, stuck at 4.1 and is also quickly rotting (despite running on top of Metal now - but I don't think anybody at Apple is doing serious maintenance work on their OpenGL implementation).
Look at Mesa release notes for example, there's a steady stream of driver feature work and bugfixes for GL: https://docs.mesa3d.org/relnotes/25.2.0.html (search for "gl_")
A slow moving graphics API is a good thing for many uses.
People are writing new OpenGL code all the time. See eg HN story sumbmissions: https://hn.algolia.com/?dateRange=all&page=0&prefix=false&qu...
It's not slow moving. It's completely frozen. The Mesa guys are the only ones actually fixing bugs and improving implementations, but the spec is completely frozen and unmaintained. Apple, Microsoft and Google don't really care if OpenGL works well on their platforms.
but, literally this article is about something new that was added to the OpenGL spec
I suppose the same is true of Direct3D 11, though. Only the Direct3D 12 spec has been updated in years from what I can tell. (I'm not a graphics programmer.)
In other words nothing changed. The OpengGL standard had been well past 4.1 for years when Apple released Metal. People working with various 3D tools had to disable system integrity checks to install working drivers from NVIDIA to replace whatever Apple shipped by default.
As a sidenote, I've very much enjoyed your blog, and developed a similar handle system as yours around the same time. Mine uses 32 bits though - 15 for index, 1 for misc stuff, 8 for random key, and 8 for object type :^)
From macOS 10.7 to 10.9, you'd get an OpenGL 3.2 context. As OpenGL 4.1 is backward compatible to OpenGL 3.2, it's fine that the same code gets OpenGL 4.1 now.
Basically, macOS will provide an "old" API to programs that need it, which is fixed at 2.1, and a "modern" API to programs that know how to ask for it, which has settled at 4.1 and is unlikely to change.
OpenGL 4.1 is harmonised with OpenGL ES 2.0. Almost the same rendering model, features, extensions, etc. On iOS, iPadOS etc you can use OpenGL ES 2.0, and no version of OpenGL (non-ES), so my guess is that's why macOS settled on OpenGL 4.1. Both platforms offer the same OpenGL rendering features, but through slightly different APIs.
But if you request 4.1 over GLX (which uses X11/Xorg/XQuartz), the X11 code only supports OpenGL 2.1. For example, if you're porting some Linux code or other GLX examples over.
Unfortunately, the GLX limitation is probably just due to the Xorg-based XQuartz being open source but only minimally maintained since before OpenGL 3.2 was added to macOS. XQuartz uses Xorg and Mesa, which have all the bindings for 4.1, but some of them are not quite wired up.
It's the only way to ship portable 3D software across the desktop and mobile platforms without platform specific code paths, thanks to the API fragmentation and proprietary platform antics from our beloved vendors.
In some years WebGPU may mature and start gaining parity (webgl took a looooong time to mature), and after that it'll still take more years for applications to switch given older hardware, the software inertia needed to port all the middleware over etc.
In any case it’s not true anyway. WebGPU also does away with the global state driver, which has always been a productivity headache/source of bugs within OpenGL, and gives better abstractions with pipelines and command buffers.
Also, compute could have easily been added to WebGL, making WebGL pretty much on-par with WebGPU, just 7 years earlier. It didn't happen because WebGPU was supposed to be a better replacement, which it never became. It just became something different-but-not-better.
If you'd have to do even half of all the completely unnecessary stuff that Vulkan forces you to do in CUDA, CUDA would have never become as popular as it is.
They are the only set of 3D APIs that have been adopted in the mainstream computing, designed for managed languages, instead of year another thing to be consumed by C.
Technically Metal is also used by a managed language, but it was designed for Objective-C/C++ first, with Swift as official binding.
Microsoft gave up on Managed Direct X and XNA, and even with all the safety talks, Direct X team doesn't care to provide official COM bindings to C#.
Thus that leaves us WebGL and WebGPU for managed languages fans, which even if lagging behind, as PlayCanvas and ShaderToy show, there are enough capabilities on the shader languages that have not yet taken off.
Metal allows to disable refcounted lifetime management when recording commands since it actually adds significant overhead and D3D12 and Vulkan removed it entirely.
Unfortunately WebGPU potentially produces even more garbage than WebGL2, and we'll have yet to see how this turns out. Some drawcall heavy code actually runs faster on WebGL2 than WebGPU which really doesn't look great for a modern 3D API (not mainly because of GC but every little bit of overhead counts).
So we end up in an internal cycle that we cannot get rid of.
Metal and Web 3D APIs add other consumer languages in mind, you also see this in how ANARI is being designed.
Yes every little bit of performance counts, but it cannot be that APIs get designed as if everyone is still coding in Assembly, and then it is up to whoever cares to actually build proper high level abstractions on top, that is how we end up with Vulkan.
Why not though? In the end an API call is an API call, and everything is compiled down to machine code no matter what the source language is.
FWIW, the high-level "OOP-isms" of the Metal API is also its biggest downside. Even simple create-option "structs" like MTLRenderPassDescriptor are fully lifetime-managed Objective-C objects where every field access is a method call - that's simply unnecessary overkill.
And ironically, the most binding-friendly API for high-level languages might still be OpenGL, since this doesn't have any structs or 'objects with methods', but only plain old function calls with primitive-type parameters and the only usage of pointers is for pointing to unstructured 'bulk data' like vertex-buffer- or texture-content, this maps very well even to entirely un-C-like languages - and the changes that WebGL did to the GL API (for instance adding 'proper' JS objects for textures and buffers) are arguably a step back compared to native GL where those resource objects are just opaque handles.
The ANARI effort was born exactly because the visualisation industry refusal to adopt Vulkan as is.
If anything it looks more like an admission by Khronos that Vulkan wasn't such a great idea (but a 3D API that's based on scene graphs isn't either, so I'm not sure what's so great about ANARI tbh).
https://github.com/KhronosGroup/ANARI-SDK/tree/next_release/...
It pretty much is by now if you can use Vulkan 1.4 (or even 1.3). It's a pretty lean and mean API once you've got it bootstrapped.
There's still a lot of setup code to get off the ground (device enumeration, extensions and features, swapchain setup, pipeline layouts), but beyond that Vulkan is much nicer to work with than OpenGL. Just gotta get past the initial hurdle.
Just directly talking to the C API in the tutorials/examples instead of custom wrapper code would be a lot more helpful since you'd don't need to sift through the custom abstraction layers (even if it would be slightly more code).
E.g. have a look at the code snippets in here and weep in despair ;)
https://docs.vulkan.org/tutorial/latest/03_Drawing_a_triangl...
Trying to obfuscate all the options goes against what Vulkan was created for. Use OpenGL 4.6/WebGPU if you want simplicity.
And the rest of the API is full of similar examples of wasting developer time for the common code path.
Metal is a great example of providing both: a convenient 'beaten path' for 90% of use cases but still offering more verbose fallbacks when flexibility is needed.
Arguably, the original idea to provide a low-level explicit API also didn't quite work. Since GPU architectures are still vastly different (especially across desktop and mobile GPUs), a slightly more abstract API would be able to provide more wiggle room for drivers to implement an API feature more efficiently under the hood, and without requiring users to write different code paths for each GPU vendor.
Also, CUDA is targeting a single vendor, whereas Vulkan is targeting as many platforms as possible.
Vulkan is also trying to expose as many options as possible so as to be extensible on as many platforms as possible. Also, Vulkan isn't even trying to make it more complex than it need be--this is just how complex graphics programming is period. The only reasons people think Vulkan/DX12 are overly complicated is because they're used to using APIs where the majority of the heavy lifting comes from the drivers.
Actually, it would be kinda neat to see an API that's fully designed assuming a coherent, cached, shared memory space between device and host. Metal I guess is closest.
Desktop GPUs. Tiling GPUs are still in use on mobile and you can't use the tiling hardware effectively without baking the description into pipelines.
> You could cut things down a ton with a new API.
VK_KHR_dynamic_rendering is what you are looking for
> Actually, it would be kinda neat to see an API that's fully designed assuming a coherent, cached, shared memory space between device and host.
You can just ask for exactly that--even on Vulkan. If you don't want to support computer systems that don't support RBAR, you can do that.
Have you used Vulkan? Specifying required hardware support for your physical device is literally one of the first thing you do when setting up Vulkan.
Tbf, the distinction between rendering and compute has been disappearing for quite a while now, apart from texture sampling there isn't much reason to have hardware that's dedicated for rendering tasks on GPUs, and when there's hardly any dedicated rendering hardware on GPUs, why still have dedicated rendering APIs?
Note that it's not always better. The task shaders are quite hardware specific and it makes sense to ship defaults inside the driver.
More traditional rendering APIs can then be build on top of such a "compute-first-API", but that shouldn't be the job Khronos.
I believe the llama.cpp Vulkan backend is inoperable on Adreno GPUs
The worst thing about OpenGL is probably the hilariously non-typesafe C API.
AFAIK mesh shaders also get rid of (the ever troublesome) geometry shaders and hull shaders, but don't quote me on that :)
By far most traditional triangle rendering use cases should only see minimal performance improvements though, it's very much the definition of 'diminishing returns'.
It's definitely more straightforward and 'elegant' though.
PS: this is a pretty good introduction I think https://gpuopen.com/learn/mesh_shaders/mesh_shaders-from_ver...
Imagine you hired a robot artist to draw.
Before Shaders (The Old Way): The robot had a fixed set of instructions. You could only tell it "draw a red circle here" or "draw a blue square there." You could change the colors and basic shapes, but you couldn't change how it drew them. This was called the fixed-function pipeline.
After Shaders (The New Way): You can now give the robot custom, programmable instructions, or shaders. You can write little programs that tell it exactly how to draw things.
The Two Original Shaders This programmability was primarily split into two types of shaders:
Vertex Shader: This program runs for every single point (vertex) of a 3D model. Its job is to figure out where that point should be positioned on your 2D screen. You could now program custom effects like making a character model jiggle or a flag wave in the wind.
Fragment (or Pixel) Shader: After the shape is positioned, this program runs for every single pixel inside that shape. Its job is to decide the final color of that pixel. This is where you program complex lighting, shadows, reflections, and surface textures like wood grain or rust.
For example, hair meshes (lots of small strands) are usually generated on the CPU from some basic parameters (basic hairstyle shape, hair color, strand density, curliness, fuzziness etc) and then the generated mesh (which could be quite large) is loaded onto the GPU. But the GPU could do that itself using mesh shaders, saving a lot of memory bandwidth. Here is a paper about this idea: https://www.cemyuksel.com/research/hairmesh_rendering/Real-T...
However, the main application of mesh shaders currently is more restricted: Meshes are chunked into patches (meshlets), which allows for more fine grained occlusion culling of occluded geometry.
Though most these things, I believe, can already be done with compute shaders, although perhaps not as elegantly, or with some overhead.
In this regard, 3d scenes offer the elements but shaders can design them much more efficient than a engine ever could.
Is that accurate?
Btw, can objects modified by shaders signal collisions?
3D APIs are more on the level of 'draw this list of triangles, and the color of a specific pixel in the triangle is computed like this: (hundreds of lines of pixel shader code)" - but even this is slowly being being replaced by even lower level code which implements completely custom rendering pipelines entirely on the GPU.
Collisions aren't part of a graphics API.
You can do occlusion queries though, which is a form of 2D collision detection similar to what home computer sprite hardware provided ;)
- https://alteredqualia.com/css-shaders/article/
- https://developer.mozilla.org/en-US/docs/Web/API/Houdini_API...
OpenGL was a very nice API and even despite its shortcomings, it is quite telling that VK didn't fully replace it 10 years later.
Cross-vendor mesh shader support is great - we had NV_mesh_shader for quite a while but it's great that it's also supported on AMD now. It's good for voxel games like this - the shape of the vertex data is fairly fixed and very compressible, mesh shaders can really cut down on the VRAM usage and help reduce overhead.
Most minecraft optimisation mods generally try to reduce drawcalls by batching chunks (16x16x16) into bigger regions and use more modern OpenGL to reduce API overhead.
This mod does GPU-driven culling for invisible chunk sections (so the hidden chunks aren't rendered but without a roundtrip to the CPU) and also generates the triangles themselves with a mesh shader from the terrain data, which cuts down on the vertex size a lot. (EDIT: I reworded this section because the mod does only a few drawcalls in total so my wording was inaccurate. Sorry!)
Sadly, optimising the game is a bit tricky due to several reasons - the first big one is translucency sorting, because there are translucent blocks in the game like stained glass, which have to be properly sorted for the blending to work. (the base game doesn't sort correctly either by default....)
The second is that it's quite overengineered, so improving it while also not breaking other mods and accidentally fixing vanilla bugs is quite hard.
There are further improvements possible but honestly, this is day and night compared to the vanilla renderer :)
For us mere mortals (not working at Unity or Unreal), the complexity is just too much. Vulkan tries to abstract desktop and mobile together, but if you're making an indie game, there's no value for you in that. The GL/GLES split was better because each could evolve to its strengths instead of being chained to a fundamentally different design.
The global state in OpenGL is certainly an annoyance, but I do not think that replacing it with fixed pipelines is an improvement, especially considering that most of that state is just a register write in desktop GPUs. Luckily, they eased up on that, but the API is still confusing, the defaults are not sane, and you need vendor-specific advice to know what's usable and what isn't. Ironically, writing Vulkan makes you more vendor-dependent in a sense, because you don't have OpenGL extension hell - you have Vulkan extension hell AND a bunch of incidental complexity around the used formats and layouts and whatnot.
On a more positive note, I seriously hope that OpenGL won't be entirely abandoned in the future, it has been a great API so far and it only really has small issues and driver problems but nothing really unfixable.
I think this is an extremely subjective take :) If you haven't been closely following OpenGL development since the late 1990s it is a very confusing API, since it simply stacks new concepts on top of old concepts all the way back to GL 2.0. E.g. if anything good can be said about Vulkan it's that at least it isn't such a hot mess of an API (yet) like OpenGL has become in the last 25 years ;)
Just look at glVertexAttribPointer()... it's an absolute mess of hidden footguns. A call to glVertexAttribPointer() 'captures' the current global vertex buffer binding for that attribute (very common source of bugs when working with vertex-input from different buffers), and the 'pointer' argument isn't a pointer at all, but a byte-offset into a vertex buffer. The entire API is full of such weird "sediment layers", and yes there are more recent vertex specification functions which are cleaner, but the old functions are still part of the new GL versions and just contribute to the confusion for new people trying to understand the API.
Okay fair but that's all takes on this site :)
Yes, vertexAttribPointer is a footgun (in my project I wrote an analyser to generate a compiler error when you write it down...) but luckily in modern OpenGL it doesn't matter because you have separated vertex format. The names are confusing because it's legacy shit but the functionality is there. It's very much not as clean as other APIs but it gets the job done.
If you stick to the modern versions (so bindVertexBuffer / vertexAttribFormat / VertexAttribBinding) and do one VAO per vertex format, it's quite nice. And just forbid using the old ones. ;)
More broadly, I admit it's a subjective thing but I find these issues much smaller than like, broader conceptual issues. You mix the function names up a few times then you learn not to do it. But when an API is just fundamentally unergonomic and inflexible, you can't really get past that. Maybe you get used to it after a while but the pain will always be there....
And why for ES? I thought ES was for less advanced hardware.
https://wikis.khronos.org/opengl/OpenGL_Extension#Extension_...