edid-decode: fix emscripten build
[edid-decode.git] / calc-ovt.cpp
blob10ca606c88b937a91a03cc2aa8733a33844fd62f
1 // SPDX-License-Identifier: MIT
2 /*
3 * Copyright 2021 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
5 * Author: Hans Verkuil <hverkuil-cisco@xs4all.nl>
6 */
8 #include <stdio.h>
9 #include <stdlib.h>
10 #include <math.h>
11 #include <time.h>
12 #include <numeric>
14 #include "edid-decode.h"
16 #define MinVblankDuration 460
17 #define MinVblankLines 20
18 #define MinVsyncLeadingEdge 400
19 #define MinVsyncLELines 14
20 #define MinClockRate420 590000000
21 #define PixelFactor420 2
22 #define MinHblank444 80
23 #define MinHblank420 128
24 #define PixelClockGranularity 1000
25 #define MinHtotalGranularity 8
26 #define MaxChunkRate 650000000
27 #define AudioPacketRate 195000
28 #define AudioPacketSize 32
29 #define LineOverhead 32
31 static unsigned roundup_to_power_of_two(unsigned v)
33 unsigned shift = 1;
34 unsigned mask = 0;
36 if (!v || v > 0x80000000) {
37 fprintf(stderr, "roundup_to_power_of_two: invalid input %u.\n", v);
38 exit(1);
41 v--;
42 do {
43 mask = v >> shift;
44 v |= mask;
45 shift <<= 1;
46 } while (mask);
47 return v + 1;
50 static unsigned greatest_power_of_two_divider(unsigned x)
52 return x & ~(x - 1);
55 timings edid_state::calc_ovt_mode(unsigned Hactive, unsigned Vactive,
56 unsigned Hratio, unsigned Vratio,
57 unsigned Vrate)
59 timings t = {};
61 t.hact = Hactive;
62 t.vact = Vactive;
63 t.hratio = Hratio;
64 t.vratio = Vratio;
66 unsigned MaxVrate = Vrate;
67 unsigned VtotalGranularity = 1;
69 // Step 1
70 switch (Vrate) {
71 case 24: case 25: case 30:
72 MaxVrate = 30;
73 VtotalGranularity = 20;
74 break;
75 case 48: case 50: case 60:
76 MaxVrate = 60;
77 VtotalGranularity = 20;
78 break;
79 case 100: case 120:
80 MaxVrate = 120;
81 VtotalGranularity = 5;
82 break;
83 case 200: case 240:
84 MaxVrate = 240;
85 VtotalGranularity = 5;
86 break;
87 case 300: case 360:
88 MaxVrate = 360;
89 VtotalGranularity = 5;
90 break;
91 case 400: case 480:
92 MaxVrate = 480;
93 VtotalGranularity = 5;
94 break;
97 // Step 2
98 double MaxActiveTime = (1000000.0 / MaxVrate) - MinVblankDuration;
99 double MinLineTime = MaxActiveTime / Vactive;
100 unsigned MinVblank = max(MinVblankLines, ceil(MinVblankDuration / MinLineTime));
101 unsigned MinVtotal = Vactive + MinVblank;
103 if (MinVtotal % VtotalGranularity)
104 MinVtotal += VtotalGranularity - (MinVtotal % VtotalGranularity);
106 // Step 3
107 unsigned MinLineRate = MaxVrate * MinVtotal;
108 unsigned MaxAudioPacketsPerLine = ceil((double)AudioPacketRate / MinLineRate);
110 // Step 4
111 unsigned MinHtotal = Hactive +
112 max(MinHblank444, LineOverhead + AudioPacketSize * MaxAudioPacketsPerLine);
113 double MinPixelClockRate = (double)MaxVrate * MinHtotal * MinVtotal;
114 double HCalcGranularity = roundup_to_power_of_two(ceil(MinPixelClockRate / MaxChunkRate));
115 unsigned HtotalGranularity = max(MinHtotalGranularity, HCalcGranularity);
117 if (MinHtotal % HtotalGranularity)
118 MinHtotal += HtotalGranularity - (MinHtotal % HtotalGranularity);
120 unsigned ResolutionGranularity = PixelClockGranularity /
121 gcd(PixelClockGranularity, MaxVrate);
122 unsigned Htotal = 0;
123 unsigned Vtotal = 0;
124 unsigned long long PixelClockRate = 0;
126 for (;;) {
127 // Step 5
128 unsigned long long RMin = 0;
129 unsigned V = MinVtotal;
131 for (;;) {
132 unsigned H = MinHtotal;
133 unsigned long long R = H * V;
134 if (RMin && R > RMin)
135 break;
136 while (R % ResolutionGranularity ||
137 MaxVrate * R / greatest_power_of_two_divider(H) > MaxChunkRate) {
138 H += HtotalGranularity;
139 R = H * V;
141 if (!RMin || R < RMin) {
142 Htotal = H;
143 Vtotal = V;
144 RMin = R;
146 V += VtotalGranularity;
148 PixelClockRate = MaxVrate * RMin;
150 // Step 6
151 MinHtotal = Hactive + max(MinHblank420, PixelFactor420 *
152 (LineOverhead + AudioPacketSize * MaxAudioPacketsPerLine));
153 if (PixelClockRate >= MinClockRate420 &&
154 Htotal < MinHtotal)
155 continue;
156 break;
159 // Step 7
160 Vtotal = Vtotal * MaxVrate / Vrate;
162 // Step 8
163 unsigned Vblank = Vtotal - Vactive;
164 unsigned VsyncPosition = max(MinVsyncLELines,
165 ceil((double)MinVsyncLeadingEdge * PixelClockRate / (1000000.0 * Htotal)));
166 t.vfp = Vblank - VsyncPosition;
168 t.vsync = 8;
169 t.vbp = Vblank - t.vfp - t.vsync;
170 t.pos_pol_vsync = true;
171 unsigned Hblank = Htotal - Hactive;
172 t.hsync = 32;
173 t.hbp = 32;
174 t.hfp = Hblank - t.hsync - t.hbp;
175 t.pos_pol_hsync = true;
176 t.pixclk_khz = PixelClockRate / 1000;
177 if (!t.hratio || !t.vratio)
178 calc_ratio(&t);
179 return t;