Monday, March 15, 2010

Stingray : the new engine

Stingray is organised into a Channel strips. Each has a list of RenderChannels, and each of these have a list of DrawCommands.

The strips and channels are created and arranged in an order specified by the game programmer. This design means that a Stingray game is not bound to forward-rendering, or deferred-rendering, single or multi-pass materials etc. It is completely flexible from this standpoint.

Channel Strips are purely for convenience, they are repeatable blocks of Render Channels, for example implementing shadow-mapped light requires light-map-write and light-map-read channels. These two make up a LightMapChannelStrip; each light-mapped light thus creates its own LightMapChannelStrip.

The fundamental drawing unit in Stingray, the DrawCommand, exists so that all draw commands can be sorted with respect to one another. This allows each render channel to sort its draw commands to draw in the most optimal order. For example the depth-pass channel requires little state changing, and so sorts its draw commands front-to-back to take advantage of the GPU's z-occlusion culling. The Texturing render channel on the other hand utilises heavy state-setting, and thus sorts its render commands via state blocks. DrawCommands are highly frame coherent, and this fact is taken advantage of - draw commands are not issued to channels per-frame at runtime, instead draw commands are owned by objects and meshes, and meshes are bound() and unbound() infrequently to channel strips.

Mesh files contain a list of MeshPieces - parts of a mesh that have the same material.

Material files contain a list of RenderChannels that draw a mesh piece, for example texture, light, then post-process. For each render channel, XML invokes class factories to create DrawCommands. This means a material may contain passes that are not used by a particular game; if a game only implements some render channels, then parts of the material simply won't be bound at runtime. Thus we have a dynamically-bound multi-pass material system.

When a mesh is bound(), all its mesh pieces use their materials to register draw commands to the appropriate render channels. In some instances, a draw command will be bound to multiple channels - for example, there may be two cameras with complete render channel strips, or five lighting channel strips. Cameras and Lights are therefore treated exactly the same, they are simply render channel strips.

All resources are referenced by integer IDs and stored in Managers, thus any resource can be reloaded at runtime, and the instance memory is kept to a minimum.

Stingray uses Boost::Python to expose nearly all of the engine to Python. There is no inherent render pipeline, this is created by the game python scripts.

There is no multi-threading in this engine, however it is designed for it. Draw Commands are independent objects, thus getting the draw commands ready on render channels can be done in any order, before the final rendering stage goes through a sorted list of draw commands and submits them to DirectX. So each render channel can cull and sort draw commands in parallel, only the final submission must be done in order. And before this is done, it is possible to double buffer the draw command lists such that the next frame can be made ready while draw command submission is taking place.

No comments:

Post a Comment