mirror of
https://gitlab.freedesktop.org/emersion/libdisplay-info.git
synced 2024-12-25 21:59:08 +01:00
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:
parent
11f48480d8
commit
87e264f7fb
7 changed files with 237 additions and 39 deletions
|
@ -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(>f, >f_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
129
gtf.c
Normal 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,
|
||||
};
|
||||
}
|
72
include/libdisplay-info/gtf.h
Normal file
72
include/libdisplay-info/gtf.h
Normal 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
|
|
@ -39,6 +39,7 @@ di_lib = library(
|
|||
'displayid.c',
|
||||
'dmt-table.c',
|
||||
'edid.c',
|
||||
'gtf.c',
|
||||
'info.c',
|
||||
'log.c',
|
||||
],
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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'
|
||||
|
|
|
@ -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 @@
|
||||
|
||||
----------------
|
||||
|
|
Loading…
Reference in a new issue