Page MenuHomePhabricator

Bug 1977746 - display HDR video on Windows using RGB10A2
ClosedPublic

Authored by ahale on Oct 14 2025, 8:25 AM.
Referenced Files
Unknown Object (File)
Thu, Jan 22, 5:46 AM
Unknown Object (File)
Mon, Jan 19, 6:44 PM
Unknown Object (File)
Tue, Jan 13, 6:16 PM
Unknown Object (File)
Tue, Jan 13, 12:54 PM
Unknown Object (File)
Tue, Jan 13, 10:09 AM
Unknown Object (File)
Mon, Jan 12, 3:01 PM
Unknown Object (File)
Sun, Jan 11, 9:22 PM
Unknown Object (File)
Sun, Jan 11, 10:47 AM

Details

Summary

This adds support for MFVideoFormat_P010 and MFVideoFormat_A2R10G10B10
in a number of places (both WMF and DVXA2 code paths with ffmpeg).

This advertises that we support HDR to JavaScript so video players can
detect our support if the window is on an HDR display at the time.

This adds comments for several poorly documented parts of the code that
I had to figure out. It changes fallback logic for selecting a WMF
video subtype to do what the code was clearly meant to do (e.g. fall
back from P010 to NV12 or YV12 depending on hw vs sw decode).

Zero copy decode is not supported by this patch, but can be
implemented in a follow-up bug.

HDR videos are now automatically flagged as promoted surfaces more
aggressively than for video in general, because WebRender does not
currently have the ability to do regular CSS/SVG compositing of HDR
video, so we definitely do want it to be a compositor surface if
possible - this is still subject to the MAX_COMPOSITOR_SURFACES limit in
WebRender, so a document with more than 2 or 3 HDR videos will have a
bad time, that is worth fixing in a follow-up bug, and we still don't
have HDR CSS rendering in WebRender as mentioned so any clipmasks will
usually prevent surface promotion for HDR videos, the same goes for
any CSS filter effects or SVG filter primitives applied to a video.

IsHDRTransferFunction() was added to check if a gfx::TransferFunction is
one of the HDR ones (PQ or HLG), but currently TextureHost does not have
any easy way to get the gfx::TransferFunction to DCLayerTree to make a
decision to display it as HDR, so DCLayerTree code is assuming that any
video with BT2020 colorspace is HDR (this is the same assumption we made
on macOS, it has proven surprisingly robust) - it would be good to clean
that up by properly plumbing TransferFunction through TextureHost, which
could be useful for future code paths like HDR canvas and images.

Tests are not added by this patch because properly testing HDR video
would rely heavily on features not currently implemented in WebRender
and ImageLib for reftests to work with high dynamic range colors, we
have already been shipping HDR video on macOS for a while without tests,
so this is not meaningfully different. A proper test suite is planned
in 2026 as a major project that depends on those other moving parts.

Event Timeline

There are a very large number of changes, so older changes are hidden. Show Older Changes
dom/media/platforms/ffmpeg/FFmpegVideoDecoder.cpp
2405–2406

nits : let's print the value of isHDR in logging.

dom/media/platforms/wmf/MFTDecoder.cpp
45

We can remove aFallbackSubType here as it's not used at all.

dom/media/platforms/wmf/MFTDecoder.h
40

Update the comment for functions as well, same for below.

dom/media/platforms/wmf/WMFVideoMFTManager.cpp
267

Same here, if HDR is not supported in zero copy, we should add a comment to explicitly explain why it can't be supported.

329–334

Print mIsHDR as well.

818–852

This comment seems implying that HDR has the lowest priority, which is wrong. Put HDR above if HW....

826

Align these three FAILED(...).

865–867

As ConfigureForSize will set the output type to MFVideoFormat_P010 when mIsHDR is true , but if the decoder output type is set to MFVideoFormat_NV12/MFVideoFormat_YV12 or even MFVideoFormat_P016, what will happen when those two types are unmatched?

Maybe we should instead let ConfigureForSize knows what format it should set?

ahale requested review of this revision.Nov 22 2025, 6:55 AM
ahale updated this revision to Diff 1161321.
ahale edited the summary of this revision. (Show Details)
ahale marked an inline comment as done.
ahale marked 3 inline comments as done.

Code analysis found 6 defects in diff 1161322:

  • 3 defects found by clang-format
  • 3 defects found by clang-format (Mozlint)
WARNING: Found 6 defects (warning level) that can be dismissed.

You can run this analysis locally with:

  • ./mach clang-format -p dom/media/platforms/wmf/MFTDecoder.h dom/media/platforms/ffmpeg/FFmpegVideoDecoder.cpp dom/media/platforms/wmf/WMFVideoMFTManager.cpp
  • ./mach lint --warnings --outgoing

For your convenience, here is a patch that fixes all the clang-format defects (use it in your repository with hg import or git apply -p0).


If you see a problem in this automated review, please report it here.

You can view these defects in the Diff Detail section of Phabricator diff 1161322.

ahale added inline comments.
dom/media/platforms/ffmpeg/FFmpegVideoDecoder.cpp
753

Short answer - no. I was going off of the comments text here and I honestly don't know what this does, only that I encountered it when debugging. I'll see if it works the same without this change.

Seems to work the same so I have removed this change.

2389–2392

I tried to make zerocopy work but I am not totally sure I understand how it functions, it's worth noting that dcomp can't display DXGI_FORMAT_P010 with DXGI_COLOR_SPACE_YCBCR_STUDIO_G2084_LEFT_P2020, so if the 'copy' refers to converting from P010 to RGB10A2 then we need the copy, if the copy is some other part of the processing then we may not, I can say that the zerocopy code has an awful lot of mentions of NV12 in it so it looked possibly non-trivial to upgrade.

It's worth noting that I tried requesting decode to subtype MFVideoFormat_A2B10G10R10 and it could not find find a matching decoder, at least on AMD. I haven't tried other vendors to confirm if others might be able to skip a step.

dom/media/platforms/wmf/MFMediaEngineDecoderModule.cpp
146 ↗(On Diff #1155134)

I've found that I no longer use aFallbackSubType in MFTDecoder::Create so I've removed this change.

dom/media/platforms/wmf/WMFAudioMFTManager.cpp
133

SetMediaTypes takes a aFallbackSubType, which implements the previously internal fallback to MFAudioFormat_Float in this case, so no change in behavior but this is now controlled by the caller.

dom/media/platforms/wmf/WMFVideoMFTManager.cpp
267

I'm not completely certain that it can't, it depends what zerocopy is actually trying to do - if it's skipping a copy of a processing buffer then that probably can work, but if it's skipping the MFVideoFormat_P010->MFVideoFormat_A2B10G10R10 conversion (which is necessary) then it can't support HDR.

818–852

I don't follow? I was preserving the existing behavior, which always tried NV12/YV12 first, it never even attempted P010 or P016 because of the behavior of MFTDecoder::SetDecoderOutputType.

826

Refactored to actually shorten the logic now that I made GUID_NULL a valid thing to pass as aFallbackSubType, so that this logic can actually work for the first time - previously before my changes in this patch only the first one mattered since it would never fail as all fallback logic is inside MFTDecoder::SetDecoderOutputType.

gfx/layers/DcompSurfaceImage.cpp
68

I assume this is resolved then.

gfx/layers/d3d11/TextureD3D11.cpp
480–528

Okay, I've reduced it to that subset and added a gfxCriticalNote to indicate if this is reached.

gfx/webrender_bindings/DCLayerTree.cpp
2767

I will be doing that minor refactor soon.

ahale marked 3 inline comments as done.

Code analysis found 9 defects in diff 1161324:

  • 4 defects found by clang-format
  • 5 defects found by clang-format (Mozlint)
WARNING: Found 9 defects (warning level) that can be dismissed.

You can run this analysis locally with:

  • ./mach clang-format -p dom/media/platforms/wmf/MFTDecoder.h gfx/layers/d3d11/TextureD3D11.cpp dom/media/platforms/ffmpeg/FFmpegVideoDecoder.cpp dom/media/platforms/wmf/WMFVideoMFTManager.cpp
  • ./mach lint --warnings --outgoing

For your convenience, here is a patch that fixes all the clang-format defects (use it in your repository with hg import or git apply -p0).


If you see a problem in this automated review, please report it here.

You can view these defects in the Diff Detail section of Phabricator diff 1161324.

ahale edited the summary of this revision. (Show Details)

Code analysis found 8 defects in diff 1162214:

  • 4 defects found by clang-format
  • 4 defects found by clang-format (Mozlint)
WARNING: Found 8 defects (warning level) that can be dismissed.

You can run this analysis locally with:

  • ./mach clang-format -p gfx/layers/d3d11/TextureD3D11.cpp dom/media/platforms/ffmpeg/FFmpegVideoDecoder.cpp dom/media/platforms/wmf/WMFVideoMFTManager.cpp dom/media/platforms/wmf/MFTDecoder.h
  • ./mach lint --warnings --outgoing

For your convenience, here is a patch that fixes all the clang-format defects (use it in your repository with hg import or git apply -p0).


If you see a problem in this automated review, please report it here.

You can view these defects in the Diff Detail section of Phabricator diff 1162214.

We need a high level explanation of what, why and how this patch does things in the commit message.

dom/media/platforms/wmf/WMFVideoMFTManager.cpp
223–226

It's usually better to not uselessly duplicate state when it can be a method.

bool IsHDR() const {
  gfx::TransferFunction transferFunction =
    mVideoInfo.mTransferFunction.refOr(gfx::TransferFunction::BT709);
  return (transferFunction == gfx::TransferFunction::PQ ||
              transferFunction == gfx::TransferFunction::HLG);
}
dom/media/platforms/ffmpeg/FFmpegVideoDecoder.cpp
2389–2392

@sotaro could you help us clarify the zero copy a little bit? will it be able to support HDR? Thanks!

dom/media/platforms/wmf/WMFVideoMFTManager.cpp
818–852

Sorry for not being clear earlier. I just meant that the new comment form (if XXX...) is a bit confusing, as it gives me an impression that we would check HW first, then SW, and HDR last.

Maybe rephrase it as: Note: we will check P010/P016 first if HDR is preferred.

865–867

This is still not addressed yet.

ahale marked an inline comment as done.

Code analysis found 8 defects in diff 1166903:

  • 2 defects found by clang-format
  • 6 defects found by clang-format (Mozlint)
WARNING: Found 8 defects (warning level) that can be dismissed.

You can run this analysis locally with:

  • ./mach lint --warnings --outgoing
  • ./mach clang-format -p dom/media/platforms/wmf/DXVA2Manager.cpp dom/media/platforms/wmf/WMFVideoMFTManager.h

For your convenience, here is a patch that fixes all the clang-format defects (use it in your repository with hg import or git apply -p0).


If you see a problem in this automated review, please report it here.

You can view these defects in the Diff Detail section of Phabricator diff 1166903.

ahale added inline comments.
dom/media/platforms/wmf/WMFVideoMFTManager.cpp
223–226

I've moved this logic to a static inline function in gfx/2d/Types.h called IsHDRTransferFunction, and also added a convenience method WMFVideoMFTManager::IsHDR to avoid duplicating the rather verbose call of IsHDRTransferFunction(mVideoInfo.mTransferFunction.refOr(gfx::TransferFunction::BT709)) where it cares about that.

This also could be called in DCLayerTree once the mTransferFunction is plumbed through the TextureHost stuff in future, which would let us decide if it is an HDR texture rather than speculating that BT2020 is always HDR (which is not true from a spec standpoint but from a videos-found-in-the-wild perspective seems to be universally true as we've been shipping that assumption for macOS HDR video for some time now).

I hope that resolves the concern?

818–852

Okay, I've replaced the comment with a more detailed explanation of rationale with HDR vs SDR as the top level decision for the two fallback sequences, and also added an explanation for the use of GUID_NULL and what that does in MFTDecoder::SetDecoderOutputType.

865–867

I'm going to think a bit about how to address this. Thanks for highlighting it.

My understanding of the video pipeline being pretty vague here - I've written video codecs from scratch before and I understand the multi-stage transforms that typically occur in a video decode pipeline, but I'm not sure what parts of the pipeline each of these choices represents in context of WMF and DVXA2, I've been assuming the choice here is picking what the stream decoder will output (so typically a YUV format), and the choice in ConfigureForSize is the target YUV/RGB format to blit that into when we wrap it in TextureHost to send on to DCLayerTree to put in a compositor swapchain.

ahale marked 2 inline comments as done.

Code analysis found 8 defects in diff 1166927:

  • 2 defects found by clang-format
  • 6 defects found by clang-format (Mozlint)
WARNING: Found 8 defects (warning level) that can be dismissed.

You can run this analysis locally with:

  • ./mach clang-format -p dom/media/platforms/wmf/DXVA2Manager.cpp dom/media/platforms/wmf/WMFVideoMFTManager.h
  • ./mach lint --warnings --outgoing

For your convenience, here is a patch that fixes all the clang-format defects (use it in your repository with hg import or git apply -p0).


If you see a problem in this automated review, please report it here.

You can view these defects in the Diff Detail section of Phabricator diff 1166927.

ahale marked 5 inline comments as done.
ahale edited the summary of this revision. (Show Details)
ahale edited the summary of this revision. (Show Details)
ahale edited the summary of this revision. (Show Details)
dom/media/platforms/ffmpeg/FFmpegVideoDecoder.cpp
2389–2392

Per discussion with Sotaro on Matrix, yes zerocopy can work, it involves passing around the decoder output buffer rather than making an internal copy to pass to the color transform, so I'll look into making it work, the code path looks non-trivial to understand and it has an obsession with NV12 so it will take a bit to rework that.

I'd prefer to put zerocopy in as a separate patch because it's not necessary for the feature to work, but does improve performance., so if it causes regressions I'd prefer it be rolled back separately.

dom/media/platforms/wmf/WMFVideoMFTManager.cpp
267

Per discussion with Sotaro, zerocopy is just avoiding an unnecessary copy of a processing buffer on the GPU, so it definitely can support HDR. However zerocopy is currently coded in a way that only works with NV12 and I'm not sure refactoring it should be in scope for this patch. So I am focusing on adding relevant comments to indicate it could be done but isn't yet.

865–867

After looking over this carefully, I removed the subtype override in ConfigureForSize, and changed the output format choices to RGB10A2 and BGRA8. I verified that there's no situation where the subtype coming into ConfigureForSize mismatches the incoming video type.

Thank a lot for this! r+ for media part.

dom/media/platforms/wmf/DXVA2Manager.cpp
1056

nits : add TODO for MFVideoFormat_A16B16G16R16F.

TODO : For HDR with alpha...

1067

Could you file a follow-up bug to remove mTransform? It’s no longer used for color conversion, which is now handled by the video processor. Given this, I think we can safely remove this function call.

1094

These subtypes are different from the comment in line #945-948. Update the comment above.

dom/media/platforms/wmf/WMFUtils.cpp
137

Since I don’t see any usage of MFVideoFormat_I420 or MFVideoFormat_YUY2, do we still need them? Or are they primarily kept for logging purposes when encountering these formats?

dom/media/platforms/wmf/WMFVideoMFTManager.cpp
262

Could you file a follow up bug and add the bug number here? Thanks!

330

What will happen in this case? Will we use a normal surface to display HDR video, and will it be processed correctly as HDR in the graphics pipeline?

bradwerth added inline comments.
gfx/webrender_bindings/DCLayerTree.cpp
448

This can be removed, and I think it should be.

sotaro added inline comments.
gfx/layers/d3d11/TextureD3D11.cpp
525

It might be better to use gfxCriticalNoteOnce since the error log could be noisy.

This revision is now accepted and ready to land.Jan 6 2026, 12:35 AM
ahale marked 8 inline comments as done.