Monday, October 30, 2017

N64 VI Filter

The N64's RDP chip includes a Video Interface (VI) stage that prepares the video for the final output. From the N64 Programming Manual:
The video interface reads the data out of the framebuffer in main memory and generates the composite, S-video, and RGB signals. The video interface also performs the second pass of the antialias algorithm. The video interface works in either NTSC or PAL mode, and can display 15- or 24-bit color pixels, with or without filtering, at both high and low resolutions. The video interface can also scale up a smaller image to fill the screen.
These functions can make a very big impact on the final image of an N64 game, and the ParaLLEl-N64 libretro core exposes the ability to toggle the postprocessing effects of this stage on and off. Turning it off nets you a few frames per second of speed but also gives us a peek behind the VI curtain:
So, you can see that the filter just barely touches the HUD elements but it does some pretty dramatic stuff to the rest of the image. It applies strong antialiasing to the outside edges of objects, which has a big, noticeable effect (so noticeable, you can see it in the thumbnail images) on Mario's hat and the silhouette of the tree, and it does some blurring that smooths out the dithering that is very visible in the unfiltered shot. On actual hardware, the blurring can be toggled off in some games (Quake II, for example, IIRC) or using Gameshark codes. I believe consoles modded with UltraHDMI or etim's N64RGB boards can also switch it off through the boards' firmwares.

Wednesday, October 25, 2017

Using RetroArch via Snappy

I've been working with some folks on trying to get a snap package up and running for RetroArch to go with our FlatPak and AppImage universal linux packages, and it's turned out to be more complicated than I expected to navigate the particulars of the packaging format combined with the restrictions of the security sandboxing.

We announced the package a couple of weeks ago but quickly got reports that users couldn't load files, they were confused as to why the package took a long time to load (only on the first launch, but they didn't know that), and more. Since updating my laptop to Ubuntu 17.10, I decided to "dogfood" the snap package, since that would be the only way I could get in front of the reports and ensure a good experience.

Since RetroArch requires a lot of stuff to look nice and function properly, we use a wrapper script that checks for the existence of that stuff and, if it's not where we expect it, it copies the stuff into the snap's user directory. Since that copying can take a long time, I decided to use notify-send to include some admittedly uninformative notices just to let the user know that nothing is frozen/broken and that we're just copying stuff in the background. The catch here is that you can't use the system's notify-send, you have to include it in the snap as a runtime dependency, under the "stage-packages" in the snapcraft.yaml recipe, like this. I tried adding an icon to make the notifications prettier and more obviously RetroArch-related, but I could never get it to actually see the icon, no matter where I stored it, so I gave up on that.

Ok, so the notifications were a nice little improvement, but we still couldn't actually get to any files to launch them, which makes the program pretty useless. For that, we needed to add the "home" plug to the recipe, like this. This plug is supposed to be auto-connected, so you shouldn't need to do anything to make it accessible to your application once it's in the recipe. However, RetroArch's non-native file-browsing meant that it tried to start in /, which is inaccessible (and in fact, totally invisible) to the snap (and if your snap starts you in an inaccessible directory, you can't ever get out of it), so I added a line to my wrapper that pre-populates the user's retroarch.cfg config file with a line telling it to start in the home directory, where we should have access. I tried using $HOME and ~/, both of which just sent me to the snap's home directory instead of the true home directory with all the files -_-. The solution I found--which is pretty crummy but whatever--is to use a relative path that points to one level above the snap package. That is, ~/../../../

Similarly, I couldn't reach my network shares, which I mount in /media (despite adding any plug that seemed even vaguely related to such a thing to the recipe), so I had to move my mount points into my true home directory and use those same relative paths to everything, e.g. ~/../../../smbshare/Emulation/BIOS for my 'system' directory. Once the mount point is in my true home directory, I could probably put symlinks into the snap package, as well, to avoid the silly relative paths.

The last major issue I ran into was that the *.desktop launcher that shows up when you search for programs in the sidebar kept complaining about not having an "exec" line and then failing to launch because of it. This one was super-confusing because our snap has a *.desktop file (it lives in $SNAP/meta/gui), and that file definitely has an exec line. It turns out that, during installation, snapd generates the *.desktop file that the OS actually looks for and stores it in /var/lib/snapd/desktop/applications. This file is based on the *.desktop included with your program, but if the exec line isn't just like it expects, it will strip it out entirely and not give you any indication of why. Initially, our *.desktop file pointed the exec line to the retroarch.wrapper script that does so much work for us, but snapd didn't like this and rejected it until we switched it to just "Exec=retroarch", which isn't the name of the actual executable but rather the name of the snap itself. It still launched the wrapper script, since that's what our recipe points to, so we're all set.

Since we need to use our script when we launch from a command line, as well, we made sure to end it with $*, but this has a couple of problems that experienced scriptors will spot immediately. First, it's not escaped, so any spaces in file names will break it. Second, it will only accept a single argument, which isn't going to work for us. So, I changed it to "$@" and all is well.

Now, the only issues left that I know of are: 1.) the wrapper script has our nice invader icon, which shows in the sidebar while the script is running, but once it dies off, the icon goes with it and the actual program just has an ugly question-mark/no-icon-found icon in the sidebar and 2.) the snap can't load any dynamic libraries that live outside of its domain, so I can't conveniently compile a test core and then launch from command line to test it with the -L switch. #1 isn't a big deal and #2 probably isn't possible to fix, so it is what it is.

Saturday, October 21, 2017

Running Graphical Programs as Root in Wayland

Fix for Invalid MIT-MAGIC-COOKIE-1 keyCannot open display error when trying to use sudo.

I just updated to Ubuntu 17.04 (and it's a great release; I was on 16.04 LTS before and it's well-worth the update) and noticed that I kept getting the above error when I tried to elevate my privs to edit system files with a graphical text editor (typically gedit, but I've switched to pluma). That's a result of improved security measures in Wayland that we didn't have to worry about with the now-abandoned Unity desktop used in previous releases.

Most of the solutions floating around for this error refer to X sessions (usually X-forwarding over SSH) and don't actually do anything to correct the Wayland issue. However, I came across this solution, which worked a treat:

Step 1.) Create a new local directory to house a custom executable:
mkdir ~/.local/bin/
Step 2.) Next, we'll make a little script that will elevate the privileges for us when invoked (the OP called it 'wsudo', which seems like a good choice to me):
nano ~/.local/bin/wsudo
Step 3.) Paste in these contents:
#small script to enable root access to x-windows systems
xhost +SI:localuser:root
sudo $1
#disable root access after application terminates
xhost -SI:localuser:root
#print access status to allow verification that root access was removed
Step 4.) Make the script executable:
chmod +x ~/.local/bin/wsudo
Step 5.) Temporarily add our local script directory to our Path for easy access:
export PATH=$PATH:~/.local/bin
Now, you can take it for a spin and make sure it works as expected (by running, for example, wsudo gedit /testfile and making sure it saves okay). If everything is in order...

Step 6.) Permanently add our local script directory to our Path:
echo "export PATH=$PATH:~/.local/bin" >> ~/.bashrc
That's it. Now you should be able to invoke wsudo any time you need to run a GUI program with elevated privs.

Analytics Tracking Footer