mamedev / mame

MAME
https://www.mamedev.org/
Other
7.95k stars 1.98k forks source link

Change B/C/G formula in render.cpp #5969

Open couriersud opened 4 years ago

couriersud commented 4 years ago

The current formula in render.cpp is not a fair representation of the physical order in the signal chain. Here's the current calculation.

    /* first apply gamma */
    srcval = pow(srcval, 1.0f / gamma);

    /* then contrast/brightness */
    srcval = (srcval * contrast) + brightness - 1.0f;

At this point in time 'RGB' values in mame represent voltage values at the video outputs. The displayed intensity can be expressed - given g is the gamma of the monitor - as:

I = pow(f(channel_voltage), g)

f represents brightness and contrast adjustment at the monitor:

f(v) = contrast * v + brightness

Modern pc graphic cards deliver sRGB to the monitor, the perceived intensity (i.e. the linear RGB value) is approximately

I = pow(channel_rgb, 2.2)

Thus

channel_rgb = pow(f(channel_voltage), g / 2.2)

Let ag = g / 2.2 denote the gamma adjustment to be applied.

Thus the formula in MAME actually should be

    // contrast/brightness
    srcval = (srcval * contrast) + brightness - 1.0f;

    // apply gamma 
    srcval = pow(srcval, gamma_adjustment);

This will have an impact on the commandline options and cfg files. I consider this change to be important. MAME is a documentation project, the current implementation does not represent the signal chain.

Alternatively we might not use "gamma adjustment", but the monitor gamma and default gamma to 2.2 resulting in the same default as now (1.0) and use gamma / 2.2.

In the final implementation we should use the exact formulas for srgb conversion. I have omitted those here for better readability.

galibert commented 4 years ago

That sounds incorrect. The channel voltage at the entry of a monitor is already in gamma 2.2 (roughly). And the monitor does the contrast/brightness adjustment in gamma space, not in linear space...

OG.

On Mon, Nov 25, 2019 at 11:13 PM couriersud notifications@github.com wrote:

The current formula in render.cpp is not a fair representation of the physical order in the signal chain. Here's the current calculation.

/ first apply gamma / srcval = pow(srcval, 1.0f / gamma);

/ then contrast/brightness / srcval = (srcval * contrast) + brightness - 1.0f;

At this point in time 'RGB' values in mame represent voltage values at the video outputs. The displayed intensity can be expressed - given g is the gamma of the monitor - as:

I = pow(f(channel_voltage), g)

f represents brightness and contrast adjustment at the monitor:

f(v) = contrast * v + brightness

Modern pc graphic cards deliver sRGB to the monitor, the perceived intensity (i.e. the linear RGB value) is approximately

I = pow(channel_rgb, 2.2)

Thus

channel_rgb = pow(f(channel_voltage), g / 2.2)

Let ag = g / 2.2 denote the gamma adjustment to be applied.

Thus the formula in MAME actually should be

// contrast/brightness srcval = (srcval * contrast) + brightness - 1.0f;

// apply gamma srcval = pow(srcval, gamma_adjustment);

This will have an impact on the commandline options and cfg files. I consider this change to be important. MAME is a documentation project, the current implementation does not represent the signal chain.

Alternatively we might not use "gamma adjustment", but the monitor gamma and default gamma to 2.2 resulting in the same default as now (1.0) and use gamma / 2.2.

In the final implementation we should use the exact formulas for srgb conversion. I have omitted those here for better readability.

— You are receiving this because you are subscribed to this thread. Reply to this email directly, view it on GitHub https://github.com/mamedev/mame/issues/5969?email_source=notifications&email_token=ACGSF4PY2FK5KYL7KBN5VIDQVREW3A5CNFSM4JRPOZIKYY3PNVWWK3TUL52HS4DFUVEXG43VMWVGG33NNVSW45C7NFSM4H36HUQQ, or unsubscribe https://github.com/notifications/unsubscribe-auth/ACGSF4OK7XSNMARFTGUIYILQVREW3ANCNFSM4JRPOZIA .

couriersud commented 4 years ago

Here's the schematics of an EZV: It just expects a voltage which is linearily (f(x)=ax+b) converted. https://www.arcade-museum.com/manuals-monitors/sanyo-ezv20rc.pdf This signal then in the tube is transformed into light using the transform G(x)=(f(x))^g where g is the monitor gamma (approx ~2.2, for 80s monitor literature states 1.6 to 3). Now the human eye has a gamma as well. This is approx. 0.4: E(y)=y^0.4 0.4*2.2 is approx 0.9 and thus the human eye roughly eliminates monitor gamma.

Here's some reading material:

http://poynton.ca/notes/colour_and_gamma/GammaFAQ.html (see bullet point 16)

http://web.mit.edu/jmorzins/www/gamma/rwb/gamma.html https://en.wikipedia.org/wiki/SRGB#The_sRGB_transfer_function_(%22gamma%22)

And here is an article why all our screen filtering chains and color mixing is just wrong: https://learnopengl.com/Advanced-Lighting/Gamma-Correction In a nutshell: colormetry math works in linear RGB, it fails if fed with sRGB.

couriersud commented 4 years ago

And another link ... with some rendering examples: https://medium.com/@Jacob_Bell/programmers-guide-to-gamma-correction-4c1d3a1724fb