Skip to content

libobs: Draw Darken sources over white so transparency keeps the background - #1406

Merged
zackees merged 2 commits into
obs-rust:masterfrom
rdoupe:fix/darken-transparent
Oct 18, 2026
Merged

zackees merged 2 commits into
obs-rust:masterfrom
rdoupe:fix/darken-transparent

Conversation

@rdoupe

@rdoupe rdoupe commented Oct 18, 2026 •

Copy link
Copy Markdown
Collaborator

Fixes #1404

What and why

A source set to Darken blending now leaves the background where it is transparent. Before, it drew black there and cut a hole in the scene's alpha (upstream obsproject/obs-studio#6591, reported by SuslikV; closed upstream as not planned, though the blend-mode author agreed it is a bug).

  • Darken uses GS_BLEND_OP_MIN, and Direct3D and OpenGL ignore the blend factors for MIN and MAX: each channel becomes min(source, destination) on premultiplied colour, and a transparent pixel (0, 0, 0, 0) always wins.
  • Darken items always render through their item texture (item_texture_enabled(): non-default blending). That texture is now cleared to opaque white instead of transparent black for Darken items, so the source is drawn over white. A transparent pixel becomes white with alpha 1 and the minimum keeps the background's colour and alpha. An opaque pixel is the same as before. A partly transparent pixel is darkened as the source over white would be, which is the workaround users were given upstream and on the forum (re-export the image on white).
  • Only Darken items change; every other blend mode clears as before.

Headless (private Xvfb, private D-Bus, fresh HOME), driven over obs-websocket: a light grey (209) colour source, a PNG over it whose left half is transparent and whose right half is opaque grey (128), scene screenshot:

Build Darken, transparent half Darken, opaque half Normal / Lighten / Multiply
v0.1.0-beta.20261014 AppImage 0, 0, 0, alpha 0 128 unchanged
master 3fa2833 0, 0, 0, alpha 0 (test: luma 16) 128 unchanged
This branch 209, 209, 209, alpha 1 128 unchanged (209 / 209 / 104 on the right)

RED → GREEN

  • RED: 9db475d test/cmocka: Add failing test for Darken over a transparent source. test_darken_transparent puts an opaque light grey background on the program and over it a box that is transparent in its left half and opaque darker grey in its right half, runs a raw video encoder on the program and compares each half's mean luma with Darken and with Normal (where the box is opaque it is darker than the background, so the two must agree). On master it fails 1 of 2: darken_keeps_background_where_transparent (left half luma 16 with Darken, 180 with Normal). Needs core video: runs under xvfb-run on Linux, skips without a display.
  • GREEN: e34bbce libobs: Draw Darken sources over white so transparency keeps the background. 2 of 2, three runs; test_scaled_mix_alpha (Subtract) still passes. Full build (C libobs lane) and full ctest -j4 (private Xvfb, private D-Bus, fresh HOME, system libobs-opengl masked): 304/304; the only skipped case is open_crashes_without_obs_core, as on master. The scene renderer is C in both libobs lanes.

Checklist

  • Base is master
  • I claimed the issue, or no one else has an open PR for it
  • Characterization test (if the unit had none), then RED, then GREEN commits
  • (Optional) Local gate passed and the pushed head is stamped; otherwise PR CI runs the full suite
  • Warning or flag changes (-W..., ratchets): none
  • Intentional differences from C listed in the parity test header and rust/README.md (ports): not a port

AI note: Claude Code (Claude Opus 5.5) wrote the code, the test, the commit messages and this text under the submitter's direction, and ran the tests above on the submitter's machines.

@rdoupe
rdoupe requested a review from zackees as a code owner October 18, 2026 08:17
@zackees
zackees added this pull request to the merge queue Oct 18, 2026
@github-merge-queue
github-merge-queue Bot removed this pull request from the merge queue due to a conflict with the base branch Oct 18, 2026
A source set to Darken blending draws black where it is transparent, and
its alpha punches a hole through the scene, instead of leaving the
background as it is (obsproject/obs-studio#6591, reported by SuslikV).

test_darken_transparent puts an opaque light grey background on the
program and over it a box that is transparent in its left half and an
opaque darker grey in its right half, runs a raw video encoder on the
program and compares the mean luma of each half with Darken and with
Normal blending. Where the box is opaque it is darker than the
background, so the two modes must agree.

Fails 1 of 2: darken_keeps_background_where_transparent (left half luma
16, black, with Darken; 180 with Normal). The Normal control passes.
Needs core video, so it runs under xvfb-run on Linux and skips without a
display.

Refs obs-rust#1404.
…ground

Darken draws the item's texture with GS_BLEND_OP_MIN, and Direct3D and
OpenGL ignore the blend factors for MIN and MAX: each channel becomes
min(source, destination) on premultiplied colour. A transparent source
pixel is (0, 0, 0, 0), so it always won: black in colour and 0 in alpha,
which also cut a hole through the scene (obsproject/obs-studio#6591).

Darken items always render through their item texture first. That
texture is now cleared to opaque white instead of transparent black for
them, so the source is drawn over white: a transparent pixel becomes
white with alpha 1, and the minimum keeps the background's colour and
alpha; an opaque pixel is the same as before. A partly transparent pixel
is darkened as the source over white would be, which is the workaround
users were given (export the image on white). Other blend modes are
unchanged.

test_darken_transparent: 2 of 2 (three runs). In the app, a half-
transparent PNG set to Darken over a grey background now shows the
background (209, 209, 209, alpha 1) in its transparent half instead of
(0, 0, 0, 0).

Fixes obs-rust#1404.
@rdoupe
rdoupe force-pushed the fix/darken-transparent branch from 4f105bc to e34bbce Compare October 18, 2026 16:08
@zackees
zackees enabled auto-merge October 18, 2026 16:13
@zackees
zackees added this pull request to the merge queue Oct 18, 2026
Merged via the queue into obs-rust:master with commit ba3fa64 Oct 18, 2026
23 checks passed
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.

bug: libobs: a source set to Darken blending draws black where it is transparent (upstream #6591)

2 participants