How do graphic engine developers debug their 3D graphics code? I'm currently trying to create an amateur game engine, and I often run into very basic bugs (eg I change the node hierarchy code and suddenly nothing is displayed). Some of the methods I will use include to track down these bugs include:


Use my IDE's debugger and lots of printf calls to look at what's in memory.
Make lots of tests with different parameters, placing the camera in different positions, to get a better feel of what the code is doing.
Just brute force my way through by re-reading each line of code until I find the one that's misbehaving.


These methods all seem sluggish and inefficient to me. The problem is, that 3D rendering involves a lot of unintuitive operations with not much to visualize except the final "product"; when I'm running into a bug (especially "nothing is displayed" types of bugs), I often feel like I'm fumbling around blindly.



So.

Let's say you're a developer working on Unity, Godot, or some other 3D engine, and you just changed some steps in your rendering pipeline, and now, for whatever reason, the wireframe renderer displays incoherent results when entity batching is activated. The "wires" are crisscrossing all over the screen instead of representing the edges of the batched entity's triangles.

How do you track down and fix that bug? Do you have a specific workflow? Do you use some kind of GPU analysis tool? Or do you just fumble around blindly?

In other words, what methods, tools and best practices can engine developers (not engine users) use to analyze the data and behavior of their 3D graphics code (not just its performance) to efficiently address defects and bugs?
I'm programming mostly in OpenGL. In this case, the very first thing I do is setting up KHR_debug extension. It provides a way to subscribe to messages generated by GL drivers - from errors to warnings to detailed information about what the driver is doing. Especially open source Linux drivers (Mesa) generate lots of useful messages.

When it comes to tools, my first choice is usually ApiTrace. It allows you record a trace of all rendering API calls and then replay it and inspect state at any point in time (this includes contents of buffers, render targets, etc.). It also allows you to share a trace with other people, which is useful when working in a team. Then, there are other tools such as RenderDoc, NVIDIA Tegra Graphics Debugger, Xcode's graphics debugger and some others. Whichever you chose, it will improve your work a lot.

Another thing is testing. One thing is building a collection of simple scenes excercising single feature of the engine (such as different material settings, different animation techniques, etc.).
When a bug is introduced into the codebase, this helps debugging it (since you have simple to analyse test cases readily available) and verifying that a fix doesn't accidentally break something else. I guess it's quite common thing to do; Unity3D developers do it, for example.

You could extend this and automate it by creating test harness, which would build and run all test on regular basis, and verify that no regressions happened. If you have lots of test scenarios, this might be feasible, although obviously requires additional investments into infrastructure. 

Then there are more "standard" unit tests. One area I've applied them is node-based material system, which can target different rendering techniques (forward, deferred, whatever) and APIs. I approached it by writing unit tests which generate shader code from material and other settings, compiler it and issues a simple draw calls with given inputs (pixel shader inputs). Outputs are written to a render target and fetched for comparison with expected values. IMHO this is a nice  thing to do when you have complex material system, esp. with shader code generation.

Finally, more "traditional" approaches can be applied to areas which can be separated from rendering. Things like spatial data structures, asset loading and similar can be unit/integration tested, as applicable in specific case.

Edit: Here's a post from Unity3D developer describing how they test graphics code.