Quantcast
Channel: Анал со зрелой
Viewing all articles
Browse latest Browse all 47

A Primer on sokol_gfx.h

$
0
0

sokol_gfx.h by Andre Weissflog is the best 3D API wrapper I’ve ever seen. It’s just the bare minimum common-slice between all the modern rendering APIs on today’s platforms, nothing more, with a very well designed set of structs and functions.

The purpose of sokol_gfx is very straightforward, as it only does a few things.

  • Vertex and index buffers
  • Textures or render targets
  • Upload shaders to the GPU
  • Set shader uniforms

However, sokol_gfx has a great way to organize these pieces with a couple of abstractions, called passes and pipelines. Here’s what a typical rendering loop looks like.

begin pass
	apply pipeline
		apply bindings
		apply uniforms
		draw
end pass

Let us go over each piece. Be sure to have open sokol_gfx.h in a web browser or text editor to search for things! The docs are really quite good, so don’t be shy about it. The key observation is each indentation in the above example represents a different frequency. Generally there are multiple passes (though a single pass is also just fine), multiple pipelines can be used within each pass, and multiple bindings/uniforms can be setup within a single pipeline.

Draw, Uniforms, Bindings

This step is done by the function sg_draw (this is a great time to search up the docs for sg_draw, but I’ll paste them here this time).

sg_draw

This function maps to a single draw call. There isn’t much more to be said here. Once a shader (sg_shader) is set, vertex/index buffers are bound, textures are setup, uniforms uploaded to the GPU (sg_apply_uniforms), and anything else, then drawing can happen.

The bindings (sg_bindings) simply store a reference to textures (sg_image_desc), vertex buffers (sg_buffer), and index buffers (sg_buffer).

Pipeline

The pipeline (sg_pipeline_desc) references a shader and also stores a bunch of other state for stencil settings, blend settings, rasterizer settings (e.g. cull mode, winding order), and describes vertex/index buffer layout. All this info describes how to use a shader in relation to buffers that are inputs to the vertex shader.

Now is a great time to talk about how sokol_gfx.h handles initialization of structures. Here’s an example of a pipeline I setup to draw an offscreen buffer onto the screen.

pipeline

The params structure holds all the values necessary to build an actual pipeline. There exists a desc struct for each kind of object sokol_gfx exposes in its API. The intent is to zero initialize every single desc struct before using them. sokol_gfx has a very clever method for default initialization of all the various desc parameter structs. Since there are quite a lot of different settings in, for example, the sg_pipeline_desc struct, the majority of which aren’t going to be used every time, it’s great to default initialize the majority of them and not worry about what they’re set to.

By initializing sokol_gfx structs to 0, every single member of the struct with a zero value is then assigned, internally, upon building an object, to an actual and useful non-zero value. All of this is completely hidden behind the sokol_gfx API, so we only need to minimal code settings fields we care about.

Let us check out the docs for pipelines.

sg_defaults

I’ve circled the area where the defaults are shown. Looking up the defaults is the most important part about using sokol_gfx. Anything zeroed out in a struct will be internally set to these default values.

Using sokol_gfx is merely a matter of looking up in the docs what the defaults are, and changing them as necessary upon initialization.

Pass

Passes reference a place to draw, be it the screen or an off-screen texture. A pass has an action. The actions are to clear, load the previously rendered data, or “don’t care” which I’ve never used.

Limitations

The great thing about sokol_gfx is that it has a clearly defined scope. It’s just used to access 3D hardware rendering APIs on different platforms. It doesn’t do shader cross-compiling, which is good! That would be *really* complicated for a single library to tackle all on its own. It also doesn’t create device contexts for you, which is also great! By keeping the scope down sokol_gfx has an extremely small and well-defined API.

sokol_gfx grants access to low-level rendering tools, does it really well, and doesn’t bother you with anything extra. And the docs are very well written. The documentation is what really makes the library so easy to use!

To me this library is a breath of fresh air. Forgive me for being all philosophical or curmudgeonly, but in my opinion modern rendering APIs are all completely over-engineered in a sort of vortex of passion. I’m not really a graphics enthusiast, so practicality is king for me, and in that regard a small library written with a single vision and strict scope control yields the best tools.

Live Examples

If you’d like to see a full working end-to-end piece along with the source code, check out this link. There’s a whole bunch of samples available.

TwitterRedditFacebookShare


Viewing all articles
Browse latest Browse all 47

Latest Images

Trending Articles



Latest Images