diff options
Diffstat (limited to 'src/calibrator.c')
-rw-r--r-- | src/calibrator.c | 733 |
1 files changed, 0 insertions, 733 deletions
diff --git a/src/calibrator.c b/src/calibrator.c deleted file mode 100644 index a22feb4..0000000 --- a/src/calibrator.c +++ /dev/null @@ -1,733 +0,0 @@ -/** - * crt-calibrator – Calibration utility for CRT monitors - * Copyright © 2014 Mattias Andrée (maandree@member.fsf.org) - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - */ -#include "calibrator.h" - -#include "gamma.h" -#include "state.h" - -#include <unistd.h> -#include <termios.h> -#include <sys/types.h> -#include <sys/wait.h> -#include <errno.h> - - - -/** - * Draw bars in different shades of grey, red, green and blue - * used for calibrating the contrast and brightness - */ -void draw_contrast_brightness(void) -{ - const int CONTRAST_BRIGHTNESS_LEVELS[21] = - { - 0, 17, 27, 38, 48, 59, 70, 82, 94, 106, 119, 131, - 144, 158, 171, 185, 198, 212, 226, 241, 255 - }; - size_t f; - uint32_t y, x; - for (f = 0; f < framebuffer_count; f++) - { - framebuffer_t* restrict fb = framebuffers + f; - for (y = 0; y < 4; y++) - for (x = 0; x < 21; x++) - { - int v = CONTRAST_BRIGHTNESS_LEVELS[x]; - uint32_t colour = fb_colour(v * ((y == 1) | (y == 0)), - v * ((y == 2) | (y == 0)), - v * ((y == 3) | (y == 0))); - fb_fill_rectangle(fb, colour, - x * fb->width / 21, - y * fb->height / 4, - (x + 1) * fb->width / 21 - x * fb->width / 21, - (y + 1) * fb->height / 4 - y * fb->height / 4); - } - } -} - - -/** - * Draw a seven segment display - * - * @param fb The framebuffer to draw on - * @param colour The intensity of the least intense colour to use - * @param x The X component of the top left corner of the seven segment display - * @param y The Y component of the top left corner of the seven segment display - */ -void draw_digit(framebuffer_t* restrict fb, int colour, uint32_t x, uint32_t y) -{ - uint32_t c; - - c = fb_colour(colour + 0, colour + 0, colour + 0); - fb_fill_rectangle(fb, c, x + 20, y, 80, 20); - - c = fb_colour(colour + 1, colour + 1, colour + 1); - fb_fill_rectangle(fb, c, x, y + 20, 20, 80); - - c = fb_colour(colour + 2, colour + 2, colour + 2); - fb_fill_rectangle(fb, c, x + 100, y + 20, 20, 80); - - c = fb_colour(colour + 3, colour + 3, colour + 3); - fb_fill_rectangle(fb, c, x + 20, y + 100, 80, 20); - - c = fb_colour(colour + 4, colour + 4, colour + 4); - fb_fill_rectangle(fb, c, x, y + 120, 20, 80); - - c = fb_colour(colour + 5, colour + 5, colour + 5); - fb_fill_rectangle(fb, c, x + 100, y + 120, 20, 80); - - c = fb_colour(colour + 6, colour + 6, colour + 6); - fb_fill_rectangle(fb, c, x + 20, y + 200, 80, 20); -} - - -/** - * Manipulate a CRT controllers gamma ramps to display a specific digit - * for one of the seven segment display on only that CRT controller's - * monitors - * - * @param crtc The CRT controller information - * @param colour The intensity of the least intense colour in the seven segment display - * @param value The valud of the digit to display - */ -void gamma_digit(drm_crtc_t* restrict crtc, int colour, size_t value) -{ -#define __ 0 - const int DIGITS[11] = { 1 | 2 | 4 | __ | 16 | 32 | 64, /* (0) */ - __ | __ | 4 | __ | __ | 32 | __, /* (1) */ - 1 | __ | 4 | 8 | 16 | __ | 64, /* (2) */ - 1 | __ | 4 | 8 | __ | 32 | 64, /* (3) */ - __ | 2 | 4 | 8 | __ | 32 | __, /* (4) */ - 1 | 2 | __ | 8 | __ | 32 | 64, /* (5) */ - 1 | 2 | __ | 8 | 16 | 32 | 64, /* (6) */ - 1 | __ | 4 | __ | __ | 32 | __, /* (7) */ - 1 | 2 | 4 | 8 | 16 | 32 | 64, /* (8) */ - 1 | 2 | 4 | 8 | __ | 32 | 64, /* (9) */ - __ | __ | __ | __ | __ | __ | __}; /* not visible */ - int i, digit = DIGITS[value]; - - for (i = 0; i < 7; i++) - { - uint16_t c = (digit & (1 << i)) ? 0xFFFF : 0; - int j = i + colour; - crtc->red[j] = crtc->green[j] = crtc->blue[j] = c; - } -#undef __ -} - - -/** - * Draw an unique index on each monitor - * - * @return Zero on success, -1 on error - */ -int draw_id(void) -{ - size_t f, c, id = 0; - for (f = 0; f < framebuffer_count; f++) - { - framebuffer_t* restrict fb = framebuffers + f; - fb_fill_rectangle(fb, fb_colour(0, 0, 0), 0, 0, fb->width, fb->height); - draw_digit(fb, 1, 40, 40); - draw_digit(fb, 8, 180, 40); - } - for (c = 0; c < crtc_count; c++) - { - drm_crtc_t* restrict crtc = crtcs + c; - if (drm_get_gamma(crtc) < 0) - return -1; - gamma_digit(crtc, 1, id < 10 ? 10 : (id / 10) % 10); - gamma_digit(crtc, 8, (id / 1) % 10); - id++; - if (drm_set_gamma(crtc) < 0) - return -1; - } - return 0; -} - - -/** - * Draw squares used as reference when tweeking the gamma correction - */ -void draw_gamma(void) -{ - size_t f; - uint32_t x, y; - for (f = 0; f < framebuffer_count; f++) - { - framebuffer_t* restrict fb = framebuffers + f; - for (x = 0; x < 4; x++) - { - int r = (x == 1) || (x == 0); - int g = (x == 2) || (x == 0); - int b = (x == 3) || (x == 0); - uint32_t background = fb_colour(128 * r, 128 * g, 128 * b); - uint32_t average = fb_colour(188 * r, 188 * g, 188 * b); - uint32_t high = fb_colour(255 * r, 255 * g, 255 * b); - uint32_t low = fb_colour(0, 0, 0); - uint32_t xoff = x * fb->width / 4; - fb_fill_rectangle(fb, background, xoff, 0, fb->width / 4, fb->height); - xoff += (fb->width / 4 - 200) / 2; - fb_fill_rectangle(fb, high, xoff, 40, 200, 200); - fb_fill_rectangle(fb, average, xoff + 50, 40, 100, 200); - fb_fill_rectangle(fb, average, xoff, 280, 200, 200); - for (y = 0; y < 200; y += 2) - { - fb_draw_horizontal_line(fb, high, xoff + 50, 280 + y + 0, 100); - fb_draw_horizontal_line(fb, low , xoff + 50, 280 + y + 1, 100); - } - fb_fill_rectangle(fb, average, xoff, 520, 200, 200); - fb_fill_rectangle(fb, high, xoff + 50, 520, 100, 200); - } - } -} - - -/** - * Print a pattern on the screen that can be used when - * calibrating the convergence - */ -void draw_convergence(void) -{ - uint32_t black = fb_colour(0, 0, 0); - uint32_t white = fb_colour(255, 255, 255); - uint32_t x, y; - size_t f; - for (f = 0; f < framebuffer_count; f++) - { - framebuffer_t* restrict fb = framebuffers + f; - fb_fill_rectangle(fb, black, 0, 0, fb->width, fb->height); - for (y = 0; y <= fb->height; y += 16) - { - if (y == fb->height) - y = fb->height - 1; - for (x = 0; x <= fb->width; x += 16) - { - if (x == fb->height) - x = fb->height - 1; - fb_draw_pixel(fb, white, x, y); - } - } - } -} - - -/** - * Print a pattern on the screen that can be used when - * calibrating the moiré cancellation - * - * @param gap The horizontal and vertical gap, in pixels, between the dots - * @param diagonal Whether to draw dots in a diagonal pattern - */ -void draw_moire(uint32_t gap, int diagonal) -{ - uint32_t black = fb_colour(0, 0, 0); - uint32_t white = fb_colour(255, 255, 255); - uint32_t x, y, gap2 = gap << 1; - size_t f; - gap += (uint32_t)(!diagonal); - if (diagonal) - for (f = 0; f < framebuffer_count; f++) - { - framebuffer_t* restrict fb = framebuffers + f; - fb_fill_rectangle(fb, black, 0, 0, fb->width, fb->height); - for (y = 0; y < fb->height; y += gap) - for (x = (y % gap2); x < fb->width; x += gap2) - fb_draw_pixel(fb, white, x, y); - } - else - for (f = 0; f < framebuffer_count; f++) - { - framebuffer_t* restrict fb = framebuffers + f; - fb_fill_rectangle(fb, black, 0, 0, fb->width, fb->height); - for (y = 0; y < fb->height; y += gap) - for (x = 0; x < fb->width; x += gap) - fb_draw_pixel(fb, white, x, y); - } -} - - -/** - * Analyse the monitors calibrations - * - * @return Zero on success, -1 on error - */ -int read_calibs(void) -{ - size_t c; - for (c = 0; c < crtc_count; c++) - { - if (drm_get_gamma(crtcs + c) < 0) - return -1; - - gamma_analyse(crtcs[c].gamma_stops, crtcs[c].red, gammas[0] + c, - contrasts[0] + c, brightnesses[0] + c); - gamma_analyse(crtcs[c].gamma_stops, crtcs[c].green, gammas[1] + c, - contrasts[1] + c, brightnesses[1] + c); - gamma_analyse(crtcs[c].gamma_stops, crtcs[c].blue, gammas[2] + c, - contrasts[2] + c, brightnesses[2] + c); - } - return 0; -} - - -/** - * Apply the selected calibrations to the monitors - * - * @return Zero on success, -1 on error - */ -int apply_calibs(void) -{ - size_t c; - for (c = 0; c < crtc_count; c++) - { - gamma_generate(crtcs[c].gamma_stops, crtcs[c].red, gammas[0][c], - contrasts[0][c], brightnesses[0][c]); - gamma_generate(crtcs[c].gamma_stops, crtcs[c].green, gammas[1][c], - contrasts[1][c], brightnesses[1][c]); - gamma_generate(crtcs[c].gamma_stops, crtcs[c].blue, gammas[2][c], - contrasts[2][c], brightnesses[2][c]); - - if (drm_set_gamma(crtcs + c) < 0) - return -1; - } - return 0; -} - - -/** - * Print calibrations into a file - * - * @param f The file - * @return Zero on success, -1 on error - */ -int save_calibs(FILE* f) -{ - size_t c; - for (c = 0; c < crtc_count; c++) - { - if (fprintf(f, "# index = %lu\n", - c) < 0) - return -1; - - if (fprintf(f, "edid = %s\n", - crtcs[c].edid) < 0) - return -1; - - if (fprintf(f, "brightness = %f:%f:%f\n", - brightnesses[0][c], - brightnesses[1][c], - brightnesses[2][c]) < 0) - return -1; - - if (fprintf(f, "contrast = %f:%f:%f\n", - contrasts[0][c], - contrasts[1][c], - contrasts[2][c]) < 0) - return -1; - - if (fprintf(f, "gamma = %f:%f:%f\n\n", - gammas[0][c], - gammas[1][c], - gammas[2][c]) < 0) - return -1; - } - return 0; -} - - -int main(int argc, char* argv[]) -{ - FILE* output_file = stdout; - int tty_configured = 0, rc = 0, in_fork = 0; - struct termios saved_stty; - struct termios stty; - pid_t pid; - - if ((argc > 2) || ((argc == 2) && (argv[1][0] == '-'))) - { - printf("USAGE: %s [output-file]\n", *argv); - return 0; - } - - if ((acquire_video() < 0) || - (tcgetattr(STDIN_FILENO, &saved_stty) < 0) || - (tcgetattr(STDIN_FILENO, &stty) < 0)) - goto fail; - - stty.c_lflag &= (tcflag_t)~(ICANON | ECHO); - if (tcsetattr(STDIN_FILENO, TCSAFLUSH, &stty) < 0) - goto fail; - tty_configured = 1; - - printf("\033[?25l"); - fflush(stdout); - - pid = fork(); - if ((pid != (pid_t)-1) && (pid != 0)) - { - int status; - retry: - if (waitpid(pid, &status, 0) != (pid_t)-1) - rc = !!status; - else - { - if (errno != EINTR) - perror(*argv); - goto retry; - } - goto done; - } - else if (pid == 0) - in_fork = 1; - - printf("\033[H\033[2J"); - printf("Please deactivate any program that dynamically\n"); - printf("applies filters to your monitors' colours\n"); - printf("and remove any existing filters.\n"); - printf("In doubt, you probably do not have any.\n"); - printf("Do not try to calibrate CRT monitors will\n"); - printf("they are cold.\n"); - printf("\n"); - printf("You will be presented with an image on each\n"); - printf("monitor. Please use the control panel on your\n"); - printf("to calibrate the contrast and brightness of\n"); - printf("each monitor. The contrasts adjusts the\n"); - printf("brightness of bright colours, and the\n"); - printf("brightness adjusts the brightness of dim\n"); - printf("colours. All rectangles are of equals size\n"); - printf("and they should be distrint from eachother.\n"); - printf("There should only be a slight difference\n"); - printf("between the two darkest colours for each\n"); - printf("colour. The grey colour does not need to\n"); - printf("be perfectly grey but should be close.\n"); - printf("The brightness should be as high as\n"); - printf("possible without the first square being\n"); - printf("any other colour than black or the two first\n"); - printf("square being too distinct from eachother. The\n"); - printf("contrast should be as high as possible without\n"); - printf("causing distortion.\n"); - printf("\n"); - printf("Press ENTER to continue, and ENTER again when\n"); - printf("your are done.\n"); - fflush(stdout); - - while (getchar() != 10) - ; - - printf("\033[H\033[2J"); - fflush(stdout); - draw_contrast_brightness(); - - while (getchar() != 10) - ; - - printf("\033[H\033[2J"); - printf("An index will be displayed on each monitor.\n"); - printf("It behoves you to memorise them. They will\n"); - printf("be used in the output when descibing the\n"); - printf("calibrations, and is the index of the monitors\n"); - printf("that are used when changing monitor to\n"); - printf("calibrate.\n"); - printf("\n"); - printf("Press ENTER to continue, and ENTER again when\n"); - printf("your are done.\n"); - fflush(stdout); - - while (getchar() != 10) - ; - - printf("\033[H\033[2J"); - fflush(stdout); - if ((read_calibs() < 0) || (draw_id() < 0)) - goto fail; - - while (getchar() != 10) - ; - - if (apply_calibs() < 0) - goto fail; - - printf("\033[H\033[2J"); - printf("You will not be given the opportunity to.\n"); - printf("calibrate your monitors' brightness and\n"); - printf("contrast using software incase your monitors\n"); - printf("could not be sufficiently calibrated using\n"); - printf("hardware.\n"); - printf("\n"); - printf("<Left> and <right> is used to change which\n"); - printf("monitor to calibrate. <Left> switches to the\n"); - printf("previous monitor (one lower in index) and\n"); - printf("<right> switches to the next monitor (one\n"); - printf("higher in index.)\n"); - printf("<Up> and <down> is used to increase and\n"); - printf("descrease the settings. respectively.\n"); - printf("<Shift+b> is used to switch to changing the.\n"); - printf("monitor's brightness and <shift+c> switches\n"); - printf("to contrast.\n"); - printf("<r> is used to switch to changing the red.\n"); - printf("channel, <g> switches to the green channel,\n"); - printf("<b> switches to the blue channel, and <a>\n"); - printf("is used to switch to change all channels.\n"); - printf("\n"); - printf("Press ENTER to continue, and ENTER again when\n"); - printf("your are done.\n"); - fflush(stdout); - - while (getchar() != 10) - ; - - printf("\033[H\033[2J"); - fflush(stdout); - draw_contrast_brightness(); - - { - int c, b = 0, at_contrast = 0; - int red = 1, green = 1, blue = 1; - size_t mon = 0; - while ((c = getchar()) != 10) - { - if (b) - { - b = 0; - if ((c == 'A') && at_contrast) - { - contrasts[0][mon] += (double)red / 100; - contrasts[1][mon] += (double)green / 100; - contrasts[2][mon] += (double)blue / 100; - } - else if (c == 'A') - { - brightnesses[0][mon] += (double)red / 100; - brightnesses[1][mon] += (double)green / 100; - brightnesses[2][mon] += (double)blue / 100; - } - else if ((c == 'B') && at_contrast) - { - contrasts[0][mon] -= (double)red / 100; - contrasts[1][mon] -= (double)green / 100; - contrasts[2][mon] -= (double)blue / 100; - } - else if (c == 'B') - { - brightnesses[0][mon] -= (double)red / 100; - brightnesses[1][mon] -= (double)green / 100; - brightnesses[2][mon] -= (double)blue / 100; - } - else if (c == 'C') - mon = (mon + 1) % crtc_count; - else if (c == 'D') - mon = (mon == 0 ? crtc_count : mon) - 1; - - if ((c == 'A') || (c == 'B')) - apply_calibs(); - } - else if (c == '[') b = 1; - else if (c == 'B') at_contrast = 0; - else if (c == 'C') at_contrast = 1; - else if (c == 'r') red = 1, green = 0, blue = 0; - else if (c == 'g') red = 0, green = 1, blue = 0; - else if (c == 'b') red = 0, green = 0, blue = 1; - else if (c == 'a') red = 1, green = 1, blue = 1; - } - } - - printf("\033[H\033[2J"); - printf("You will now be presented with squares used\n"); - printf("to calibrate the gamma correction. There will\n"); - printf("be four stacks: grey, red, green and blue.\n"); - printf("Each stack has three squares: the upper square\n"); - printf("shows the characterics of how the middle square\n"); - printf("will look if the gamma is too high, and the\n"); - printf("lower shows how the middile will look if the\n"); - printf("gamma is too low. The middle square should\n"); - printf("look like it is one single colour if the gamma\n"); - printf("correction is configured correctly. You may\n"); - printf("have to look from a distance or not focus\n"); - printf("your eyes on the squares to compensate for\n"); - printf("the fact that there actually multiple colours\n"); - printf("is the square.\n"); - printf("The grey should look perfectly grey when you\n"); - printf("are done.\n"); - printf("\n"); - printf("<Left> and <right> is used to change which\n"); - printf("monitor to calibrate. <Left> switches to the\n"); - printf("previous monitor (one lower in index) and\n"); - printf("<right> switches to the next monitor (one\n"); - printf("higher in index.)\n"); - printf("<Up> and <down> is used to increase and\n"); - printf("descrease the gamma. respectively.\n"); - printf("<r> is used to switch to changing the red.\n"); - printf("channel, <g> switches to the green channel,\n"); - printf("<b> switches to the blue channel, and <a>\n"); - printf("is used to switch to change all channels.\n"); - printf("\n"); - printf("Press ENTER to continue, and ENTER again when\n"); - printf("your are done.\n"); - fflush(stdout); - - while (getchar() != 10) - ; - - printf("\033[H\033[2J"); - fflush(stdout); - draw_gamma(); - - { - int c, b = 0; - int red = 1, green = 1, blue = 1; - size_t mon = 0; - while ((c = getchar()) != 10) - { - if (b) - { - b = 0; - if (c == 'A') - { - gammas[0][mon] += (double)red / 100; - gammas[1][mon] += (double)green / 100; - gammas[2][mon] += (double)blue / 100; - } - else if (c == 'B') - { - gammas[0][mon] -= (double)red / 100; - gammas[1][mon] -= (double)green / 100; - gammas[2][mon] -= (double)blue / 100; - if (gammas[0][mon] < 0) gammas[0][mon] = 0; - if (gammas[1][mon] < 0) gammas[1][mon] = 0; - if (gammas[2][mon] < 0) gammas[2][mon] = 0; - } - else if (c == 'C') - mon = (mon + 1) % crtc_count; - else if (c == 'D') - mon = (mon == 0 ? crtc_count : mon) - 1; - - if ((c == 'A') || (c == 'B')) - apply_calibs(); - } - else if (c == '[') b = 1; - else if (c == 'r') red = 1, green = 0, blue = 0; - else if (c == 'g') red = 0, green = 1, blue = 0; - else if (c == 'b') red = 0, green = 0, blue = 1; - else if (c == 'a') red = 1, green = 1, blue = 1; - } - } - - printf("\033[H\033[2J"); - printf("The next step is to calibrate the monitors'\n"); - printf("convergence settings using the monitors'\n"); - printf("control panel. White dots will be printed on the\n"); - printf("screens, you should try to get as many as\n"); - printf("possible of them to appear as pure white dots\n"); - printf("rather than dots splitted in the red, green and\n"); - printf("blue dots. On most CRT monitors this is not\n"); - printf("possible to get all corners perfect.\n"); - printf("\n"); - printf("Press ENTER to continue, and ENTER again when\n"); - printf("your are done.\n"); - fflush(stdout); - - while (getchar() != 10) - ; - - printf("\033[H\033[2J"); - fflush(stdout); - draw_convergence(); - - while (getchar() != 10) - ; - - printf("\033[H\033[2J"); - printf("The final step is to calbirate the monitors' moiré\n"); - printf("cancellation. This too is done on the using the\n"); - printf("monitors' control panel.\n"); - printf("\n"); - printf("You can use <d> and the arrow keys to change the\n"); - printf("dot-pattern on the screens.\n"); - printf("\n"); - printf("Press ENTER to continue, and ENTER again when\n"); - printf("your are done.\n"); - fflush(stdout); - - while (getchar() != 10) - ; - - printf("\033[H\033[2J"); - fflush(stdout); - draw_moire(1, 1); - - { - int c, b = 0, d = 1; - uint32_t gap = 1; - while ((c = getchar()) != 10) - { - if (b) - { - b = 0; - if ((c == 'A') || (c == 'C')) - draw_moire(++gap, d); - else if ((c == 'B') || (c == 'D')) - { - if (--gap == 0) - gap = 1; - draw_moire(gap, d); - } - } - else if (c == '[') - b = 1; - else if (c == 'd') - draw_moire(gap, d ^= 1); - } - } - - printf("\033[H\033[2J"); - fflush(stdout); - - if (argc == 2) - { - output_file = fopen(argv[1], "w"); - if (output_file == NULL) - goto fail; - } - - if (save_calibs(output_file) < 0) - goto fail; - fflush(output_file); - - if (argc == 2) - { - if (fclose(output_file)) - goto fail; - } - - done: - if (in_fork == 0) - { - release_video(); - if (tty_configured) - tcsetattr(STDIN_FILENO, TCSAFLUSH, &saved_stty); - printf("\033[?25h"); - fflush(stdout); - } - return rc; - fail: - perror(*argv); - rc = 1; - goto done; -} - |