Design help on software rasterizer / renderer

Started by
12 comments, last by Jason Z 10 years, 3 months ago

Firstly, let me say "good luck" - I can say from experience that writing your own software rasterizer is both fun and rewarding.

My own software rasterizer, Rasterizr, is written in C#. The performance is nothing to write home about, but that's partly because I prioritised understandable code over speed. I chose to follow the Direct3D API quite closely, so I have the following stages:

  • Input assembler
  • Vertex shader
  • Geometry shader
  • Rasterizer
  • Pixel shader
  • Output merger

I found that this architecture helped keep the code clean and understandable.

For shaders, I did more or less what cgrant suggested. I implemented an HLSL bytecode parser (called SlimShader: https://github.com/tgjones/slimshader). Then I wrote a virtual machine that can execute HLSL shaders on the CPU. Then I wrote a jitter for the virtual machine, to keep performance within reasonable bounds - it produces C# code for a given shader and compiles it on the fly. The end result is that my software rasterizer uses "real" HLSL shaders. (Originally, I used C# for the shaders, but handling pixel shader gradient calculations, which is required for texture mipmapping, was a problem. Also using HLSL shaders is more fun.)

(It's awesome to see Jason Zink replying in this thread - his book "Practical Rendering and Computation with Direct3D 11" was an invaluable reference for me while I was figuring out how Direct3D 11 works, so that I could borrow some of its API for Rasterizr. Thank you Jason!)

I wrote a visual debugging tool, based on Visual Studio's graphics tools - here's a screenshot. It was helpful just yesterday in tracking down a bug related to geometry shaders and render target arrays!

BclO5KWCAAALRfj.png

If you want to look at my code, you'll find it here: https://github.com/tgjones/rasterizr. I'd be happy to help if you have any questions.

Good luck!

Advertisement


(It's awesome to see Jason Zink replying in this thread - his book "Practical Rendering and Computation with Direct3D 11" was an invaluable reference for me while I was figuring out how Direct3D 11 works, so that I could borrow some of its API for Rasterizr. Thank you Jason!)

I'm happy that it was useful for you! :)

Your debugging tool looks pretty nice - do you have any advice to share about implementing such a system? I have been considering adding a tool like this to Hieroglyph 4, and any advice or lessons learned would be very welcome indeed!

Good question! I'm not actually sure what you mean though - Hieroglyph being a Direct3D-based engine, it can presumably take advantage of PIX / VS2012+'s built-in graphics debugging tools?

The details of Rasterizr's pixel history tool are quite specific to it being a software rasteriser, but anyway, here's roughly how it works:

  • Before rendering a frame, you create a TracefileBuilder object, passing it the Device object. The TracefileBuilder listens for every method call which can change device state. It only needs to listen for "public" method calls, such as Draw, because everything else can be derived from that, including the actual rasterized pixels. At this point, no per-pixel data is recorded, so we don't need to store too much in the logfile for each frame.
  • The logfile can be saved to disk or, as in Rasterizr Studio, can be sent directly to the pixel history tool. Here's an example of a serialized logfile: https://github.com/tgjones/rasterizr/blob/master/src/Rasterizr.Studio/Examples/BasicTriangle.rlog
  • The pixel history tool creates a Replayer object, passing it the coordinates of the pixel we're interested in. The Replayer registers itself as interested in any rasterized output which affects that pixel. Then it steps through each logged method call and calls the appropriate methods on the device, to "replay" the frame.
  • The output of all that is a list of PixelHistoryEvent objects, which are shown in the pixel history UI.
  • Each time you click a different pixel, it will actually re-render the frame, recording only per-pixel events that affect the selected pixel. (The full history of every pixel takes up quite a bit of space - my initial implementation did exactly that, but it was far too inefficient, and it's quick enough to simply re-render the frame.)

The two files that do most of this work in Rasterizr are these:

https://github.com/tgjones/rasterizr/blob/master/src/Rasterizr.Diagnostics.Logging/TracefileBuilder.cs

https://github.com/tgjones/rasterizr/blob/master/src/Rasterizr.Diagnostics.Logging/Replayer.cs

The key idea is to record only the public method calls - including the method name and arguments. During replay, everything else can be derived from that. It's important for IDs of resources created during replay to match what was used during recording - but that will happen simply by executing the method calls that create resources in the right order.

There's actually a big limitation in my current implementation - it only works if everything, including creating the device and setting all device state, happens in one frame. MS's Direct3D debugging tools can obviously handle those things happening in a previous frame - I assume they take a snapshot of the initial device state at the beginning of the frame being recorded.

Anyway, sorry, I don't think I answered your question at all! Maybe you could elaborate a bit on what sort of debugging tool you're thinking about?


Good question! I'm not actually sure what you mean though - Hieroglyph being a Direct3D-based engine, it can presumably take advantage of PIX / VS2012+'s built-in graphics debugging tools?

Indeed I can, assuming that I am running on Windows 8 :) Currently there isn't a usable solution for the Graphics Debugger on Windows 7 with an express edition, which happens to be the SKU that I use at work for a number of projects.

In addition, I also want to be able to experiment with new debugging concepts and ideas. Don't get me wrong, I think the graphics debugger in VS2013 is fantastic and has actually eclipsed the old PIX functionality (plus it is significantly more stable...). However, sometimes there are things that I want to do that just aren't included in the graphics tools yet. I desire the ability to customize how data is collected, analyzed, and most importantly to be able to create new visualizations of the data as well.

Your description is actually quite helpful, and I appreciate you sharing the information. I need to formalize what I really want to be able to do, and then I will take this into consideration when designing how the system might work. Thanks again for sharing!

This topic is closed to new replies.

Advertisement