/* * $Id$ * * Copyright (C) 2003-2015 JNode.org * * This library is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation; either version 2.1 of the License, or * (at your option) any later version. * * This library 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 Lesser General Public * License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this library; If not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ package org.jnode.driver.video.util; /** * This is a implementation of Vesa's General Timing Formula base on the code * of the Linux gtf tool * <p> * Timing description I'm accustomed to: * <pre> * <--------1--------> <--2--> <--3--> <--4--> _________ * |-------------------|_______| |_______ * * R SS SE FL * </pre> * 1: visible image 2: blank before sync (aka front porch) 3: sync pulse 4: * blank after sync (aka back porch) R: Resolution SS: Sync Start SE: Sync End * FL: Frame Length */ public class VesaGTF { /* assumed character width in pixels */ private static final double CELL_GRAN = 8.0; /* minimum front porch */ private static final double MIN_PORCH = 1.0; /* min time of vsync + back porch (microsec) */ private static final double MIN_VSYNC_PLUS_BP = 550.0; /* width of vsync in lines */ private static final double V_SYNC_RQD = 3.0; /* width of hsync as % of total line */ private static final double H_SYNC_PERCENT = 8.0; /* C' and M' are part of the Blanking Duty Cycle computation */ private static final double M_PRIME = 300.0; private static final double C_PRIME = 30.0; private int hResolution; private int hSyncStart; private int hSyncEnd; private int hFrameLength; private int vResolution; private int vSyncStart; private int vSyncEnd; private int vFrameLength; private double pixelClock; private double hFrequency; private double vFrequency; public VesaGTF(int hResolution, int hSyncStart, int hSyncEnd, int hFrameLength, int vResolution, int vSyncStart, int vSyncEnd, int vFrameLength, double pixelClock, double hFrequency, double vFrequency) { super(); this.hResolution = hResolution; this.hSyncStart = hSyncStart; this.hSyncEnd = hSyncEnd; this.hFrameLength = hFrameLength; this.vResolution = vResolution; this.vSyncStart = vSyncStart; this.vSyncEnd = vSyncEnd; this.vFrameLength = vFrameLength; this.pixelClock = pixelClock; this.hFrequency = hFrequency; this.vFrequency = vFrequency; } /** * calculate the modelines for the given screen resolution and refresh rate. * * @param hPixels * @param vLines * @param frequency * @return the modelines */ public static VesaGTF calculate(int hPixels, int vLines, double frequency) { double total_active_pixels = Math.round(hPixels / CELL_GRAN) * CELL_GRAN; double h_period_est = ((1.0 / frequency) - (MIN_VSYNC_PLUS_BP / 1000000.0)) / (vLines + MIN_PORCH) * 1000000.0; double vsync_plus_bp = Math.round(MIN_VSYNC_PLUS_BP / h_period_est); double total_v_lines = vLines + vsync_plus_bp + MIN_PORCH; double v_field_rate_est = 1.0 / h_period_est / total_v_lines * 1000000.0; double h_period = h_period_est / (frequency / v_field_rate_est); double ideal_duty_cycle = C_PRIME - (M_PRIME * h_period / 1000.0); double h_blank = Math.round(total_active_pixels * ideal_duty_cycle / (100.0 - ideal_duty_cycle) / (2.0 * CELL_GRAN)) * (2.0 * CELL_GRAN); double total_pixels = total_active_pixels + h_blank; double pixel_freq = total_pixels / h_period; double h_freq = 1000.0 / h_period; double h_sync = Math.round(H_SYNC_PERCENT / 100.0 * total_pixels / CELL_GRAN) * CELL_GRAN; double h_front_porch = (h_blank / 2.0) - h_sync; return new VesaGTF((int) total_active_pixels, (int) (total_active_pixels + h_front_porch), (int) (total_active_pixels + h_front_porch + h_sync), (int) total_pixels, vLines, (int) (vLines + MIN_PORCH), (int) (vLines + MIN_PORCH + V_SYNC_RQD), (int) total_v_lines, pixel_freq, h_freq, frequency); } public int getHFrameLength() { return hFrameLength; } public double getHFrequency() { return hFrequency; } public int getHResolution() { return hResolution; } public int getHSyncEnd() { return hSyncEnd; } public int getHSyncStart() { return hSyncStart; } public double getPixelClock() { return pixelClock; } public int getVFrameLength() { return vFrameLength; } public double getVFrequency() { return vFrequency; } public int getVResolution() { return vResolution; } public int getVSyncEnd() { return vSyncEnd; } public int getVSyncStart() { return vSyncStart; } @Override public String toString() { StringBuilder sb = new StringBuilder(100); sb.append("Resolution "); sb.append(hResolution); sb.append("x"); sb.append(vResolution); sb.append("@"); sb.append(vFrequency); sb.append("Hz\nHSS: "); sb.append(hSyncStart); sb.append(" HSE: "); sb.append(hSyncEnd); sb.append(" HFL: "); sb.append(hFrameLength); sb.append("\nVSS: "); sb.append(vSyncStart); sb.append(" VSE: "); sb.append(vSyncEnd); sb.append(" VFL: "); sb.append(vFrameLength); sb.append(" PCLK: "); sb.append(pixelClock); sb.append(" HFREQ: "); sb.append(hFrequency); return sb.toString(); } /* * Test code.. */ public static void main(String[] args) { // Test some default values.. VesaGTF gtf1 = VesaGTF.calculate(800, 600, 50); VesaGTF gtf2 = VesaGTF.calculate(800, 600, 60); VesaGTF gtf3 = VesaGTF.calculate(800, 600, 70); System.out.println("800x600 Resolution:"); System.out.println("50Hz:\n" + gtf1.toString()); System.out.println("60Hz:\n" + gtf2.toString()); System.out.println("70Hz:\n" + gtf3.toString()); VesaGTF gtf4 = VesaGTF.calculate(1024, 768, 60); System.out.println("1024x768 Resolution:\n60Hz:\n" + gtf4.toString()); } }