27 April 2008

Gallium3D: Introduction

At Tungsten Graphics I've been working in Gallium3D — a very promising architecture to develop 3D graphic drivers for multiple operating systems and graphic APIs.

It comes as no surprise that Gallium3D is a large and complex piece of software. So I've decided to write a bit about it in the hope of helping newcomers to get more quickly familiarized with it.

A few adverts: I had little to do with Gallium3D's design — that's the work of much brighter people such as Keith Whitwell and Brian Paul — so a lot of the rationale written here is partly my own speculation; also Gallium3D architecture is still under flux (much less than before, but still), so this refers to its current state.

Architecture

Gallium3D architecture can be described as a set of interfaces and a collection of supporting libraries.

Gallium3D is not a framework. All attempts of using the Hollywood Principle of "Don’t call us, we’ll call you." for 3D driver development imply making assumptions about the hardware behavior which quickly are proven wrong as new hardware generations come along. Instead, by simply providing a set of libraries, Gallium3D's can more easily adapt in this rapidly evolving field. So Gallium3D's principle is indeed "Is up to you to call us, as we won't call you". Is is necessary to have this principle in mind to understand how all Gallium pieces fit together.

Modules

State tracker
Translates the graphics API state (e.g., blend mode, texture sampling mode, etc.), shaders, and graphics primitives into something that the pipe driver below understands.
Pipe driver
Translates the state, shaders, and primitives in something that the hardware understands (e.g., register writes, shader/command buffers, and vertex buffers).
Winsys
Instantiates and binds all pieces above (state tracker and pipe driver) together with the OS, window system, and 2D display driver.
Auxiliary modules
Provide optional auxiliary services such as, software interpretation of shaders for hardware without hardware vertex shader support, state caching, buffer management, etc.
Module dependency table
Graphics APIGraphics HardwareOS
Auxiliary modulesNoNoNo
State TrackerYesNoYes/No(1)
Pipe driverNoYesNo
WinsysYesYesYes

(1) The state tracker depends on the graphics API, so it can be made OS-independent for OS-independent APIs (such as OpenGL), but not for OS-dependent APIs (such as Direct3D)

The higher the module is in the previous table the more it is reused (auxiliary modules,State Tracker). The lower it is, more times it will have to be rewritten (Winsys). Although the dividing line between these modules is blurry, we are always interested in moving functionality upwards as much as possible. This is one of the areas where Gallium3D architecture is under flux: when we support a new graphics hardware, graphics API, or OS and realize that there is some functionality that can be generalized then we move it upwards; if we realize that previously made assumptions no longer hold, then we move that functionality downwards.

Interfaces

State tracker <-> Pipe driver
There is a per-context interface(p_context.h) and a global/per-screen interface(p_screen.h).
State tracker <-> Winsys
p_winsys.h
Pipe driver <-> Winsys
Besides p_winsys.h above, each pipe driver has its own additional winsys interface: sp_winsys.h (pure-software pipe driver), i915_winsys.h (Intel 915/945 pipe driver), etc.

Data flow

The data flow is actually quite simple to understand:

The graphics state and primitives created in the application are successively broken down in things more close to the hardware as they progress in the pipe line. One of Gallium3D's biggest achievement is defining a set of interfaces that allows the central piece -- the pipe driver --, to be reused in different graphics APIs and OSes.

If you zoom up the microscope one level, you can detect two extra (auxiliary) modules:

CSO context
Optionally used by the state tracker for Constant State Object (CSO) caching. The state passed to the pipe driver is immutable (constant) to simplify the pipe driver implementation. To avoid the performance penalty of always destroying/creating these state objects, these are stored in a cache.
Draw module
Optionally used by the pipe driver to do vertex transform, lighting, and primitive clipping in software, for hardware without support for it.

The rest...

That's all for today. Hopefully soon I'll write a bit more about these modules in more detail. I actually started my way in Gallium3D from Winsys and only recently started working on the State tracker, so there is some studying left to do.

Until then, to learn more about Gallium3D see:

11 comments:

Anonymous said...

Very nice overview of Gallium!

But I have some questions about the dependency table.

1) Is there really such a thing as an operating system dependend API? Shouldn't it be possible to offer a Direct3D state tracker for wine?

2) Somehow it looks wrong that winsys depends on the graphic API. Shouldn't the state tracker isolate the lower modules from the API dependencies? (The pipe driver has a 'no' in its column)

And one last question about how this relates to the current linux drivers: Will winsys on linux replace the current drm modules or is this a userspace part?

José Fonseca said...

Torsten,

1) Is there really such a thing as an operating system dependend API? Shouldn't it be possible to offer a Direct3D state tracker for wine?

It might be possible, but in that case you still have the dependency on the OS — you're satisfying that dependency with an OS emulation layer. Microsoft Office, for example, is not cross-platform just because it can run on Wine.

2) Somehow it looks wrong that winsys depends on the graphic API. Shouldn't the state tracker isolate the lower modules from the API dependencies? (The pipe driver has a 'no' in its column)

That would be ideal, but not possible at the moment, for two reasons.

First, in some cases the API/OS doesn't see state tracker or the pipe driver at all — instead they are loaded by the winsys —, so from their point of view from the API/OS point of view, the winsys is the driver. (This is the case for example with linux DRI drivers, the winsys ends up being the /usr/lib/dri/xxx_dri.so and includes the state tracker and the pipe driver inside).

The second reason is that there is no common interface for the state tracker. On Linux you have to play nice with the X DDX driver, on Windows you have to play nice with the Display Driver; both are hardware dependent. So if you don't want to make the state tracker dependent on the hardware, you need to give that responsibility to winsys.

Anyway, this is surely one part where there can be improvements (we are noticing many similarities in the winsys written so far). It is not a performance critical path, and winsys are really small compared with the rest, hence the current state.

And one last question about how this relates to the current linux drivers: Will winsys on linux replace the current drm modules or is this a userspace part?

It is an userspace part. It will talk to the same drm modules as the other drivers so far.

Anonymous said...

Thanks for these additional answers.

1) OS-independend Direct3D API
OK, I understand. I just had a different meaning for dependency / inoperability in mind. I was just looking at isolated the interface part of the API as a "simple" list of calls and arguments. And oversimplified this into the possibility to just compile the windows Direct3D state tracker on linux and replace all the Direct3D-Helper/Translators in wine with a minimal glue layer.

2)API dependence of the winsys module
By placing the winsys layer into the kernel I hand the wrong picture that the module dependencies image did mean a strong hierarchical ordering.
Like replacing the handware dependent r300_dri.so with generic gallium-mesa-state-tracker_dri.so that only internaly loads the concrete pipe and winsys drivers.

But that would assume that you could use the current interface to the *_dri.so as a stable interface for the state tracker, but as you said the additional requirements to "play nice" with DDX makes this impossible.

the winsys ends up being the /usr/lib/dri/xxx_dri.so and includes the state tracker and the pipe driver inside

So the modularity of gallium is more from the source perspective for code reuse than real (semi-)independend loadable modules, with the winsys part being the glue that holds the gallium parts together and defining the external interface for the specific OS.

Should then there be an additional (small?) winsys-box between Graphics API and the State Tracker in the Data flow images?

José Fonseca said...

So the modularity of gallium is more from the source perspective for code reuse than real (semi-)independend loadable modules, with the winsys part being the glue that holds the gallium parts together and defining the external interface for the specific OS.

That's actually a superb way of explaining it. Of course, nobody is saying that deploying to users independent loadable modules is not possible, or even desirable in some platforms, but at this development stage there would be zero benefit.

Should then there be an additional (small?) winsys-box between Graphics API and the State Tracker in the Data flow images?

Although there is communication going on between the Graphics API and the Winsys, it is not the bulk data. It is things: What window is this 3D context associated to? Get me the graphics memory for this surface, or Attach my private data to that structure, and so on.

There could be a dependency link between the Graphics API and the Winsys in the module diagram, but I find it distracting/irrelevant. For example, in Linux, the winsys has actually little/nothing to do with OpenGL, but everything to do with the GLX (which is not represented in the diagram, as it would have to be connected both to the Graphics API and the OS). So all these gory details end up being winsys responsibility.

At this level of detail I prefer have the average the reader to focus mostly on the graphics state, shaders, primitives, etc. But thanks for your pertinent questions. ;)

Anonymous said...

That's actually a superb way of explaining it.

Thank you. ;)

Of course, nobody is saying that deploying to users independent loadable modules is not possible, or even desirable in some platforms, but at this development stage there would be zero benefit.

Yes, I just wanted to describe the current state. And I agree that I can't see any benefit for loadable modules at the current stage. Just your description that the borders between the modules are still somewhat in flux make it clear that even trying to define an interface for such modules would be a futile effort. Maybe this will evolve like the linux kernel that also started a a single blob but at its current state can easily be divided into numerous modules. But that is very far into the future, with the added big 'if' that such a design would need to show significant benefit to offset the cost of implementing and maintaining it.

At this level of detail I prefer have the average the reader to focus mostly on the graphics state, shaders, primitives, etc. But thanks for your pertinent questions. ;)

Yes, I can understand that. I hope I wasn't too pertinent. ;)

Anonymous said...

Just a quick question for clarification - so the reasoning behind this effort (and the abstraction layout) is to make writing drivers easier (as well as easier to maintain), while theoretically the under-pinnings should be more stable?

For example, looking at the past and how the RV250 driver was "neutered" for the sake of "manageability", theoretically if a similar case should arise in the future - it should be possible to be handled more "gracefully" (from the end-user perspectice)?

I was a long-time RV250 user (Radeon 7500) on *nix and lived through the above case - going from %90 of Windows' performance and extremely stable, to ~%60 of Windows' performance with iffy stability. So anytime I hear the words "reuse code" this case comes to mind, and I cringe (for good reason - especially considering the R300 driver stagnated and there was no real upgrade-path for me).

Thanks,
DS

José Fonseca said...

DS,

Just a quick question for clarification - so the reasoning behind this effort (and the abstraction layout) is to make writing drivers easier (as well as easier to maintain), while theoretically the under-pinnings should be more stable?

The original drive for Gallium3D was to make writing drivers easier. But since then we realized that we could take a step further and make writing drivers easier for many graphics APIs, and OSes. This has become the main drive.

About the performance, I don't know R300 development history so I can't comment on that. But generally speaking, one cannot expect to make these abstractions, target multiple graphic APIs, and support multiple OSes without falling slightly from the performance peak in some cases (although we have yet to find a case where there is a significant change). So your concerns are not unfounded. On the other hand, by managing complexity much better, we found that we can do even more complex optimizations (most important of which are avoiding falling back to software rendering for certain hardware unsupported features like antialiased points and lines, by breaking them down in something equivalent that is supported by the hardware). But even more important than all that, is that the minimum hardware requirements for Gallium3D are fairly high — it does not make sense to implement a Gallium3D driver for hardware with fixed graphics pipeline (i.e., without at least decent fragment shader support). This means that we don't have to bend ourselves to support very old hardware with completely different design — those will likely be served by the existing drivers for the foreseeable future.

Unknown said...

"Gallium3D architecture can be described as ... a collection of supporting libraries... Gallium3D is not a framework." Well... wikipedia says:"In broad terms, a software framework is a code library that is designed to help software development."
Then according to wikipedia Gallium3D is a framework.
Instead of fighting on high level terminology, better go down one level in accuracy to shoot any troll on that subject.

José Fonseca said...

sylware,

Then according to wikipedia Gallium3D is a framework.

If you read the wikipedia article to the end it says: Software frameworks rely on the Hollywood Principle: "Don’t call us, we’ll call you." The definition you chose does start by saying "In broad terms"...

More important than of what wikipedia says, that was not what I was taught in university. And even more important than that, is that I justify why it is not a framework within that context. After all, one can find as many definitions of framework as authors on the subject.

Anonymous said...

Though I have no comments or insight into the workings of graphic drivers, I believe I grasp the concept of Gallium, and would just like to thank you for your work on the project.

It really does seem like this could produce better drivers, with increased support for graphic funtionality for a wider range of platforms (IE. not just Windows) and graphic APIs.

Thank you and good luck with the project.

Electro said...

sylware, much to my chagrin, in your attempt to pre-empt trolling, you have become the first troll.

English is a language of consensus, it changes with time and with opinion... so 'framework' is in the winsys module, please write a new definition for your own use.

The first gallium3d joke. Thanks for making the framework, I'll introduce a friend of mine to it.