Sunday, April 28, 2024

Month 5 - Week 3 - X11 Fullscreen Bug

 After the final touches to audio, my focus has now shifted to a new and rather interesting bug involving X11 window events and, arguably more importantly, Arch Linux. This bug has shown itself to me for a little while but was largely inconsistent in how it appeared. It would show in the unit tests ~80% of the time, and the source of it seems to be unknown currently. This bug will be my last bug to fix for the project as part of FSU, however, if I can't fix this bug by the deadline, I will be continuing work to fix it after. This is largely because this is the only bug left to fix to finally add Arch Linux as a fully supported platform. This will be brief as I didn't have a lot of time to fully inspect the bug like I wanted to, but there will be enough here to mark my current progress. So, with that, let's get started.

The first thing to note is the description of the bug.


Here are the things to note:

  • The bug has a visual aspect (the window will sometimes show, sometimes stay hidden, or show completely but be transparent).
  • It fails specifically when the check is run to see if the window is fullscreen.
  • Previous calls in the said test don't do anything.

Here is the test.


We can see on the overview that the window is initially created with a basic position (0, 0) and dimension (800, 500). It then reconfigures itself to a different position with different dimensions. Something else you might have taken notice of is the usage of `GiveWindowTimeBeforeRequiringPass`. From what I've gathered, this is here because sometimes X11 requires a bit of time to process events before it can check for what we want. So this is here to effectively wait out the processing of events to check if a function has passed properly. From here, this is where I started testing.

First off, breakpoint debugging is useless for this bug. Because if I placed a breakpoint and walked the function line by line, nothing would go wrong. Debugging would mainly be useful here if I could catch the bug failing in action, however, I'm not able to do that here. So, this leads me to test a little more conventionally. The thing I checked for immediately was timing. It could be that the code is going too quick and preventing X11 from processing everything in time. So I added small delays to check for this, however, it did not work. I also tried using the exact delays used in other tests, but the results were the same.

Interestingly enough, if I duplicated the exact same test and ran the full unit test suite, only the first test would fail, with the duplicate passing. Odd behavior.


From the discord messages above (which are posted in the Gateware Development channel), I described my difficulties with this bug as well as what I feel the bug is.

I feel this bug is a timing bug. Basically, one thread is doing things so quickly that the other thread can't keep up in time. This would explain the odd behavior, and why the test doesn't always fail. Of course, there is more testing and inspecting of the code that will be needed, but in total, this seems to be the main issue. So now, what has to happen, is we have to specialize the probes for this bug to target the timing over the functionality. If I can pinpoint that it is timing-related, then I focus my efforts on fixing that. However, if this isn't the case, I will have to inspect further to see what is exactly happening.

Currently, this is all that I have done for this bug. Next week should hopefully go into a deeper discussion on how I found the fix for it. But for now, this is all.

Sunday, April 21, 2024

Month 5 - Week 2 - Final Touches

 Last week, we discussed finishing the WAV file reader and getting the overall status for it marked as completed. There were some final changes. Moving over to GFile for UWP was a big step, but there was still some branching in the code, primarily due to Linux and Windows differences. I decided to focus my energy on getting these rounded out and fixed. This will be a light post, and step through everything fairly quickly.

The thing to really focus on and correct is how Linux and Windows structure the WAV header. Internally, Linux structures a WAV fairly simple, and this is due to it not requiring the extra data that was later attached when Microsoft extended the WAV format. Windows contains many things, however. It contains the primary information which is the same as Linux, but a union that holds additional information. This is also paired with a GUID. The purpose of the union and GUID is unknown to me, but to bridge compatibility with platforms, I had to move away from a platform-specific definition and move to an internal definition, which is exactly what I did.


If you have a keen eye with the Windows API, you will notice immediately that this new structure setup for WavReader is the exact same as Windows's definition. I did this for a simple reason: to support Windows and allow support for Linux. If I used the Windows definition, it wouldn't be able to compile for Linux due to obvious reasons (Windows API not being available for other OSes). After moving to the new structure, it was now the process of hooking everything up and removing old branching.





After making these changes, now WavReader no longer branches and works on every platform universally. Additionally, it acts as a wonderful introduction to what is possible with the library, as all of the heavy lifting for data handling is done by library code (GFile). So a lot of beginners just getting into Gateware could learn a fair bit by reading through the source code of WavReader.

This marks this merge request as complete. I marked my name in the list of contributors, and let the merge get reviewed again. It was merged. The last thing I did for audio was make two merge requests, one focusing on some simple Windows refactors, and the other focusing on UWP refactors. Effectively syncing both to the same modern standard as Linux. In total, everything is now completed.

What now? Now I find a new issue I can tackle, a bug or possible feature that will take only two weeks to implement. With my time almost finished with Gateware, I'm no longer able to tackle such large issues as I have in the past, so that will be left up to others. However, I will try to provide supporting changes here and there, and see what I can do with the time I have left for finals.

Sunday, April 14, 2024

Month 5 - Week 1 - Finishing the WAV File Reader

 In the previous week, we discussed and showed the introduction to the WAV file reader I'm implementing. The goal of this reader is to allow WAV files to be universal in logic while retaining the cross-platform nature of supporting not just Linux or Windows, but UWP as well. I'm excluding Mac from this as it already has a native WAV reader provided, so we don't have to implement this, thankfully. Now, I showed the very early stages of this file reader, specifically its Linux and Windows implementation, and what was needed for that. Well, over this week, we added UWP support and a lot of work had to go into that. There were also changes made to the unit tests to support the new UWP usage, among many other things. There's a lot, but I will go over them as quick as I can while retaining the main bits of information.

Firstly, UWP's management for file reading was much different from Linux and Windows. Linux and Windows used GFile for most of the file handling and file communication, however, UWP used an internal Windows library that is within the File API. This API had many quirks that I didn't like, but at the time felt it had to be used, resulting in my reader class getting very cluttered upon initial implementation.


As you can see, there was a lot of code added, and this code specifically was just for opening the file. Some interesting things to note specifically with UWP's file handling:

  1. All files are stored as a handle that we pass to functions to perform actions we want. This isn't too unknown and is regular, but is normally hidden, meaning the library is even more low-level than regular filesystem code in C++.
  2. `SetFilePointer` on the surface looks to be like a form of seeking inside of a file, but is actually lower-level than that, it is a function that is used to make the seek function.
  3. All file paths have to be wide char paths, if they are not, it will fail to open outright.

In total, the File API worked with is extremely low-level and lightweight, but also more bare compared to traditional options. this meant more work had to be put in just to get the state of the UWP support 1:1 with the other platforms. Extra frustrating is that UWP didn't like working with GFile, so I had to take note and continue implementing using this interface. 



By the end of the implementation, it bumped the full source file from around 500 lines of code to over 700 lines. Most of the additions were all focused on preprocessor branching, platform checking, and platform-specific code. Not good since GFile is meant to prevent a lot of the IO branching I had to do. During the meeting, the code was shown in a working state on all platforms and was shown to do the job intended, but I brought this issue up, and we discussed fixes. By the end of the meeting, I was assigned to figure out why GFile was failing and fix it. That's exactly what I did.

I spent a long time simply debugging and understanding the issue. I removed all traces of the File API used and used GFile instead. Here are something interesting I found.


So, come to find out, this was a pathing issue. Something that was happening because GFile wants relative pathing to work with, not absolute pathing. What this means is the unit tests have to change since they give absolute paths to the audio files. We don't want that, we want it to work with relative paths. So, we have to update the unit tests.



So after making all the edits, updating some of the code to reduce branching, and removing all the File API code, the tests now work.


There's still some cleaning I have to do to the code itself before I commit, but once that is done, I can rest easy knowing that my file reader is now using GFile completely, and executing its functionality 1:1 with every platform. The last change needed is replacing the Windows structures used currently for the WAV header info with actual full and proper internal structures. This will remove more branching, and separate any dependencies for this WAV reading functionality. Luckily, this shouldn't take me long and should be a relatively smooth process in total. It will just take some time to fully implement. Overall, this is everything I worked on this week.