Introduce di_gtf_compute()

This is a function to compute a timing according to GTF.

Signed-off-by: Simon Ser <contact@emersion.fr>
This commit is contained in:
Simon Ser 2022-09-26 11:03:57 +02:00
parent 11f48480d8
commit 87e264f7fb
7 changed files with 237 additions and 39 deletions

View file

@ -6,9 +6,10 @@
#include <getopt.h>
#include <libdisplay-info/cta.h>
#include <libdisplay-info/displayid.h>
#include <libdisplay-info/dmt.h>
#include <libdisplay-info/edid.h>
#include <libdisplay-info/displayid.h>
#include <libdisplay-info/gtf.h>
#include <libdisplay-info/info.h>
static struct {
@ -57,11 +58,14 @@ print_standard_timing(const struct di_edid_standard_timing *t)
int32_t vert_video;
const struct di_dmt_timing *dmt;
int hbl, vbl, horiz_total, vert_total;
double refresh, horiz_freq_hz, pixel_clock_mhz;
double refresh, horiz_freq_hz, pixel_clock_mhz, pixel_clock_khz;
struct di_gtf_options gtf_options;
struct di_gtf_timing gtf;
vert_video = di_edid_standard_timing_get_vert_video(t);
dmt = di_edid_standard_timing_get_dmt(t);
printf(" ");
if (dmt) {
hbl = dmt->horiz_blank - 2 * dmt->horiz_border;
vbl = dmt->vert_blank - 2 * dmt->vert_border;
@ -70,15 +74,37 @@ print_standard_timing(const struct di_edid_standard_timing *t)
refresh = (double) dmt->pixel_clock_hz / (horiz_total * vert_total);
horiz_freq_hz = (double) dmt->pixel_clock_hz / horiz_total;
pixel_clock_mhz = (double) dmt->pixel_clock_hz / (1000 * 1000);
printf("DMT 0x%02x", dmt ? dmt->dmt_id : 0);
} else {
/* TODO: GTF and CVT timings */
refresh = 0;
horiz_freq_hz = 0;
pixel_clock_mhz = 0;
/* TODO: CVT timings */
gtf_options = (struct di_gtf_options) {
.h_pixels = t->horiz_video,
.v_lines = vert_video,
.ip_param = DI_GTF_IP_PARAM_V_FRAME_RATE,
.ip_freq_rqd = t->refresh_rate_hz,
.m = DI_GTF_DEFAULT_M,
.c = DI_GTF_DEFAULT_C,
.k = DI_GTF_DEFAULT_K,
.j = DI_GTF_DEFAULT_J,
};
di_gtf_compute(&gtf, &gtf_options);
hbl = gtf.h_front_porch + gtf.h_sync + gtf.h_back_porch + 2 * gtf.h_border;
vbl = gtf.v_front_porch + gtf.v_sync + gtf.v_back_porch + 2 * gtf.v_border;
horiz_total = gtf.h_pixels + hbl;
vert_total = gtf.v_lines + vbl;
/* Upstream edid-decode rounds the pixel clock to kHz... */
pixel_clock_khz = round(gtf.pixel_freq_mhz * 1000);
refresh = (pixel_clock_khz * 1000) / (horiz_total * vert_total);
horiz_freq_hz = (pixel_clock_khz * 1000) / horiz_total;
pixel_clock_mhz = pixel_clock_khz / 1000;
printf("GTF ");
}
printf(" ");
printf("DMT 0x%02x:", dmt ? dmt->dmt_id : 0);
printf(":");
printf(" %5dx%-5d", t->horiz_video, vert_video);
printf(" %10.6f Hz", refresh);
printf(" %s ", standard_timing_aspect_ratio_name(t->aspect_ratio));

129
gtf.c Normal file
View file

@ -0,0 +1,129 @@
/*
* Copyright 2006-2012 Red Hat, Inc.
* Copyright 2018-2021 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
*
* Originally imported from edid-decode.
*/
#include <math.h>
#include <libdisplay-info/gtf.h>
/**
* The assumed character cell granularity of the graphics system, in pixels.
*/
#define CELL_GRAN 8.0
/**
* The size of the top and bottom overscan margin as a percentage of the active
* vertical image.
*/
#define MARGIN_PERC 1.8
/**
* The minimum front porch in lines (vertical) and character cells (horizontal).
*/
#define MIN_PORCH 1.0
/**
* The width of the V sync in lines.
*/
#define V_SYNC_RQD 3.0
/**
* The width of the H sync as a percentage of the total line period.
*/
#define H_SYNC_PERC 8.0
/**
* Minimum time of vertical sync + back porch interval (µs).
*/
#define MIN_VSYNC_BP 550.0
void di_gtf_compute(struct di_gtf_timing *t, const struct di_gtf_options *options)
{
double c_prime, m_prime, h_pixels_rnd, v_lines_rnd, h_margin,
v_margin, interlace, total_active_pixels, pixel_freq,
h_blank_pixels, total_pixels, v_sync_bp, v_field_rate_rqd,
h_period_est, total_v_lines, v_field_rate_est, h_period,
ideal_duty_cycle, h_freq, ideal_h_period, v_back_porch, h_sync,
h_front_porch;
/* C' and M' are part of the Blanking Duty Cycle computation */
c_prime = ((options->c - options->j) * options->k / 256.0) + options->j;
m_prime = options->k / 256.0 * options->m;
h_pixels_rnd = round(options->h_pixels / CELL_GRAN) * CELL_GRAN;
v_lines_rnd = options->int_rqd ?
round(options->v_lines / 2.0) :
options->v_lines;
h_margin = options->margins_rqd ?
round(h_pixels_rnd * MARGIN_PERC / 100.0 / CELL_GRAN) * CELL_GRAN :
0;
v_margin = options->margins_rqd ?
round(MARGIN_PERC / 100.0 * v_lines_rnd) :
0;
interlace = options->int_rqd ? 0.5 : 0;
total_active_pixels = h_pixels_rnd + h_margin * 2;
switch (options->ip_param) {
case DI_GTF_IP_PARAM_V_FRAME_RATE:
// vertical frame frequency (Hz)
v_field_rate_rqd = options->int_rqd ?
options->ip_freq_rqd * 2 :
options->ip_freq_rqd;
h_period_est = (1.0 / v_field_rate_rqd - MIN_VSYNC_BP / 1000000.0) /
(v_lines_rnd + v_margin * 2 + MIN_PORCH + interlace) * 1000000.0;
v_sync_bp = round(MIN_VSYNC_BP / h_period_est);
total_v_lines = v_lines_rnd + v_margin * 2 +
v_sync_bp + interlace + MIN_PORCH;
v_field_rate_est = 1.0 / h_period_est / total_v_lines * 1000000.0;
h_period = h_period_est / (v_field_rate_rqd / v_field_rate_est);
ideal_duty_cycle = c_prime - m_prime * h_period / 1000.0;
h_blank_pixels = round(total_active_pixels * ideal_duty_cycle /
(100.0 - ideal_duty_cycle) /
(2 * CELL_GRAN)) * 2 * CELL_GRAN;
total_pixels = total_active_pixels + h_blank_pixels;
pixel_freq = total_pixels / h_period;
break;
case DI_GTF_IP_PARAM_H_FREQ:
// horizontal frequency (kHz)
h_freq = options->ip_freq_rqd;
v_sync_bp = round(MIN_VSYNC_BP * h_freq / 1000.0);
ideal_duty_cycle = c_prime - m_prime / h_freq;
h_blank_pixels = round(total_active_pixels * ideal_duty_cycle /
(100.0 - ideal_duty_cycle) /
(2 * CELL_GRAN)) * 2 * CELL_GRAN;
total_pixels = total_active_pixels + h_blank_pixels;
pixel_freq = total_pixels * h_freq / 1000.0;
break;
case DI_GTF_IP_PARAM_H_PIXELS:
// pixel clock rate (MHz)
pixel_freq = options->ip_freq_rqd;
ideal_h_period = (c_prime - 100.0 +
sqrt((100.0 - c_prime) * (100.0 - c_prime) +
0.4 * m_prime * (total_active_pixels + h_margin * 2) / pixel_freq))
/ 2.0 / m_prime * 1000.0;
ideal_duty_cycle = c_prime - m_prime * ideal_h_period / 1000.0;
h_blank_pixels = round(total_active_pixels * ideal_duty_cycle /
(100.0 - ideal_duty_cycle) /
(2 * CELL_GRAN)) * 2 * CELL_GRAN;
total_pixels = total_active_pixels + h_blank_pixels;
h_freq = pixel_freq / total_pixels * 1000.0;
v_sync_bp = round(MIN_VSYNC_BP * h_freq / 1000.0);
break;
}
v_back_porch = v_sync_bp - V_SYNC_RQD;
h_sync = round(H_SYNC_PERC / 100.0 * total_pixels / CELL_GRAN) * CELL_GRAN;
h_front_porch = h_blank_pixels / 2.0 - h_sync;
*t = (struct di_gtf_timing) {
.h_pixels = (int) h_pixels_rnd,
.v_lines = options->v_lines,
.v_sync = V_SYNC_RQD,
.h_sync = (int) h_sync,
.v_front_porch = MIN_PORCH,
.v_back_porch = (int) v_back_porch,
.h_front_porch = (int) h_front_porch,
.h_back_porch = (int) (h_front_porch + h_sync),
.h_border = (int) h_margin,
.v_border = (int) v_margin,
.pixel_freq_mhz = pixel_freq,
};
}

View file

@ -0,0 +1,72 @@
#ifndef DI_GTF_H
#define DI_GTF_H
#include <stdbool.h>
/**
* Low-level API for Generalized Timing Formula Standard version 1.1.
*/
/**
* Type of frequency parameter used in di_gtf_options.ip_freq_rqd.
*/
enum di_gtf_ip_param {
/* Vertical frame frequency (Hz) */
DI_GTF_IP_PARAM_V_FRAME_RATE,
/* Horizontal frequency (kHz) */
DI_GTF_IP_PARAM_H_FREQ,
/* Pixel clock rate (MHz) */
DI_GTF_IP_PARAM_H_PIXELS,
};
/**
* Input options for GTF.
*/
struct di_gtf_options {
/* Number of active image pixels displayed on a line, not including any
* margin */
int h_pixels;
/* Number of vertical lines in the displayed image */
int v_lines;
/* Whether margins are required */
bool margins_rqd;
/* Indicates which frequency parameter is specified in ip_freq_rqd */
enum di_gtf_ip_param ip_param;
/* Vertical frame frequency (in Hz), horizontal frequency (in kHz) or
* pixel clock rate (in MHz) */
double ip_freq_rqd;
/* Whether interlaced is required */
bool int_rqd;
/* Blanking formula gradient */
double m;
/* Blanking formula offset */
double c;
/* Blanking formula scaling factor */
double k;
/* Blanking formula scaling factor weighting */
double j;
};
#define DI_GTF_DEFAULT_M 600.0
#define DI_GTF_DEFAULT_C 40.0
#define DI_GTF_DEFAULT_K 128.0
#define DI_GTF_DEFAULT_J 20.0
/**
* Output timing data for GTF.
*/
struct di_gtf_timing {
int h_pixels, v_lines;
int h_sync, v_sync;
int h_front_porch, h_back_porch;
int v_front_porch, v_back_porch;
int h_border, v_border;
double pixel_freq_mhz; /* in mega-hertz */
};
/**
* Compute a timing via the GTF formula.
*/
void di_gtf_compute(struct di_gtf_timing *t, const struct di_gtf_options *options);
#endif

View file

@ -39,6 +39,7 @@ di_lib = library(
'displayid.c',
'dmt-table.c',
'edid.c',
'gtf.c',
'info.c',
'log.c',
],

View file

@ -1,18 +1,5 @@
--- ref
+++ di
@@ -37,9 +37,9 @@
DMT 0x24: 1280x1024 75.024675 Hz 5:4 79.976 kHz 135.000000 MHz
Apple : 1152x870 75.061550 Hz 192:145 68.681 kHz 100.000000 MHz
Standard Timings:
- GTF : 640x480 119.999084 Hz 4:3 61.800 kHz 52.406000 MHz
- GTF : 800x600 119.999886 Hz 4:3 77.160 kHz 83.950000 MHz
- GTF : 1024x768 119.999931 Hz 4:3 98.760 kHz 139.054000 MHz
+ DMT 0x00: 640x480 0.000000 Hz 4:3 0.000 kHz 0.000000 MHz
+ DMT 0x00: 800x600 0.000000 Hz 4:3 0.000 kHz 0.000000 MHz
+ DMT 0x00: 1024x768 0.000000 Hz 4:3 0.000 kHz 0.000000 MHz
DMT 0x23: 1280x1024 60.019740 Hz 5:4 63.981 kHz 108.000000 MHz
DMT 0x33: 1600x1200 60.000000 Hz 4:3 75.000 kHz 162.000000 MHz
DMT 0x2f: 1440x900 59.887445 Hz 16:10 55.935 kHz 106.500000 MHz
@@ -65,23 +65,8 @@
DTD 2: 1366x768 59.789541 Hz 683:384 47.712 kHz 85.500000 MHz
Hfront 70 Hsync 143 Hback 213 Hpol P

View file

@ -1,6 +1,6 @@
--- ref
+++ di
@@ -24,12 +24,12 @@
@@ -24,7 +24,7 @@
DMT 0x09: 800x600 60.316541 Hz 4:3 37.879 kHz 40.000000 MHz
DMT 0x10: 1024x768 60.003840 Hz 4:3 48.363 kHz 65.000000 MHz
Standard Timings:
@ -9,12 +9,6 @@
DMT 0x09: 800x600 60.316541 Hz 4:3 37.879 kHz 40.000000 MHz
DMT 0x10: 1024x768 60.003840 Hz 4:3 48.363 kHz 65.000000 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
- GTF : 1368x769 60.000000 Hz 16:9 47.760 kHz 85.968000 MHz
+ DMT 0x00: 1368x769 0.000000 Hz 16:9 0.000 kHz 0.000000 MHz
DMT 0x52: 1920x1080 60.000000 Hz 16:9 67.500 kHz 148.500000 MHz
Detailed Timing Descriptors:
DTD 1: 1920x1080 59.933878 Hz 16:9 66.587 kHz 138.500000 MHz (1000 mm x 550 mm)
@@ -40,14 +40,14 @@
Vfront 3 Vsync 5 Vback 22 Vpol P
Display Product Name: 'ITE6604'

View file

@ -1,16 +1,5 @@
--- ref
+++ di
@@ -35,8 +35,8 @@
DMT 0x24: 1280x1024 75.024675 Hz 5:4 79.976 kHz 135.000000 MHz
Standard Timings:
DMT 0x23: 1280x1024 60.019740 Hz 5:4 63.981 kHz 108.000000 MHz
- GTF : 1280x1024 75.999957 Hz 5:4 81.320 kHz 141.822000 MHz
- GTF : 1152x921 66.000114 Hz 5:4 63.162 kHz 97.017000 MHz
+ DMT 0x00: 1280x1024 0.000000 Hz 5:4 0.000 kHz 0.000000 MHz
+ DMT 0x00: 1152x921 0.000000 Hz 5:4 0.000 kHz 0.000000 MHz
DMT 0x24: 1280x1024 75.024675 Hz 5:4 79.976 kHz 135.000000 MHz
Detailed Timing Descriptors:
DTD 1: 1280x1024 60.019740 Hz 5:4 63.981 kHz 108.000000 MHz (digital composite, serrate, 380 mm x 300 mm)
@@ -50,15 +50,4 @@
----------------