Skip to content

libobs: Fix premultiplied sRGB source rendering - #13797

Open
SoprachevAK wants to merge 3 commits into
obsproject:masterfrom
SoprachevAK:fix/browser-premultiplied-srgb-blending
Open

libobs: Fix premultiplied sRGB source rendering#13797
SoprachevAK wants to merge 3 commits into
obsproject:masterfrom
SoprachevAK:fix/browser-premultiplied-srgb-blending

Conversation

@SoprachevAK

@SoprachevAK SoprachevAK commented Aug 17, 2026

Copy link
Copy Markdown

Description

Fixes rendering of sources that provide premultiplied sRGB textures and allows a source to request nonlinear blending as the initial blending method for its scene items.

This PR:

  • Adds DrawSrgbDecompressPremultiplied techniques to the default 2D and rectangle effects. The shader unpremultiplies the sampled RGB value, converts it from nonlinear sRGB to linear light, and premultiplies it again before linear compositing.
  • Propagates the scene item's linear-sRGB state while rendering a source into an intermediate texture, allowing custom-draw sources to select the correct rendering path for the active blending method.
  • Adds OBS_SOURCE_INITIAL_BLEND_METHOD_SRGB_OFF, which allows a source type to initialize newly created scene items with OBS_BLEND_METHOD_SRGB_OFF.
  • Migrates older scene items belonging to opted-in source types from OBS_BLEND_METHOD_DEFAULT to OBS_BLEND_METHOD_SRGB_OFF. Other source types and items already using another method are left unchanged.

This PR should be merged after #13790, which renames the user-facing blending methods from Default and SRGB Off to Linear and Nonlinear.

Companion obs-browser PR: obsproject/obs-browser#533

The obs-browser companion PR depends on this API and must ship in the same OBS release.

Important

Before this PR is merged, SRGB_OFF_INITIAL_BLEND_MIGRATION_VERSION must be set to the OBS version that first ships this migration:

/* TODO: Set to the OBS version that first ships this migration. */
#define SRGB_OFF_INITIAL_BLEND_MIGRATION_VERSION MAKE_SEMANTIC_VERSION(32, 2, 2)

The current value is temporary and must be updated or explicitly confirmed once the target release is known.

Motivation and Context

Chromium composites page content in nonlinear sRGB and provides OBS with premultiplied sRGB textures. Correctly supporting both OBS blending methods therefore requires two distinct rendering paths:

  • Linear must unpremultiply the encoded RGB values, convert them to linear light, and premultiply them again before compositing.
  • Nonlinear must preserve the Chromium-composited values and blend them without linear-sRGB processing.

OBS previously attempted to implement the correct premultiplied conversion in obs-studio#4935 (commit 05b507d) together with obs-browser#300 (commit aa3d36c).

That implementation was later replaced by obs-browser#318 (commit 94cbfba). The PR explicitly described the replacement as an attempt to preserve Chromium's RGB values that would work on a black background, while blending against other backgrounds would still happen in linear space and might not look correct.

The unused premultiplied conversion technique was subsequently removed in obs-studio#5360 (commit 4e6765a). Browser rendering was later switched to the sRGB texture sampling path by commit 344626c, but it continued to apply the sRGB transfer function to premultiplied RGB values.

Nonlinear blending was added afterward in obs-studio#6257 (commit e638cc9) primarily to reproduce browser compositing behavior. Browser sources were not automatically opted into it, however, and the earlier black-background workaround remained in place.

As a result, the current browser renderer does not provide a mathematically correct linear path. It approximates the Chromium/nonlinear appearance on a black background, but semi-transparent content can produce incorrect results when composited over other backgrounds. It also prevents users who deliberately select linear blending—for example, for visual effects or color-correct compositing—from receiving correct linear-light results.

This PR restores the correct premultiplied sRGB conversion needed by the linear method. The companion obs-browser change will use that path for linear blending and use the unconverted path for nonlinear blending.

Why migrate existing scene items?

Existing browser scene items are normally serialized with OBS_BLEND_METHOD_DEFAULT, but users have observed the appearance produced by the historical workaround. On black backgrounds that appearance approximates Chromium's nonlinear compositing.

After correcting the renderer, leaving those existing items on the now-correct linear method would visibly change their appearance. From the user's perspective, upgrading OBS would look like a rendering regression or downgrade, even though the new linear result is mathematically correct.

The migration preserves the established appearance by changing an older OBS_BLEND_METHOD_DEFAULT item to the source's requested nonlinear initial method when all of the following are true:

  • The source opts in through OBS_SOURCE_INITIAL_BLEND_METHOD_SRGB_OFF.
  • The scene collection was last saved by an OBS version older than the version that first ships the migration.
  • The item still uses OBS_BLEND_METHOD_DEFAULT.

Items already using OBS_BLEND_METHOD_SRGB_OFF, items belonging to other source types, and other blending settings are not changed. New opted-in sources start with nonlinear blending directly.

This provides a seamless upgrade for existing users while making both the linear and nonlinear paths correct and explicitly selectable.

How Has This Been Tested?

Manually tested on a MacBook Pro with an Apple M5 Pro running macOS 26.5.2, together with the companion obs-browser changes.

The test page contains four browser-background regions—transparent, black, white, and transparent—and renders:

  • Opaque white.
  • White at 75% and 25% opacity.
  • Red, green, and blue at 50% opacity.

index.html

OBS 32.2.1 was compared with the combined obs-studio and obs-browser branches using both blending methods and different scene backgrounds.

Verified that:

  • The linear method correctly converts the premultiplied browser texture before compositing.
  • Semi-transparent colors composite correctly over non-black backgrounds.
  • The nonlinear method preserves the appearance expected from Chromium compositing.
  • The nonlinear result is no longer approximated only for black backgrounds.
  • Switching between the two methods selects the corresponding browser rendering path.

OBS 32.2.1

Screenshot 2026-08-15 04-02-03

This PR with the companion obs-browser changes

Screenshot 2026-08-17 06-52-43

Types of changes

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)

Checklist:

  • I have read the contributing document.
  • My code has been run through clang-format.
  • My code follows the project's style guidelines
  • My code is not on the master branch.
  • My code has been tested.
  • All commit messages are properly formatted and commits squashed where appropriate.
  • I have included updates to all appropriate documentation.
  • AI tooling was used for research and autocomplete assistance (copilot). I personally wrote every submitted line of code, deliberately reviewed, understood, and verified it, and personally evaluated all architectural decisions and trade-offs.

Andrei Soprachev added 3 commits August 17, 2026 06:16
Add a default effect technique that converts premultiplied sRGB
textures to linear space.

Propagate the scene item's linear-sRGB state while rendering into an
intermediate texture so sources can select the appropriate draw path.
Add a source flag that initializes new scene items with
OBS_BLEND_METHOD_SRGB_OFF instead of OBS_BLEND_METHOD_DEFAULT. Browser
sources require nonlinear compositing to preserve their appearance.

Browser rendering previously used a workaround that made the linear
OBS_BLEND_METHOD_DEFAULT path resemble OBS_BLEND_METHOD_SRGB_OFF.
Existing browser items using OBS_BLEND_METHOD_DEFAULT therefore expect
the nonlinear appearance.

When loading older scene collections, migrate items belonging to
opted-in sources from OBS_BLEND_METHOD_DEFAULT to
OBS_BLEND_METHOD_SRGB_OFF. Leave all other blending methods unchanged.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant