A Pixel Format Guide (to the galaxy) – Update

A few weeks ago I introduced the Pixel Format Guide — a collection of documents and the accompanying pfg tool which aim to help people navigate the wilderness of pixel format definitions. In this post I will list the most exciting improvements that have been made since the original announcement.

New pixel format families

The core mission of the Pixel Format Guide is to become a comprehensive reference for pixel format definitions. Therefore, it’s no surprise that I have put a lot of effort into adding more pixel format families. At the time the previous post was written, the Pixel Format Guide supported 3 formats: Vulkan, OpenGL and Wayland-DRM. Since then, I have added the Cairo, DirectFB, Pixman, SDL2 and V4L2 pixel format families, bringing the total number of supported families to 8 and the total number of supported pixel format definitions to 459!

Bit indices

While working with packed pixel formats, I noticed that the ordering of the component bits is sometimes difficult to figure out. This happens especially when the bits of a component are split between multiple bytes, like, for example, in an RGB565 16-bit format:

Format:               SDL_PIXELFORMAT_RGB565
Described as:         Native 16-bit type
Native type:          M              L
                      RRRRRGGGGGGBBBBB
Memory little-endian: 0        1
                      M      L M      L
                      GGGBBBBB RRRRRGGG
Memory big-endian:    0        1
                      M      L M      L
                      RRRRRGGG GGGBBBBB

Each byte in memory holds 3 bits of the G component, but it’s not easy to tell exactly which bits are in each byte. To fix this, the latest version of the pfg tool introduces component bit indices. Every component bit is now accompanied by its index, making the bit order crystal clear:

Format:               SDL_PIXELFORMAT_RGB565
Described as:         Native 16-bit type
Native type:          M                              L
                      R₄R₃R₂R₁R₀G₅G₄G₃G₂G₁G₀B₄B₃B₂B₁B₀
Memory little-endian: 0                1
                      M              L M              L
                      G₂G₁G₀B₄B₃B₂B₁B₀ R₄R₃R₂R₁R₀G₅G₄G₃
Memory big-endian:    0                1
                      M              L M              L
                      R₄R₃R₂R₁R₀G₅G₄G₃ G₂G₁G₀B₄B₃B₂B₁B₀

If you prefer not to see the bit indices you can use the --hide-bit-indices flag.

Discovery of compatible pixel formats

The inspiration for the Pixel Format Guide was a series of frustrating experiences trying to manually match pixel formats with other, compatible pixel formats from different families. The latest version of the pfg tool finally includes support for automating such operations, in the form of the find-compatible command.

With the find-compatible command, discovering which OpenGL formats are compatible with the PIXMAN_b5g6r5 format is now as easy as:

$ python3 -m pfg find-compatible PIXMAN_b5g6r5 opengl
Format: PIXMAN_b5g6r5
Is compatible on all systems with:
        GL_RGB+GL_UNSIGNED_SHORT_5_6_5_REV
        GL_RGB_INTEGER+GL_UNSIGNED_SHORT_5_6_5_REV
Is compatible on little-endian systems with:
Is compatible on big-endian systems with

Similarly, to find out which SDL2 formats are compatible with the VK_FORMAT_R8G8B8A8_UNORM format, you can run:

$ python3 -m pfg find-compatible VK_FORMAT_R8G8B8A8_UNORM sdl2
Format: VK_FORMAT_R8G8B8A8_UNORM
Is compatible on all systems with:
        SDL_PIXELFORMAT_RGBA32
Is compatible on little-endian systems with:
        SDL_PIXELFORMAT_ABGR8888
Is compatible on big-endian systems with:
        SDL_PIXELFORMAT_RGBA8888

Listing supported pixel formats and families

The pfg tool now supports the list-formats and list-families commands. The former lists the supported pixel formats for the specified family, while the latter lists all the supported pixel format families. These commands can be very useful when writing scripts involving the pfg tool.

As an example, with the list-formats command you can find which OpenGL formats are compatible with each Cairo format by running:

$ for f in $(python3 -m pfg list-formats cairo); do python3 -m pfg find-compatible $f opengl; done

I hope you enjoy the improvements!

Once again, I would like to thank my employer, Collabora, for sponsoring my work on the Pixel Format Guide as an R&D project.

Advertisements

A Pixel Format Guide (to the galaxy)

I spend a lot of my time in various corners of the graphics domain of the FOSS world. In my time there I frequently have to deal with a variety of pixel formats definitions. Every graphics API and project has its own way of describing and naming pixel formats — the different flavors used by Vulkan, OpenGL, Mesa, Gallium, Wayland, DRM, GBM, Pixman, Mir and SDL are just a few of the beasts one can encounter in the graphics wilderness.

It could be my aging memory, but, for some reason, I never seem to be able to remember how to interpret all the different formats. “How are the components laid out in memory?”, “Does it matter if the system is little-endian or big-endian?” are some of the questions I often have to look up, with varying degrees of success.

It turns out that I am not the only one facing this issue. It’s not uncommon for developers to misinterpret pixel formats, often with entertaining and psychedelic effects. If you are lucky you may catch a glimpse of uncanny blue foxes running under alien red skies.

Despite the potential for entertainment, this problem is a constant cause of frustration for developers. I finally decided to do something about it — I have started the Pixel Format Guide.

The Pixel Format Guide consists of two components. The first is the guide itself — a collection of documents describing how to interpret the pixel format definitions of various APIs and projects.

The second component is the pfg tool which performs the interpretation of pixel formats automatically. Did you ever wonder how the GL_RGBA with GL_UNSIGNED_INT_2_10_10_10_REV OpenGL pixel format is laid out in memory?  Now it’s easy to figure it out:

$ python3 -m pfg describe GL_RGBA+GL_UNSIGNED_INT_2_10_10_10_REV
Format:               GL_RGBA+GL_UNSIGNED_INT_2_10_10_10_REV
Described as:         Native 32-bit type
Native type:          M                              L
                      AABBBBBBBBBBGGGGGGGGGGRRRRRRRRRR
Memory little-endian: 0        1        2        3
                      M      L M      L M      L M      L
                      RRRRRRRR GGGGGGRR BBBBGGGG AABBBBBB
Memory big-endian:    0        1        2        3
                      M      L M      L M      L M      L
                      AABBBBBB BBBBGGGG GGGGGGRR RRRRRRRR

How about the WL_DRM_FORMAT_ARGB8888 Wayland-DRM format? Again, it’s easy:

$ python3 -m pfg describe WL_DRM_FORMAT_ARGB8888
Format: WL_DRM_FORMAT_ARGB8888
Described as: Bytes in memory
Memory little-endian: 0        1        2        3
                      M      L M      L M      L M      L
                      BBBBBBBB GGGGGGGG RRRRRRRR AAAAAAAA
Memory big-endian:    0        1        2        3
                      M      L M      L M      L M      L
                      BBBBBBBB GGGGGGGG RRRRRRRR AAAAAAAA

The Pixel Format Guide is a work in progress. It currently supports many Vulkan, OpenGL and Wayland(-DRM) formats, and it’s constantly growing. This project was conceived as a collaborative endeavor, not a one-person effort (but I’ll do my best), so, if you are familiar with a pixel format family, please consider contributing to the guide and the python tool!

Before signing off I would like to thank my employer, Collabora, for sponsoring my work on the Pixel Format Guide as an R&D project.

vkmark: more than a Vulkan benchmark

Ever since Vulkan was announced a few years ago, the idea of creating a Vulkan benchmarking tool in the spirit of glmark2 had been floating in my mind. Recently, thanks to my employer, Collabora, this idea has materialized! The result is the vkmark Vulkan benchmark, hosted on github:

https://github.com/vkmark/vkmark

Like its glmark2 sibling project, vkmark’s goals are different from the goals of big, monolithic and usually proprietary benchmarks. Instead of providing a single, complex benchmark, vkmark aims to provide an extensible suite of targeted, configurable benchmarking scenes. Most scenes exercise specific Vulkan features or usage patterns (e.g., desktop 2.5D scenarios), although we are also happy to have more complex, visually intriguing scenes.

Benchmarking scenes can be configured with options that affect various aspects of their rendering. We hope that the ease with which developers can use different options will make it painless to perform targeted tests and eventually provide best practices advice.

A few years ago we were pleasantly surprised to learn that developers were using glmark2 as a testing tool for driver development, especially in free (as in freedom) software projects. This is a goal that we want to actively pursue for vkmark, too. The flexible benchmarking approach is a natural fit for this kind of development; the developer can start with getting the simple scenes working and then, as the driver matures, move to scenes that use more advanced features. vkmark has already proved useful in this regard, being an valuable testing aid for my own experiments in the Mesa Vulkan WSI implementation.

With vkmark we also want to be on the cutting edge of software development practices and tools. vkmark is a modern, C++14 codebase, using the vulkan-hpp bindings, the Meson build system and the Catch test framework. To ensure a high quality codebase, the core of vkmark is developed using test-driven development.

It is still early days, but vkmark already has support for X11, Wayland and DRM/KMS, and provides two simple scenes: a “clear” scene, and a “cube” scene that renders a simple colored cube based on the vkcube example (which is itself based on kmscube). The future looks bright!

We are looking forward to getting more feedback on vkmark and, of course, contributions are always welcome!