"Drivers" for things in the kernel space in this case, are mostly just a glorified shim that allow you to submit command buffers to a device through memory-mapped I/O.
The actual meat of the "driver" in these case is in Mesa, a userspace component, which is what actually forms and creates the command buffers to send.
You can write a driver to interact with hardware in any language assuming you don't have insane timing requirements. It's mostly a matter of engineering deciding where the pieces should go, though. (For example, everything else aside, a major advantage of this kind of design is that all the real complexity exists in userspace.)
The actual meat of the "driver" in these case is in Mesa, a userspace component, which is what actually forms and creates the command buffers to send.
You can write a driver to interact with hardware in any language assuming you don't have insane timing requirements. It's mostly a matter of engineering deciding where the pieces should go, though. (For example, everything else aside, a major advantage of this kind of design is that all the real complexity exists in userspace.)