Use RGBA16F for feedback texrenders to fix 8-bit precision loss in self-feedback shaders - #106
Open
h-e-d-o-n wants to merge 1 commit into
Open
Conversation
create_or_reset_texrender() hardcoded gs_texrender_create(GS_RGBA, ...) for input_texrender, previous_input_texrender, output_texrender, and previous_output_texrender. Any shader that feeds a texrender's own output back into itself via previous_image/previous_output (e.g. value *= 0.99 each frame to decay/accumulate something) gets stuck at an 8-bit UNORM rounding fixed point instead of continuing to converge, since 8-bit round-tripping through the render target quantizes the value back up before the next frame's multiply can move it further. Switch the shared texrender format to GS_RGBA16F, matching the format libobs already prefers for HDR/extended color spaces elsewhere in this file (gs_get_format_from_space()). This does not depend on the source's own color space - a plain SRGB source still needs float precision in the feedback loop even though gs_get_format_from_space() would return 8-bit GS_RGBA for it.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
create_or_reset_texrender()hardcodesgs_texrender_create(GS_RGBA, GS_ZS_NONE)(8-bit UNORM) for all four ping-pong feedback texrenders:input_texrender,previous_input_texrender,output_texrender,previous_output_texrender.Any shader that reads its own previous output back through
previous_image/previous_outputand applies a small per-frame change — accumulating a value, or decaying it by a fraction each frame — gets stuck at an 8-bit UNORM rounding fixed point instead of continuing to converge. This is a general correctness issue for any self-feedback shader with fine gradients, not tied to any specific effect.How it was measured
A minimal test shader seeds a state to 1.0 and multiplies it by 0.99 every frame, reading the value back from
previous_output. On stock obs-shaderfilter (OBS Studio 32.2.1-6, obs-shaderfilter 2.6.0, Linux) the state decayed249 → 202 → 159 → 133 → 110 → 87 → 65 → 49and then got stuck at exactly 50/255 for 2468 consecutive frames (82.3s) and never moved again. That's the 8-bit UNORM round-trip fixed point:50 * 0.99 = 49.5, which rounds straight back to50.The fixed point isn't specific to 0.99 — any self-feedback loop with a multiplicative or additive step small enough to round away at 8 bits will converge to some non-zero rounding floor instead of the mathematically correct limit.
Notably,
gs_get_format_from_space()is already called elsewhere in this file (get_input_source(),draw_output(), and the per-source-param texrender at line ~3091) to pick a float format for HDR/extended color spaces — but that path only returns a float format when the source itself is HDR. For an ordinary SRGB source (the common case),gs_get_format_from_space(GS_CS_SRGB)returns plain 8-bitGS_RGBA, so threading that value intocreate_or_reset_texrender()would not have fixed the measured bug for typical content — the feedback loop needs float precision independent of the source's own color space.Fix
Switch the one shared
gs_texrender_create()call increate_or_reset_texrender()fromGS_RGBAtoGS_RGBA16F. This is a minimal, single hardcoded-constant change — no new parameters, no behavior change to anything else in the file.What was and wasn't verified
obs-shaderfilter.ccompiles cleanly (gcc -std=gnu17 -Wall -Wextra) against the real, installed OBS Studio 32.2.2 SDK headers (libobs.so.30) on the machine this was developed on, with zero new warnings versus the unmodified file.libobs(viafind_package(libobs)) succeeds and produces a workingobs-shaderfilter.sothat links correctly againstlibobs.so.30and exportsobs_module_load/obs_module_get_string/etc. (One unrelated pre-existing warning inload_shader_from_file()— aconst-qualifier discard at thestrrchr(file_name, '/')call, line ~299, present inmasterbefore this change — had to be demoted from the SDK's-Werrorto build cleanly on a newer GCC; it is untouched by and unrelated to this PR, called out here rather than silently worked around.)GS_RGBA16Ftexrenders in this plugin has not been observed on-screen.Scope
Single hardcoded constant changed in one function. No other files touched.