Advertisement

DX12 Swapchain gamma correction

Started by June 10, 2020 01:49 PM
6 comments, last by 21st Century Moose 4 years, 7 months ago

Is gamma correction supposed to work with DX12 swapchains?

The following code snippet works with DX11:

IDXGIOutput* pOutput = NULL;
swapchainData.pSwapChain->GetContainingOutput (&pOutput);
if (pOutput != NULL) {

	DXGI_GAMMA_CONTROL_CAPABILITIES gammaCaps;
	if (pOutput->GetGammaControlCapabilities (&gammaCaps) == S_OK) {

		bool hasGammaramp = (pOutput->GetGammaControl (&swapchainData.defaultGammaControl) == S_OK);
		swapchainData.hasDefaultGammaControl = hasGammaramp;
	}
	pOutput->Release ();
}

But not with DX12.
GetGammaControlCapabilities should return no error when the swapchain is in fullscreen mode but I always get DXGI_ERROR_INVALID_CALL (0x887A0001) for both of my adapters attached to different display outputs.

Experimentally I even put a GetGammaControlCapabilities call into one of the MS DX12 sample app and got the same result.

Did I miss something in the DX docs??

My understanding is that fullscreen is essentially deprecated as far as DX12 is concerned, and the runtime will basically emulate it for you if you request a fullscreen swap chain. The “modern” way to do it on Windows 10 is to simply create a borderless window that covers the entire screen, in which case your swap chain will get promoted into direct flip mode which bypasses the compositor and gives you the same performance/latency benefits that you would get from exclusive fullscreen. I'm honestly not sure how that all interacts with the gamma ramp stuff, but I wouldn't be surprised if that's also gone out the window (hah!) for DX12. You may want to try asking about it on the official DirectX discord channel to see if someone from the team knows how that works.

Advertisement

The old gamma ramp APIs always had several shortcomings: they affected the full screen, even in windowed modes, they affected other programs too, and if a program crashed it would leave you with adjusted gamma.

For a modern program I'd suggest implementing gamma as a post-processing step in a shader.

Direct3D has need of instancing, but we do not. We have plenty of glVertexAttrib calls.

Thx Guys for your replies!

Yes, old gamma API's suffered from those side effects, however, with DXGI this is handled nicely (in theory and according to my experiences). An app can overtake the physical gamma ramp only for the period while it's in fullscreen state. As soon as the swapchain is switched (or forced by the DXGI watchdog) into windowed mode, the original (user defined) gamma ramp is restored. So, I can't see any reason why it couldn't work with DX12.
I sort of have the same feeling about the fact that DX12 only supports FLIP-mode swapchains ending up in fake fullscreen mode, but, even if DWM is active while in fullscreen, no other stuff than the driving app's window can appear on the particular display output (the swapchain gets forced back to windowed mode otherwise), so I still cannot understand why it's not allowed to ‘corrupt’ the gamma ramp.
Maybe because of things like potentially enabled OS-wide ‘night light’ and appearing messages from the notification center?
When designing DXGI back in the Win7 days, those weren't a thing so they have to enable it for DX11 but not for any other newer API's like DX12?

Anyway, I could do the gamma correction by a post-process shader but I wouldn't like to waste any GPU power for that. Especially with low-end GPU's like and integrated Intel.

IIRC DXGI gamma only applies to fullscrene modes so while it is more robust than the older APIs there, it still doesn't provide a solution for windowed modes.

With shader-based gamma, if you already have some post-processing passes it should be possible to bake gamma in as an additional step. Otherwise I'd still suggest you set it up and bench it, it's surprisingly faster than you might think, and does provide a robust solution in all modes.

Direct3D has need of instancing, but we do not. We have plenty of glVertexAttrib calls.

That's what I already do when running in windowed mode.
I benchmarked it in fullscreen earlier and I remember a particular case when I lost ~100 fps from ~2200 at 2560x1400 with a GTX 1060 (ok, it may sound ridiculous but..).

I will have no other choice though, meanwhile it's confirmed from the D3D team: not supported.

Advertisement

D11thDev said:

That's what I already do when running in windowed mode.
I benchmarked it in fullscreen earlier and I remember a particular case when I lost ~100 fps from ~2200 at 2560x1400 with a GTX 1060 (ok, it may sound ridiculous but..).

That's 0.02 milliseconds if I make it right; I think almost any body's frametime budget could tolerate that.

Direct3D has need of instancing, but we do not. We have plenty of glVertexAttrib calls.

This topic is closed to new replies.

Advertisement