Grab the Extended Display Identifier Data there are numerous of ways to get this but I just used xrandr --props
here, and stored it in a file. It’ll be used to get the color-characteristics but it is theoretically better to get these color characteristics from an ICC profile if possible.
DP-0 connected primary 2560x1440+0+0 (normal left inverted right x axis y ax, s) 59x 336mm
_MUTTER_PRESENTATION_OUTPUT: 0
CTM: -714877597 0 72646571 0 11403438 -2147483648 199691239 0 -221842746 0 22085969 0 53019433 0 213060787 0 -266080221 0
CscMatrix: 54627 11083 -174 0 3047 62150 337 0 809 3251 61475 0
EDID:
00ffffffffffff001e6d7f5b22580300
041f0104b53c22789f8cb5af4f43ab26
0e5054254b007140818081c0a9c0b300
d1c08100d1cf09ec00a0a0a067503020
3a0055502100001a000000fd003090e6
e63c010a202020202020000000fc004c
4720554c545241474541520a000000ff
003130344e54445636463137300a01c7
02030f712309060746100403011f136f
c200a0a0a0555030203a005550210000
1a565e00a0a0a0295030203500555021
00001a5aa000a0a0a0465030203a0055
50210000000000000000000000000000
00000000000000000000000000000000
00000000000000000000000000000000
00000000000000000000000000000060
BorderDimensions: 4
supported: 4
Border: 0 0 0 0
range: (0, 65535)
SignalFormat: DisplayPort
supported: DisplayPort
ConnectorType: DisplayPort
ConnectorNumber: 2
_ConnectorLocation: 2
non-desktop: 0
supported: 0, 1
2560x1440 143.97*+ 120.00 99.95 59.95
1920x1080 74.91 60.00 59.94 50.00
1680x1050 59.95
1600x900 60.00
1280x1024 75.02 60.02
1280x800 59.81
1280x720 60.00 59.94 50.00
1152x864 59.96
1024x768 75.03 60.00
800x600 75.00 60.32
720x480 59.94
640x480 75.00 59.94 59.93
Decode the file using any edid-decoder. The one here called edid-decode has an online version.
edid-decode [path-to-file]
The decoded edid should result in something like this
edid-decode (hex):
00 ff ff ff ff ff ff 00 1e 6d 7f 5b 22 58 03 00
04 1f 01 04 b5 3c 22 78 9f 8c b5 af 4f 43 ab 26
0e 50 54 25 4b 00 71 40 81 80 81 c0 a9 c0 b3 00
d1 c0 81 00 d1 cf 09 ec 00 a0 a0 a0 67 50 30 20
3a 00 55 50 21 00 00 1a 00 00 00 fd 00 30 90 e6
e6 3c 01 0a 20 20 20 20 20 20 00 00 00 fc 00 4c
47 20 55 4c 54 52 41 47 45 41 52 0a 00 00 00 ff
00 31 30 34 4e 54 44 56 36 46 31 37 30 0a 01 c7
02 03 0f 71 23 09 06 07 46 10 04 03 01 1f 13 6f
c2 00 a0 a0 a0 55 50 30 20 3a 00 55 50 21 00 00
1a 56 5e 00 a0 a0 a0 29 50 30 20 35 00 55 50 21
00 00 1a 5a a0 00 a0 a0 a0 46 50 30 20 3a 00 55
50 21 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 60
----------------
Block 0, Base EDID:
EDID Structure Version & Revision: 1.4
Vendor & Product Identification:
Manufacturer: GSM
Model: 23423
Serial Number: 219170
Made in: week 4 of 2021
Basic Display Parameters & Features:
Digital display
Bits per primary color channel: 10
DisplayPort interface
Maximum image size: 60 cm x 34 cm
Gamma: 2.20
DPMS levels: Standby
Supported color formats: RGB 4:4:4, YCrCb 4:4:4, YCrCb 4:2:2
Default (sRGB) color space is primary color space
First detailed timing includes the native pixel format and preferred refresh rate
Display is continuous frequency
Color Characteristics:
Red : 0.6855, 0.3085
Green: 0.2646, 0.6679
Blue : 0.1503, 0.0576
White: 0.3134, 0.3291
Established Timings I & II:
DMT 0x04: 640x480 59.940476 Hz 4:3 31.469 kHz 25.175000 MHz
DMT 0x06: 640x480 75.000000 Hz 4:3 37.500 kHz 31.500000 MHz
DMT 0x09: 800x600 60.316541 Hz 4:3 37.879 kHz 40.000000 MHz
DMT 0x0b: 800x600 75.000000 Hz 4:3 46.875 kHz 49.500000 MHz
DMT 0x10: 1024x768 60.003840 Hz 4:3 48.363 kHz 65.000000 MHz
DMT 0x12: 1024x768 75.028582 Hz 4:3 60.023 kHz 78.750000 MHz
DMT 0x24: 1280x1024 75.024675 Hz 5:4 79.976 kHz 135.000000 MHz
Standard Timings:
GTF : 1152x864 60.000000 Hz 4:3 53.700 kHz 81.624000 MHz
DMT 0x23: 1280x1024 60.019740 Hz 5:4 63.981 kHz 108.000000 MHz
DMT 0x55: 1280x720 60.000000 Hz 16:9 45.000 kHz 74.250000 MHz
DMT 0x53: 1600x900 60.000000 Hz 16:9 60.000 kHz 108.000000 MHz (RB)
DMT 0x3a: 1680x1050 59.954250 Hz 16:10 65.290 kHz 146.250000 MHz
DMT 0x52: 1920x1080 60.000000 Hz 16:9 67.500 kHz 148.500000 MHz
DMT 0x1c: 1280x800 59.810326 Hz 16:10 49.702 kHz 83.500000 MHz
GTF : 1920x1080 75.000068 Hz 16:9 84.600 kHz 220.637000 MHz
Detailed Timing Descriptors:
DTD 1: 2560x1440 143.973257 Hz 16:9 222.151 kHz 604.250000 MHz (597 mm x 336 mm)
Hfront 48 Hsync 32 Hback 80 Hpol P
Vfront 3 Vsync 10 Vback 90 Vpol N
Display Range Limits:
Monitor ranges (Bare Limits): 48-144 Hz V, 230-230 kHz H, max dotclock 600 MHz
Display Product Name: 'LG ULTRAGEAR'
Display Product Serial Number: '104NTDV6F170'
Extension blocks: 1
Checksum: 0xc7
----------------
Block 1, CTA-861 Extension Block:
Revision: 3
Basic audio support
Supports YCbCr 4:4:4
Supports YCbCr 4:2:2
Native detailed modes: 1
Audio Data Block:
Linear PCM:
Max channels: 2
Supported sample rates (kHz): 48 44.1
Supported sample sizes (bits): 24 20 16
Video Data Block:
VIC 16: 1920x1080 60.000000 Hz 16:9 67.500 kHz 148.500000 MHz
VIC 4: 1280x720 60.000000 Hz 16:9 45.000 kHz 74.250000 MHz
VIC 3: 720x480 59.940060 Hz 16:9 31.469 kHz 27.000000 MHz
VIC 1: 640x480 59.940476 Hz 4:3 31.469 kHz 25.175000 MHz
VIC 31: 1920x1080 50.000000 Hz 16:9 56.250 kHz 148.500000 MHz
VIC 19: 1280x720 50.000000 Hz 16:9 37.500 kHz 74.250000 MHz
Detailed Timing Descriptors:
DTD 2: 2560x1440 119.997589 Hz 16:9 182.996 kHz 497.750000 MHz (597 mm x 336 mm)
Hfront 48 Hsync 32 Hback 80 Hpol P
Vfront 3 Vsync 10 Vback 72 Vpol N
DTD 3: 2560x1440 59.950550 Hz 16:9 88.787 kHz 241.500000 MHz (597 mm x 336 mm)
Hfront 48 Hsync 32 Hback 80 Hpol P
Vfront 3 Vsync 5 Vback 33 Vpol N
DTD 4: 2560x1440 99.946436 Hz 16:9 150.919 kHz 410.500000 MHz (analog composite, sync-on-green, 597 mm x 336 mm)
Hfront 48 Hsync 32 Hback 80 Hpol N
Vfront 3 Vsync 10 Vback 57 Vpol N
Checksum: 0x60 Unused space in Extension Block: 58 bytes
Relevant bit is the Color-Characteristics
values:
Color Characteristics:
Red : 0.6855, 0.3085
Green: 0.2646, 0.6679
Blue : 0.1503, 0.0576
White: 0.3134, 0.3291
Subsequent program.cs
script converts the provided matrix to an RGB matrix, the math is here. The input format is Rxy Gxy Bxy
.
dotnet run 0.6855 0.3085 0.2646 0.6679 0.1503 0.0576
// program.cs
using System;
using System.Globalization;
using System.Threading;
using MathNet.Numerics.LinearAlgebra;
namespace CscMatrixCalculator {
class Program {
// credit to for the math
public struct Point {
public double X;
public double Y;
}
public struct ColorSpace {
public Point Red;
public Point Green;
public Point Blue;
public Point White;
}
public static Point D65 = new (){ X = 0.312713, Y = 0.329016 };
public static ColorSpace sRGB
= new (){ Red = new Point{ X = 0.64, Y = 0.33 },
Green = new Point{ X = 0.3, Y = 0.6 },
Blue = new Point{ X = 0.15, Y = 0.06 }, White = D65 };
public static ColorSpace P3Display
= new (){ Red = new Point{ X = 0.68, Y = 0.32 },
Green = new Point{ X = 0.265, Y = 0.69 },
Blue = new Point{ X = 0.15, Y = 0.06 }, White = D65 };
public static Matrix<double> RGBToXYZ(ColorSpace colorSpace)
{
var red = colorSpace.Red;
var green = colorSpace.Green;
var blue = colorSpace.Blue;
var white = colorSpace.White;
var whiteXYZ = Matrix<double>.Build.DenseOfArray(
new[, ]{ { white.X / white.Y }, { 1 },
{ (1 - white.X - white.Y) / white.Y } });
var Mprime = Matrix<double>.Build.DenseOfArray(new[, ]{
{ red.X / red.Y, green.X / green.Y, blue.X / blue.Y },
{ 1, 1, 1 },
{ (1 - red.X - red.Y) / red.Y,
(1 - green.X - green.Y) / green.Y,
(1 - blue.X - blue.Y) / blue.Y } });
return Mprime
* Matrix<double>.Build.DiagonalOfDiagonalVector(
(Mprime.Inverse() * whiteXYZ).Column(0));
}
public static Matrix<double> XYZToRGB(ColorSpace colorSpace)
{
return RGBToXYZ(colorSpace).Inverse();
}
public static Matrix<double> RGBToRGB(
ColorSpace from, ColorSpace to)
{
var result = XYZToRGB(to) \* RGBToXYZ(from);
result.CoerceZero(1e-14);
return result;
}
static void Main(string\[] args)
{
double\[] coords;
try {
coords = Array.ConvertAll(
args, x => double.Parse(x, CultureInfo.InvariantCulture));
if (coords.Length != 6)
throw new Exception();
} catch {
Console.WriteLine(
"Arguments must be: red_x red_y green_x green_y blue_x blue_y");
return;
}
var colorSpace = new ColorSpace{ Red
= new Point{ X = coords[0], Y = coords[1] },
Green = new Point{ X = coords[2], Y = coords[3] },
Blue = new Point{ X = coords[4], Y = coords[5] }, White = D65 };
var matrix = RGBToRGB(sRGB, colorSpace);
Thread.CurrentThread.CurrentCulture
= CultureInfo.InvariantCulture;
for (var i = 0; i < 3; i++) {
for (var j = 0; j < 3; j++) {
Console.Write(matrix[i, j]);
if (!(i == 2 && j == 2)) {
Console.Write(':');
}
}
}
}
}
}
The output should be something like this
0.8335444411825749:0.16911422824331526:-0.0026586694258896593:0.04650138955110145:0.9483488982583312:0.005149712190567302:0.012353331090545688:0.04961038521975711:0.9380362836896972
Two ways to use this color-transform-matrix, from what I found the cmdemo
method should work on both AMD & Nvidia, whereas the --set CscMatrix
is Nvidia only.
The output is already in the proper format for the color-demo-app so all that needs to be done is compile the color-demo-app
git://people.freedesktop.org/~hwentland/color-demo-app
cd color-demo-app
make
Get the display name by running xrandr
and run the executable
./cmdemo -o -d srgb -c 0.8335444411825749:0.16911422824331526:-0.0026586694258896593:0.04650138955110145:0.9483488982583312:0.005149712190567302:0.012353331090545688:0.04961038521975711:0.9380362836896972 -r srgb"
Have to use xrandr for novideo folks. No need to compile a program for this its just multiplication. Each entry needs to be multiplied by 65536.
For example if we were multiplying the red channel the red_x value would be 0.8335444411825749 * 65536 = 55460
and red_y would be 0.16911422824331526 * 65536 = 11083
. The format for the --set CscMatrix
is [R,G,B,1]
xrandr --output DP-0 --set CscMatrix 54627,11083,-174,0,3047,62150,337,0,809,3251,61475,0
Might happen to just be related to the GPU vendor and OS combination.
From what I can tell this SRGB clamp method does not clamp it to 100% coverage on certain panels/models, but will get close to it if not perfect like 103, maybe 105%? Just seems a tad bit more vibrant compared to driver level SRGB clamps on Windows or the inbuilt display presets on the hardware.
Limited to X11 only as of right now, since CSCMatrix
and/or colour management is just not a thing in Wayland as of writing this.