Friday, June 19, 2020

Watch out for Modularity

Background
A few days ago, I wrote about my encounter with the BadMatch error while running OpenGL tests on Linux. The error was caused by the context and the window not being created with compatible visuals. My fix for the issue ensured that visuals were compatible. All the tests passed and the error disappeared, however, I broke modularity in the process.

Why modularity is important
The modularity of the Gateware framework ensures that the project is easy to maintain, understand, and use. The code is separated into logical groups, such as classes or libraries. Limiting the amount of interconnectedness between each module makes it easier for developers to understand the code, test it, and track down bugs.

How I broke it
GWindow_linux creates the window module on Linux using X11. GOpenGLSurface_linux sets up the OpenGL graphics module on a GWindow. Similarly, GVulkanSurface_linux sets up the Vulkan graphics module on a GWindow. The way the framework is designed, the graphics module knows about the window module but not the other way around. My solution introduced GLX into the window module, which is specific to OpenGL. In doing so, the window module now has code specific to the OpenGL graphics module, therefor modularity is broken. This means my fix for the bug is incomplete, and I have to find another way; A way that preserves modularity.

Two potential solutions
Since the graphics module relies on the window module, my question became how to create or modify a window to ensure it has a 32-bit color buffer.

  • Solution 1: Creating a 32-bit color buffer window
    1. Window creation is done inside the window module. First, we get a list of visuals and search through them. This can be done by calling an X11 function called XGetVisual().
    2. Determine which visual in the list has 32-bit color buffer. This part is a problem because in order to get the color buffer property of the visual we need to either use a function from GLX or an X11 extension library. We already determined using GLX inside the windows module breaks modularity because it is specific to OpenGL. The X11 extension library is an additional library that needs to be installed. Ideally, we want to limit the number of steps and libraries the end-user has to install to use OpenGL with the framework.
  • Solution 2: Modify a window to have a 32-bit color buffer
    1. The ideal place to modify the window's properties would be from the graphics module. Using a reference to the window, we change its color buffer to be 32-bit. There is a function called XGetWindowAttributes() we can use to get a pointer to the window's visual. However, modifying the properties of the window fails to change its color buffer. There is also another function called XChangeWindowAttributes(), but that produces similar results.
    2. If the previous step had worked, we would then make sure the context is created with the same visual as the window.

Less than ideal solution
Unfortunately, I didn't find any other ideal solutions. The solution that ended up getting implemented and merged to the developer branch was a modified version of solution 1. The code is set up to be compiled when OpenGL is enabled; otherwise, the previous window creation code is used. Doing this prevents the OpenGL-specific code in the window module from affecting the other graphics modules like Vulkan.

Conclusion
While the solution wasn't desirable, it does fix this issue with the BadMatch error and 32-bit color buffer. Ultimately, it is good for developers to have stable error-free code. Even so, every effort should be made to preserve modularity. This solution will do for now, but I'll be on the lookout for a better solution as I move on to other bugs and features.

No comments:

Post a Comment