On older fixed function hardware the fixed function pipeline mapped to hardware pretty directly. On modern GPUs most of the fixed function pipeline is emulated in drivers and shaders. So if you're doing "proper" low level graphics programming for modern GPUs you are writing shader code. Working with fixed function is writing for a low level abstraction that doesn't represent the way hardware actually works. It's true that using a 3D API at all is an abstraction that hides and simplifies many of the workings of the actual hardware, but modern APIs are much closer to actual hardware than legacy ones.
Could you explain that?