Skip to content

Instantly share code, notes, and snippets.

@maandree
Last active June 27, 2021 12:40
Show Gist options
  • Save maandree/0275bfa0ad2d5851dc5d to your computer and use it in GitHub Desktop.
Save maandree/0275bfa0ad2d5851dc5d to your computer and use it in GitHub Desktop.
Windows gamma test
#ifndef WINVER
# define WINVER 0x0500
#endif
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <windows.h>
#include <wingdi.h>
/**
* The gamma ramp size that devices will
* always have in Windows GDI.
*/
#define GAMMA_RAMP_SIZE 256
static size_t crtcs_available;
static int* actives;
static HDC* contexts;
static int crtc_init(size_t crtc)
{
DISPLAY_DEVICE display;
HDC context;
/* Windows's API mandates this... */
display.cb = sizeof(DISPLAY_DEVICE);
/* Get identifier for selected CRTC. */
if (!EnumDisplayDevices(NULL, (DWORD)crtc, &display, 0))
return 3;
/* Check that the connector is active. */
if (!(display.StateFlags & DISPLAY_DEVICE_ACTIVE))
return 4;
/* Acquire CRTC connection. */
context = CreateDC(TEXT("DISPLAY"), display.DeviceName, NULL, NULL);
if (context == NULL)
return 5;
contexts[crtc] = context;
return 0;
}
static void crtc_destroy(size_t crtc)
{
if (contexts[crtc])
ReleaseDC(NULL, contexts[crtc]);
}
static void set_ramps(size_t crtc, uint16_t* rgb)
{
if (!SetDeviceGammaRamp(contexts[crtc], rgb))
fprintf(stderr, "Cannot set gamma ramps on active CRTC %lu\n", crtc);
}
static uint16_t* make_ramps(void)
{
uint16_t* rgb = malloc(3 * GAMMA_RAMP_SIZE * sizeof(uint16_t));
if (rgb == NULL)
return NULL;
return rgb;
}
static void fill_ramp(uint16_t* ramp, float gamma)
{
int16_t i;
for (i = 0; i < GAMMA_RAMP_SIZE; i++)
{
double f = (double)i / (double)(GAMMA_RAMP_SIZE - 1);
f = pow(f, 1.0 / gamma);
ramp[i] = (uint16_t)(f * (UINT16_MAX - 1));
}
}
static void set_gamma(size_t crtc, uint16_t* rgb, float red, float green, float blue)
{
fill_ramp(rgb + 0 * GAMMA_RAMP_SIZE, red);
fill_ramp(rgb + 1 * GAMMA_RAMP_SIZE, green);
fill_ramp(rgb + 2 * GAMMA_RAMP_SIZE, blue);
set_ramps(crtc, rgb);
}
static int parse_gamma(char* value, float* red, float* green, float* blue)
{
char* rv = value;
char* gv = strchr(rv, ':');
char* bv;
if (gv == NULL)
return 7;
*gv++ = '\0';
bv = strchr(gv, ':');
if (bv == NULL)
return 7;
*bv++ = '\0';
if (strchr(bv, ':'))
return 7;
*red = atof(rv);
*green = atof(gv);
*blue = atof(bv);
return 0;
}
int main(int argc, char** argv)
{
DWORD n = 0;
DISPLAY_DEVICE display;
size_t i, j, active_count = 0;
int r;
uint16_t* rgb;
/* Count CRTC:s by iteration over all possible identifiers
until we reach on that does not exist. */
display.cb = sizeof(DISPLAY_DEVICE);
while (EnumDisplayDevices(NULL, n, &display, 0))
if (n++, n == 0)
return 1;
crtcs_available = (size_t)n;
if (contexts = calloc(crtcs_available, sizeof(HDC)), contexts == NULL) return 2;
if (actives = calloc(crtcs_available, sizeof(int)), actives == NULL) return 2;
for (i = 0; i < crtcs_available; i++)
if ((r = crtc_init(i)))
{
if (r != 4)
return r;
}
else
{
if (GetDeviceCaps(contexts[i], COLORMGMTCAPS) != CM_GAMMA_RAMP)
fprintf(stderr,
"Warning: display %lu is not marked with gamma ramps support, "
"this may fail, but it probably will not.", i);
actives[i] = 1, active_count++;
}
if (rgb = make_ramps(), rgb == NULL)
return 6;
for (i = j = 0; i < crtcs_available; i++)
if (actives[i])
{
float red, green, blue;
if ((r = parse_gamma(argv[++j], &red, &green, &blue)))
return r;
set_gamma(i, rgb, red, green, blue);
}
free(rgb);
for (i = 0; i < crtcs_available; i++)
crtc_destroy(i);
free(contexts);
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment