StreamFX v0.8.1 is now available!

In the two months since the release of Version 0.8.0, a lot of bugs have been discovered – which now have been fixed with Version 0.8.1! Let’s take a closer look at the things that have been fixed.

Update: Update 0.8.2 has been released fixing the newly discovered issues in 0.8.1. The links in the post have been updated.

Improving the Installer experience on Windows

This had been on the table for a while, and finally made it in. Due to the excessive flood of people not reading the installation instructions and asking the same question – usually within seconds of the same question being answered – the installation process had to become a bit more automatic.With that in mind, I went to town on the installer.

The first thing I did was get rid of the Win98 feel by enabling the modern UI built into the setup tool. Next was hiding the upgrade process that happens automatically in the background, as it sometimes confused users. And finally, it received the ability to automatically install any missing MSVC Redistributable – a much needed feature as almost all support requests could be fixed with just that.

With that all done, it was time to move on to other more important things.

Invisible Source Mirrors

In version 0.8 a fix was applied to no longer freeze OBS Studio when opening the filter dialog on a Source Mirror, and this in turn caused Source Mirror to disappear as the source size was queried in the tick function. The tick function however is not called if the source has no size, which meant it was never set. Now the source size is acquired as soon as the source is acquired, which fixes it for most types of sources.

A different fix has to be implemented for asynchronous sources, which usually get their size at a later point in time. This second fix will likely be released with 0.9, and not be backported to 0.8.

Weird Shader filter Rendering

Shader filters used for glow effect.

Shader filters sometimes turned invisible on load, which resulted in very weird graphics glitches. Fixing this was actually super easy, as the reason for the invisible glitch was actually that the size of the output was set to 0x0, and thus exceptions were being thrown. Catching those exceptions and then skipping the filter fixed the issue.

But something else was still causing problems. Shader filters would look weird depending on how their output resolution was scaled. Turns out I had accidentally coded it to capture the input at the output resolution – fixing that made my effects crystal clear again. Now all shader filters should look crystal clear for you as well!

New Memory Leaks?!

Through testing with one of my complex scenes, I discovered an abnormally high number of memory leaks. As it turns out, they actually came from three distinct sources, so fixing them wasn’t easy, and I have no explanation for one of them. I’ve managed to fix all of them, but lets actually look at each one individually:

Source Tracker

For a long time now, StreamFX has used its own source tracker implementation, which keeps track of existing sources and scenes, instead of obs_enum_sources and obs_enum_scenes. And this implementation was the source of not just one, but 83 memory leaks – and due to the nature of the code, all of them are critical bugs.

So what caused them? A quick glance over the code didn’t reveal any obvious causes, and did not reveal anything unusal – even hours later I still had no idea what caused them. Even now, nothing jumps out at me that could have caused the leaks. My only guess is that we somehow missed destruction events, which would imply that libOBS is broken, or that we corrupted the map in a thread somewhere.

I could only gamble at a solution by replacing all the direct pointers with std::shared_ptr, and my gamble paid off. Replacing all the pointers to obs_source_t and obs_weak_source_t with std::shared_ptrs fixed them, as long as a custom deleter was being used. Hooray, on to the next memory leaks!

Vertex Buffers

For those not familiar with the StreamFX code base, most of the internal libOBS objects have fitting C++ wrappers that handle all the reference counting things. The same is true for gs::vertex_buffer, yet it was the source of not just one memory leak, but 13. Looking at the source code didn’t reveal much on the surface, everything looks like it should have worked as intended.

Closer inspection revealed the first bug: The gs_vbdata_t object was only deleted if the gs_vertbuffer_t object did not exist. This was obviously wrong, so I replaced the entire thing with an std::shared_ptr<gs_vbdata_t> and a custom deleter. One down, 12 to go – but where could they even be?

if (_data) {
	memset(_data, 0, sizeof(gs_vb_data));
	if (!_buffer) { // The problem.
		gs_vbdata_destroy(_data);
		_data = nullptr;
	}
}

Several hours of reading the code didn’t reveal a single thing. There should have been no way for these memory leaks to occur after this, and yet they did – in total 12 memory leaks were unaccounted for. So I started debugging, and eventually found the culprit: libOBS sets the global obs object to NULL right before unloading all modules, which meant that all the GPU related code would not run.

This is effectively unfixable from my end, so I’ve only been able to apply a work around which reduced the memory leaks to 5. Once the OBS Project releases a new OBS Studio version, they should instantly disappear as a fix for this behavior has already been applied to the main code branch of OBS Studio.

Configuration

And with that, we are left with two more fixable memory leaks – and the largest difficulty curve I have ever encountered in my entire career in programming. One of the bugs was simply forgetting to free a memory block, but the other was straight up unexplainable behavior. No matter which documentation I looked at, it should not have occured – and yet it did. Try to spot the problem yourself:

bool streamfx::ui::handler::have_shown_about_streamfx(bool shown)
{
	if (shown) {
		obs_data_set_bool(streamfx::configuration::instance()->get().get(), _cfg_have_shown_about.data(), true);
	}
	if (streamfx::configuration::instance()->is_different_version()) {
		return false;
	} else {
		return obs_data_get_bool(streamfx::configuration::instance()->get().get(), _cfg_have_shown_about.data());
	}
}
bool streamfx::ui::handler::have_shown_about_streamfx(bool shown)
{
	auto config = streamfx::configuration::instance();
	auto data   = config->get();
	if (shown) {
		obs_data_set_bool(data.get(), _cfg_have_shown_about.data(), true);
	}
	if (config->is_different_version()) {
		return false;
	} else {
		return obs_data_get_bool(data.get(), _cfg_have_shown_about.data());
	}
}

Looking at this, the only things that are different are how the std::shared_ptr<streamfx::configuration> and std::shared_ptr<obs_data_t> are stored. Both should have identical results, but they don’t. If anyone knows what the actual reason behind this weird behavior is, please leave a comment below, because I couldn’t figure it out with the C++ documentation that is available to me.

Closing Words

And that is all that was included in the update for version 0.8.1, at least on the user facing side. There are additional changes to the developer facing side, but aside from that, there isn’t much to talk about for this version. Go and grab the latest stable version from Github if you haven’t already! You can find it here on Github.

– Xaymar out.

Bookmark the permalink.

Comments are closed.