Page 1 of 3

RetroArch - Variable BFI Mod for 180Hz/240Hz/Etc

Posted: 12 Sep 2020, 14:33
by ophidon
So I've done a side project to mod Retroarch to add support for bfi at 180 Hz, 240 Hz, etc.

As discussed in previous threads, this eliminates the problem of image retention that is present at 120 Hz software bfi, further increases clarity (but decreases brightness ofc). Overall, I'm extremely happy with the output at 180hz especially. Also, you should preferably use an 8 bit panel (and the newest TNs are true 8bit too like the HP Omen X 27 I tested this on, which means you can skip the IPS glow). As also discussed in previous threads, 6bit + frc doesn't play nice with software bfi even at 180 or 240hz, I find.

I can also say that vs. using the 60hz single strobe ulmb hack, there doesn't seem to be any problem with strobe crosstalk, nor is the flickering nearly as severe. I would presume this is because since the actual backlight stays on with software bfi the total difference in luminance in on vs off frames is not as severe.

I would in no way say this mod is ready to merge into Retroarch proper, it was mainly made for personal use. But I'll include the link to my fork if anyone wants to polish and submit it to solve the ticket for BFI v2 that Chief Blurbuster already put in. Otherwise it'll get out of date vs the real Retroarch.

One minor non-ui issue (at least for me) is that seemingly whenever the emulator skips a frame because your pc can't keep up, or for emulation sync reasons, or whatever else the screen will flash for that frame. Happens much more in the menu than in game, so don't be overly concerned when you first turn it on. With hard gpu sync set to one frame look ahead, and audio sync off (which never causes any terribly out of sync audio for me) I was able to get this to down to less than once a minute, quite tolerable considering the upsides. There still might be a software solution to account for this, and at least get it to flash black when this happens so it isn't nearly as noticeable.

Here is a link to the modded retroarch exe which you just drop in replace for your current exe: ... sp=sharing

And here is a link to my Github retroarch fork if anybody wants to fork it again and take it to the point it could be merged upstream:

To use, I've turned the existing on/off setting for BFI into an integer value, where 0 is off, 1 is one black frame (meant for 120hz), 2 is two black frames (meant for 180hz), 3 is three black frames (meant for 240hz) etc. If you set the integer value to something that doesn't properly match your current screen refresh rate by the above formula, you will not like the result, lol.

Re: RetroArch - Variable BFI Mod for 180Hz/240Hz/Etc

Posted: 12 Sep 2020, 23:09
by RealNC
I don't have a 180Hz screen to test with, but it sounds like a very nice feature to have nonetheless!

I mentioned this on the libretro discord, and they are definitely interested in this feature.

Re: RetroArch - Variable BFI Mod for 180Hz/240Hz/Etc

Posted: 13 Sep 2020, 17:45
by Chief Blur Buster
RealNC wrote:
12 Sep 2020, 23:09
I don't have a 180Hz screen to test with, but it sounds like a very nice feature to have nonetheless!

I mentioned this on the libretro discord, and they are definitely interested in this feature.
Although I recall your monitor is 1440p 165Hz, I should mention:

Almost any recent >180 Hz screen (200Hz, 240Hz) can also do 180Hz.

Re: RetroArch - Variable BFI Mod for 180Hz/240Hz/Etc

Posted: 13 Sep 2020, 17:46
by Chief Blur Buster
ophidon wrote:
12 Sep 2020, 14:33
So I've done a side project to mod Retroarch to add support for bfi at 180 Hz, 240 Hz, etc.
Fantastic contribution.

We probably should crosspost in the BFIv2 github:
I know you say it's not ready but the main people at the BFIv2 probably should be made aware of this contribution too.
In the meantime I'm adding a link to this forum thread from there. Plus, I'm crossposting information from there to here, so other developers know --

Support Adjustable Software BFI for Higher Hz
We neeed RetroArch to support the following Black Frame Insertion (BFI) sequences:

- BFI sequence on 120Hz for 60Hz emulation: ON, OFF
- BFI sequence on 180Hz for 60Hz emulation: ON, OFF, OFF
- BFI sequence on 240Hz for 60Hz emulation: ON, OFF, OFF, OFF
- BFI sequence on 300Hz for 60Hz emulation: ON, OFF, OFF, OFF, OFF
- BFI sequence on 360Hz for 60Hz emulation: ON, OFF, OFF, OFF, OFF, OFF

Best Case Display Motion Blur Reduction by BFI
The easiest way to do so is provide a comma-separated black-frame insertion sequence in a configuration file, to allow customizability. Default strings can be done for common scenarios, but would let advanced users customize BFI. Relative to the original blur of a 60Hz LCD, higher Hz produces more software-BFI-blur-reduction (non-strobed LCD use-case, though software BFI also helps hardware strobing too for these specific numbers, in lower strobe lag + better quality strobing).

- 120Hz BFI sequence (50% less motion blur): 1 , 0
- 180Hz BFI sequence (66% less motion blur): 1 , 0 , 0
- 240Hz BFI sequence (75% less motion blur): 1 , 0 , 0 , 0
- 300Hz BFI sequence (80% less motion blur): 1 , 0 , 0 , 0, 0
- 360Hz BFI sequence (83% less motion blur): 1 , 0 , 0 , 0 , 0 , 0

Adjustable Motion Blur (Tradeoff Between Flicker + Brightness + Clarity)
Custom sequences can allow you to adjust motion blur, brightness, and flicker tradeoff. Just like TestUFO Variable-Blur BFI Demo. Try this link on a high-Hz LCD with hardware strobing distabled! If you have 240Hz, try configuring 4 or 5 UFOs instead, to see more variable-blur flexibility. Adjustability is a continuum between hardware Hz to emulator Hz. Minimum persistence-based display motion blur is persistence of max Hz (1/360sec visibility = 2.8ms blur). Maximum display motion blur is emulator Hz (1/60sec visibility = 16.7ms blur). Thus higher Hz, the more BFI motion blur adjustability.

- 180Hz bright BFI sequence (33% less motion blur): 1 , 1 , 0
- 240Hz bright BFI sequence (25% less motion blur): 1 , 1 , 1 , 0
- 360Hz bright BFI sequence (66% less motion blur): 1 , 1 , 0 , 0 , 0 , 0
- 360Hz bright BFI sequence (33% less motion blur): 1 , 1 , 1 , 1, 0 , 0

Basic CRT Phosphor Decay Emulation
In fact, alpha-blended BFI is also desirable, so this could be a percentage setting or floating point setting, to approximate phosphor fade. This makes flickerfeel more approximate a CRT tube (as far as refresh granularity permits). And feels much less harsh than 60Hz squarewave for many.

- 240Hz alpha-blended BFI slow-rise slow-decay sequence: 0.5 , 1 , 0.5 , 0
- 360Hz alpha-blended BFI slow-rise slow-decay sequence: 0.5 , 1 , 0.5 , 0 , 0 , 0
- 360Hz alpha-blended BFI fast-rise, slow-decay sequence: 1 , 0.5 , 0.25 , 0 , 0 , 0
- 360Hz alpha-blended BFI fast-rise, superslow-decay sequence: 1 , 0.75 , 0.5 , 0.25 , 0.1 , 0

Alternative methods of configuration could be discussed instead.

Hopefully this is a very easy change for a RetroArchfor the refresh rate race to retina refresh rates. For now, this can be just a simple configuration file string, to help users incubate this. It should be easy to write instruction guides, to help get more users playing with BFI.

BFI Percentage Terminology (in case it wasn't clear)

1 = Fully visible frame
0 = Fully black frame
0.5 = A darkened frame that is 50% brightness

  • Comma sequences too long for current actual-hardware refresh rate can simply be trunctated for lower Hz. So "1,0,0,0,0,0" can become catchall for all refresh rates
  • Comma sequences too short for current actual-hardware refresh rate can simply pad missing values as 0
  • First number should be non-blank for lowest lag. For convenience, config file reader can automatically numbershift to lag-optimize user-defined setting, e.g. turn "0, 1, 0.5, 0" into "1, 0.5, 0, 0". It is visually identical but lower lag.
  • The numbershifting technique can also be used as the anti-retention technique (can be enabled by default for hardware Hz evenly divisible by emulator Hz, such as 120,240,360 instead of 180,300, for 60Hz emulators).
  • Future Rolling BFIv3 (github #10757 ...) could actually theoretically use the same BFIv2 strings, simply by using 6 different numbershifted versions of the same strings for 6 slices for the same 360Hz display (360/60 = 6). Or 4 different numbershifted versions of the same strings for 4 slices of the same 240Hz display (240/60 = 4). For some developers, this can theoretically make BFIv3 conceptually simpler to implement (for all phosphor fade speeds), albiet alphablended overlaps will still be needed to eliminate seams/tearing artifacts. You'd simply add a command line argument "rolling = on/off". Although this may not be the most ideal coding path, explaining it this way, may be more conceptually simple for a developer how to visualize how to turn global BFIv2 into a rolling BFIv3 later on in the future, as a stopgap...
I would like to see config-file-programmble BFI sequences.

Good initial groundwork to pave simple BFI for 180Hz, 240Hz, etc (the groundwork just done so far, does equivalent comma sequences of "1,0,0" and "1,1,0" and "1,0,0,0" and "1,1,0,0" and "1,1,1,0"

One can default to "1,0,0,0,0,0" or "1" (for 1 visible, rest black). 120Hz would expand trunctate that to "1,0" and 180Hz would trunctate that to "1,0,0" and 240Hz would trunctate that to "1,0,0,0". Any missing digits at end of a BFI string would be an assumed zero, if you just did "1" or "1,1" or "1,1,1". So the comma strings don't necessarily need to match the number of actual refresh cycles per emulated refresh cycle, but still let advanced users configure the BFI sequence via manual edits to the RetroArch configuration file, or perhaps with some named predefined profiles.

Re: RetroArch - Variable BFI Mod for 180Hz/240Hz/Etc

Posted: 14 Sep 2020, 10:51
by ophidon
I was aware of that BFI v2 post when I made this mod, so I did have intentions to add more advanced BFI patterns. Though I can tell you from use of what I've done already, unless future super high hz displays can no longer sync to as 'low' as 180hz, that On/Off/Off at 180hz is a quite sufficient combination of blur reduction and maintaining brightness, without needing to do anything fancier.

Right now, I'm fighting the last semi-significant issue with bfi at 180/240hz, in that any frame variance leads to a random flash from either a black or real frame being displayed twice. The same way without BFI, you would get a momentary stutter. Even though you're only still displaying one actual frame per 60hz, the timing requirements are still much tighter at 180hz and 240hz than they even were with the existing 120hz bfi.

I'm afraid I might be out of my depth trying to solve this issue though. I am a developer by trade, but have absolutely no experience outside of this with any sort of emulation or graphics system programming.

I do believe it -can- be solved, as currently, with a newer version of the code than I posted, adjusting the in emulator sync settings, and modifying the vsync swap interval on the fly for the black frame period, instead of using multiple black frames (same end result for the amount of time black is displayed between frames but i -think- it unblocks the gpu thread earlier to keep working on the next frame to help the timing succeed), I can get it to happen on average only once every minute or two at 180hz, so the timing is succeeding 99.9% of the time as it is.

Anyway, unless this is solved, I do think a lot of people would turn it off out of annoyance, which would be a terrible shame, as it otherwise is a near perfect solution with advantages against even a 60hz hardware strobe in no strobe crosstalk, significantly less noticeable flicker, and not needing a display that can do hardware bfi at all (let alone at 60hz).

Any help you could provide getting an actual retroarch/graphics programmer to investigate a solution would eventually (once 180hz+ screens are common) be appreciated by probably nearly all Retroarch users.

Re: RetroArch - Variable BFI Mod for 180Hz/240Hz/Etc

Posted: 14 Sep 2020, 11:26
by Chief Blur Buster
Yes, as refresh rates become finer granularity, assigning the correct frame (black frame or visible frame) to the correct refresh cycle becomes harder. The time window for a correctly time page flip at 60Hz is 16.7ms but the time window for a correctly timed page flip at 40Hz is only 4.2ms. Ouch.

There are multiple tricks to smooth this out.

Adding a separate thread dedicated only to page flipping (moving a back buffer frame to front buffer).
The thread that flips finished emulator frames could run at a much higher priority (or even real time priority). That thread would be designed to only focus on flipping frames, and nothing else -- everything (emulator rendering) else would run in other threads. Basically this would be a real time thread that uses almost no CPU, except needing real time priority for the purposes of timing precision. The flipping needs to be pretty much microsecond accurate and would handle BFI behaviours on its own by itself. That way, the BFI continues working properly even if emulator framerate fluctuates. And it can also, perhaps do alphablending (e.g. 50%-50%-0%-0%) to "catch up" an out-of-sync cadence when emulator clock drifts differently from the display. So basically the BFI thread would serve the purpose of
(1) Handle BFI sequence
(2) Ultra high-accuracy timing of frame presentations
(3) Keep BFI cadence going even if emulator slows down. (lesser of evil)
(4) Detecting missed frames, and trying to retroactively compensate without flicker (can be successful if detected up to 1 refresh cycle late)
(5) Detecting out of sync situation, and trying to retroactively compensate without flicker (by blending BFI alphablended over multiple refresh cycles, to avoid flicker during BFI cadence re-sync)
(6) Anti-burn-in behaviours.
(7) Code-architecturally pave way for future BFIv3 if need be (software based CRT electron gun emulation -- aka rolling scan)

Initially the thread can focus on just (1) and (2) but makes it (theoretically) easier to do everything else independently of the emulator frame rate. Basically it can simply flywheel-sync to the emulator framerate, and slew the sync (carefully algorithmically without flicker) everytime the emulator frame rate changes or goes out of sync, etc. And also make it more compatible (maybe) to a future path of BFIv3.

Also as refresh rates become higher (tiny granularity), output-side buffering becomes tolerable -- e.g. Only 4.2ms buffer latency at 240Hz. This can help de-flicker ultra-high-Hz BFI. This would be handled by the "thread" for "BFI-related processing". Basically the main thread would Present() to the BFI thread.

Architecturally, the idea is that basically the original Direct3D Present() or OpenGL glxxSwapBuffers() in RetroArch becomes a wrapper such as PresentWrapper() or StartPresent() or whatever (basically your own frame presentation wrapper to replace the original frame presentation) -- it instead now relay the frame to the BFI thread, which can then decide to do its own asynchronous buffering as needed, or not -- perhaps as a configurable option as a flicker-avoidance manoever. RunAhead (-16.7ms latency) can save enough latency to fully compensate for BFI-handling latencies (+4.2ms latency at 240Hz), since elimination of flicker can be quite important for BFI. By 1000Hz, buffering latency becomes only 1ms (for 1 refresh cycle) or only 2ms (for 2 refresh cycle), to prevent flicker from BFI imprecisions.

The thread that does BFI should bve higher priority than ANYTHING in the emulator -- yet still use almost no CPU; simply using the high priority CPU only as a Present() timing-accuracy improver. This may improve things.

Keep overheads to minimum in the frame-present thread. Shaders and CRT filter applying should occur just before this thread -- but not inside this thread. Perhaps inside the present wrapper before the finished framebuffer is relayed to the high-priority thread (the thread designed to keep frame flipping cadence to refresh cycles).

I don't know if a presentation thread is already being done, and whether if that presentation thread is higher priority than the rest of the emulator, but this should be looked into.


Not exactcly related, but important in a timing sphere (not as critical, but important nontheless) -- VRR needs to get as much as microsecond-accurate Gametime-to-Present() time relativity as possible, for proper destuttering (technical information #1 as well as technical information #2.

You might not want to do this, or you might want to -- but this is what I think architecturally might need to be done.

This is merely only an architecture suggestion for any BFI / CRT electron gun emulator workflow in an emulator.

Re: RetroArch - Variable BFI Mod for 180Hz/240Hz/Etc

Posted: 14 Sep 2020, 16:18
by Chief Blur Buster
Oh, and additional commentary:

I think RetroArch already uses it, but you can also use waitable swapchains too, but also simultaneously keep track of the VSYNC's to make sure you've got plenty of time budget to flip on time.

One can busywait on microsecond timers here -- QueryPerformanceCounter() or RTDSC. You can use timers up to the millisecond prior, then busywait the rest of the way, before presenting the frame. This can be important for ultra-accurate VRR framepacing when there's no discrete exact emulator-Hz-matched VSYNC to wait upon. The "timer-then-busywait" technique is used by Tearline Jedi for raster-precise placement of tearlines.

With Tearline Jedi, I'm working with 10 and 20 microsecond time windows in inefficient garbage-collected interpreted languages (C# !!!), you're working with larger safety-margins. The present time window of 240Hz is 4166 microseconds -- a relative truck-sized hole in comparison. I suspect one can easily keep cadence at that (240Hz) with no BFI cadence problems or many minutes (even hourlong) in pure C/C++ with the real time priority thread technique I described above.

Especially if you use Admin-priority Real Time for the present-thread to pre-empt everything else. But for now, just simply do simple stuff: RetroArch process priority should be at least one priority level above the rest of the system priority (so background software doesn't interfere cadence as much), and frame present thread specifically should be higher thread priority than all other threads in RetroArch (so other RetroArch threads doesn't interfere with presentation cadence).

Mind you, the GPU driver may do its own sheninigians such as power management (if GPU <10%) can jitter things around, but there are workarounds for that stuff too (make the emulator work harder / present the duplicate frame multiple times / etc). When the CPU/GPU falls below 10%, power management tends to add presentation jitter, so sometimes one wants to intentional burn CPU/GPU if you don't care about power (e.g. AC connected emulator where emulation accuracy + CRT emulation accuracy is important). Tearline Jedi often became more accurate when I intentionally added some dummy activities to prevent power management induced jitter. In theory this can be a command line option that can be toggled on/off.

It is also fun statistical debugging: Jitter is often self-detectable (you can use microsecond accurate counters to detect if you're missing frame presentations), as power management jitter creates an approximately 10x-100x worse standard deviation to frame present jitter, so it lights up like a christmas tree in frame presentation timestamp statistics if you record presentation timestamps and display them onto a graph. You can also log frame-delivery timestamps (incoming frames from RetroArch to the high priority present thread) and frame-present timestamps (the time that Present() unblocks and returns). Diffs between two-adjacent-frame QueryPerformanceCounter() and display consecutive diffs of adjacent framepairs (input Hz) or refreshpairs (output Hz) and show it as a simultaneous two-overlaid graph, RTSS-style overlay if you wished. You prefer to see two flat lines, and enough time margin to allow frametime jitter without affecting BFI cadence. If very spikey, you know it's not got enough safety margin to avoid BFI flicker, and gives you opportunity to fine-tune (e.g. add a one-refresh-cycle tape delay or such -- which is less evil at higher Hz -- 360Hz is less than 3ms).

Certainly some of this stuff goes over many people's heads, but Blur Busters job is to help educate the masses on display temporals -- and you sound like you probably can figure out what I am trying to say here.

Even a small step by writing a barebones 100-line present wrapper for a separate-thread presenter, and testing the wrapper if it improves things, could be a good move. If you have the skills to write a presentation-thread, give it a try! You can stick to blocking frame presentation (VSYNC ON) for simplicity.

Once done, refine it to make sure that the blocking behaviours of the individual threads is capable of being independent (blocking within the frame presentation wrapper, and blocking within the actual frame presentation thread), to make it easier to compensate for future emulator slowdowns, i.e. main thread blocking while presentation thread is merrily continuing, and main thread not blocking, while presentation thread is in a blocking wait for actual display sync. Proper architecturing will help shock-absorb emulator jitter much better.

Re: RetroArch - Variable BFI Mod for 180Hz/240Hz/Etc

Posted: 15 Sep 2020, 08:54
by ophidon
I appreciate all the concepts on how to combat the frame miss flashing, and no, you're not talking over my head, but it might be beyond my abilities to implement in a reasonable timeframe as a hobby project currently since graphics/emulation development is so far outside of my normal business systems wheelhouse.

I believe currently, I'm going to clean up what I've done, since it is literally 99% there as far as what most people will want/need from it, and submit a PR to Retroarch proper. One actual notable change, besides the minor adjustments to try to reduce the flashing, I've made since the initial post is to disable BFI while in the menu. Not only is it just unnecessary there, but the obscene low hz flickering you could get if you set the BFI value wrong, or changed the refresh rate after setting it, could make it physically painful to navigate back to the setting to fix it.

After this initial submission, I'll work on combating the remaining flashing as I can, or maybe one of the long-term Retroarch devs could solve it much more quickly, but better to at least get the current 99% version out there, than to remain with nothing as solving this last problem could take orders of magnitude longer than the rest of it.

Re: RetroArch - Variable BFI Mod for 180Hz/240Hz/Etc

Posted: 16 Sep 2020, 13:03
by Chief Blur Buster
Yes, good points on hobby time versus work coding time. There are major diminishing returns for advanced coding tricks. If you're able to push it to once every 10 minutes for example --

Though slower systems might erratically flash every few seconds, which is when the tricks may come to play here.

And as refresh rates go higher (e.g. 1000Hz), the precision margins will likely require the techniques eventually. But this could be iteratively added later. Even the present-thread technique is useful (more accurate sync to VSYNC without blocking behaviours interfering) even if you ignore thread priorities, with that being dealt later.

Low-lying-apple adaptive/usability behaviours may be a more useful hobbyist-cleanup move (e.g. ignoring invalid BFI settings or automatically turning off BFI if the BFI strobes at too low frequency).

Re: RetroArch - Variable BFI Mod for 180Hz/240Hz/Etc

Posted: 16 Sep 2020, 13:45
by ophidon
Yes, that is a good point about system speed. I am running an 8700k at a constant 5ghz oc, so solved for my system will still probably be far from solved for weaker systems. (Though I bet the overlap of people with 240hz screens and older systems isn't very high at the moment.)

As for 1000hz screens in the future, as long as they don't remove the ability to run at 'low' Hz like 180 or 240, the issue should remain resolved if it can be with current technology. While I would certainly like to see a 1000 Hz display that could be bright enough at a 1/1000, or even 10/1000 frame pulses for amazing clarity, I remain doubtful that will -ever- exist. :D