kopia lustrzana https://github.com/hoglet67/RGBtoHDMI
1038 wiersze
38 KiB
C
1038 wiersze
38 KiB
C
#include <stdio.h>
|
|
#include "geometry.h"
|
|
#include "cpld.h"
|
|
#include "osd.h"
|
|
#include "defs.h"
|
|
#include "logging.h"
|
|
#include "rgb_to_hdmi.h"
|
|
#include "startup.h"
|
|
|
|
static const char *px_sampling_names[] = {
|
|
"Normal",
|
|
"Odd",
|
|
"Even",
|
|
"Half Odd",
|
|
"Half Even",
|
|
};
|
|
|
|
static const char *sync_names[] = {
|
|
"-H-V",
|
|
"+H-V",
|
|
"-H+V",
|
|
"+H+V",
|
|
"Composite",
|
|
"Inverted Composite",
|
|
"Composite -V",
|
|
"Inverted -V"
|
|
};
|
|
|
|
static const char *vsync_names[] = {
|
|
"Auto",
|
|
"Interlaced",
|
|
"Interlaced 160uS Vsync",
|
|
"Non Interlaced",
|
|
"Flywheel",
|
|
"Blanking",
|
|
"Polarity",
|
|
"Force Interlaced"
|
|
};
|
|
|
|
static const char *setup_names[] = {
|
|
"Normal",
|
|
"Set Min/Offset",
|
|
"Set Maximum",
|
|
"Set Clock/Line",
|
|
"Fine Set Clock"
|
|
};
|
|
|
|
static const char *fb_sizex2_names[] = {
|
|
"Normal",
|
|
"Double Height",
|
|
"Double Width",
|
|
"Double Height+Width",
|
|
};
|
|
|
|
static const char *deint_names[] = {
|
|
"Progressive",
|
|
"Interlaced",
|
|
"Interlaced Teletext",
|
|
"Line Doubled"
|
|
};
|
|
|
|
static const char *bpp_names[] = {
|
|
"4",
|
|
"8",
|
|
"16"
|
|
};
|
|
|
|
static param_t params[] = {
|
|
{ SETUP_MODE, "Setup Mode", "setup_mode", 0,NUM_SETUP-1, 1 },
|
|
{ H_OFFSET, "H Offset", "h_offset", 1, 384, 4 },
|
|
{ V_OFFSET, "V Offset", "v_offset", 0, 256, 1 },
|
|
{ MIN_H_WIDTH, "Min H Width", "min_h_width", 100, 1920, 8 },
|
|
{MIN_V_HEIGHT, "Min V Height", "min_v_height", 100, 1200, 2 },
|
|
{ MAX_H_WIDTH, "Max H Width", "max_h_width", 120, 1920, 8 },
|
|
{MAX_V_HEIGHT, "Max V Height", "max_v_height", 120, 1200, 2 },
|
|
{ H_ASPECT, "H Pixel Aspect", "h_aspect", 0, 12, 1 },
|
|
{ V_ASPECT, "V Pixel Aspect", "v_aspect", 0, 12, 1 },
|
|
{ FB_SIZEX2, "FB Size", "fb_size", 0, 3, 1 },
|
|
{ FB_BPP, "FB Bits/Pixel", "fb_bits_pixel", 0, NUM_BPP-1, 1 },
|
|
{ CLOCK, "Clock Frequency", "clock_frequency", 1000000,64000000, 1000 },
|
|
{ LINE_LEN, "Line Length", "line_length", 100, 5000, 1 },
|
|
{ CLOCK_PPM, "Clock Tolerance", "clock_tolerance", 0, 100000, 100 },
|
|
{ LINES_FRAME, "Lines per Frame", "lines_per_frame", 250, 1200, 1 },
|
|
{ SYNC_TYPE, "Sync Type", "sync_type", 0, NUM_SYNC-1, 1 },
|
|
{ VSYNC_TYPE, "V Sync Type", "vsync_type", 0,NUM_VSYNC-1, 1 },
|
|
{ VIDEO_TYPE, "Video Type", "video_type", 0,NUM_VIDEO-1, 1 },
|
|
{ PX_SAMPLING, "Pixel Sampling", "pixel_sampling", 0, NUM_PS-1, 1 },
|
|
{ -1, NULL, NULL, 0, 0, 0 }
|
|
};
|
|
|
|
typedef struct {
|
|
int setup_mode; // dummy entry for setup
|
|
int h_offset; // horizontal offset (in psync clocks)
|
|
int v_offset; // vertical offset (in lines)
|
|
int min_h_width; // active horizontal width (in 8-bit characters)
|
|
int min_v_height; // active vertical height (in lines)
|
|
int max_h_width; // framebuffer width in pixels
|
|
int max_v_height; // framebuffer height (in pixels, before any doubling is applied)
|
|
int h_aspect; // horizontal pixel aspect ratio
|
|
int v_aspect; // vertical pixel aspect ratio
|
|
int fb_sizex2; // if 1 then double frame buffer height if 2 double width if 3 then both
|
|
int fb_bpp; // framebuffer bits per pixel
|
|
int clock; // cpld clock (in Hz)
|
|
int line_len; // number of clocks per horizontal line
|
|
int clock_ppm; // cpld tolerance (in ppm)
|
|
int lines_per_frame; // number of lines per frame
|
|
int sync_type; // sync type and polarity
|
|
int vsync_type; // vsync type auto/interlaced/non-interlaced
|
|
int video_type; // deinterlace type off/teletext
|
|
int px_sampling; // pixel sampling mode
|
|
} geometry_t;
|
|
|
|
static int modeset;
|
|
static geometry_t *geometry;
|
|
static geometry_t set1_geometry;
|
|
static geometry_t set2_geometry;
|
|
static int scaling = 0;
|
|
static int capvscale = 1;
|
|
static int caphscale = 1;
|
|
static int fhaspect = 1;
|
|
static int fvaspect = 1;
|
|
static int use_px_sampling = 1;
|
|
|
|
void geometry_init(int version) {
|
|
// These are Beeb specific defaults so the geometry property can be ommitted
|
|
set2_geometry.setup_mode = 0;
|
|
set2_geometry.v_offset = 18;
|
|
set2_geometry.min_h_width = 504 & 0xfffffff8;
|
|
set2_geometry.min_v_height = 270 & 0xfffffffe;
|
|
set2_geometry.max_h_width = 504 & 0xfffffff8;
|
|
set2_geometry.max_v_height = 270 & 0xfffffffe;
|
|
set2_geometry.h_aspect = 3;
|
|
set2_geometry.v_aspect = 4;
|
|
set2_geometry.fb_sizex2 = SIZEX2_DOUBLE_HEIGHT;
|
|
set2_geometry.fb_bpp = 0;
|
|
set2_geometry.clock = 12000000;
|
|
set2_geometry.line_len = 12 * 64;
|
|
set2_geometry.clock_ppm = 5000;
|
|
set2_geometry.lines_per_frame = 312;
|
|
set2_geometry.sync_type = SYNC_COMP;
|
|
set2_geometry.vsync_type = VSYNC_AUTO;
|
|
set2_geometry.video_type = VIDEO_TELETEXT;
|
|
set2_geometry.px_sampling = PS_NORMAL;
|
|
|
|
set1_geometry.setup_mode = 0;
|
|
set1_geometry.v_offset = 21;
|
|
set1_geometry.min_h_width = 672 & 0xfffffff8;
|
|
set1_geometry.min_v_height= 270 & 0xfffffffe;
|
|
set1_geometry.max_h_width = 672 & 0xfffffff8;
|
|
set1_geometry.max_v_height= 270 & 0xfffffffe;
|
|
set1_geometry.h_aspect = 1;
|
|
set1_geometry.v_aspect = 2;
|
|
set1_geometry.fb_sizex2 = SIZEX2_DOUBLE_HEIGHT;
|
|
set1_geometry.fb_bpp = 1;
|
|
set1_geometry.clock = 16000000;
|
|
set1_geometry.line_len = 16 * 64;
|
|
set1_geometry.clock_ppm = 5000;
|
|
set1_geometry.lines_per_frame = 312;
|
|
set1_geometry.sync_type = SYNC_COMP;
|
|
set1_geometry.vsync_type = VSYNC_AUTO;
|
|
set1_geometry.video_type = VIDEO_PROGRESSIVE;
|
|
set1_geometry.px_sampling = PS_NORMAL;
|
|
|
|
int firmware_support = cpld->old_firmware_support();
|
|
|
|
if (firmware_support & BIT_NORMAL_FIRMWARE_V1) {
|
|
// For backwards compatibility with CPLDv1
|
|
set2_geometry.h_offset = 0;
|
|
set1_geometry.h_offset = 0;
|
|
} else if (firmware_support & BIT_NORMAL_FIRMWARE_V2) {
|
|
// For backwards compatibility with CPLDv2
|
|
set2_geometry.h_offset = 96 & 0xfffffffc;
|
|
set1_geometry.h_offset = 128 & 0xfffffffc;
|
|
} else {
|
|
// For CPLDv3 onwards
|
|
set2_geometry.h_offset = 140 & 0xfffffffc;
|
|
set1_geometry.h_offset = 160 & 0xfffffffc;
|
|
}
|
|
geometry_set_mode(MODE_SET1);
|
|
}
|
|
|
|
void geometry_set_mode(int mode) {
|
|
modeset = mode;
|
|
if (modeset == MODE_SET1) {
|
|
geometry = &set1_geometry;
|
|
} else {
|
|
geometry = &set2_geometry;
|
|
}
|
|
}
|
|
int geometry_get_mode() {
|
|
return modeset;
|
|
}
|
|
int geometry_get_value(int num) {
|
|
switch (num) {
|
|
case SETUP_MODE:
|
|
return geometry->setup_mode;
|
|
case H_OFFSET:
|
|
return geometry->h_offset & 0xfffffffc;
|
|
case V_OFFSET:
|
|
return geometry->v_offset;
|
|
case MIN_H_WIDTH:
|
|
return geometry->min_h_width & 0xfffffff8;
|
|
case MIN_V_HEIGHT:
|
|
return geometry->min_v_height & 0xfffffffe;
|
|
case MAX_H_WIDTH:
|
|
return geometry->max_h_width & 0xfffffff8;
|
|
case MAX_V_HEIGHT:
|
|
return geometry->max_v_height & 0xfffffffe;
|
|
case H_ASPECT:
|
|
return geometry->h_aspect;
|
|
case V_ASPECT:
|
|
return geometry->v_aspect;
|
|
case FB_SIZEX2:
|
|
return geometry->fb_sizex2;
|
|
case FB_BPP:
|
|
return geometry->fb_bpp;
|
|
case CLOCK:
|
|
return geometry->clock;
|
|
case LINE_LEN:
|
|
return geometry->line_len;
|
|
case CLOCK_PPM:
|
|
return geometry->clock_ppm;
|
|
case LINES_FRAME:
|
|
return geometry->lines_per_frame;
|
|
case SYNC_TYPE:
|
|
return geometry->sync_type;
|
|
case VSYNC_TYPE:
|
|
return geometry->vsync_type;
|
|
case VIDEO_TYPE:
|
|
return geometry->video_type;
|
|
case PX_SAMPLING:
|
|
if (use_px_sampling == 0) {
|
|
geometry->px_sampling = 0;
|
|
}
|
|
return geometry->px_sampling;
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
const char *geometry_get_value_string(int num) {
|
|
if (num == SETUP_MODE) {
|
|
return setup_names[geometry_get_value(num)];
|
|
}
|
|
if (num == PX_SAMPLING) {
|
|
return px_sampling_names[geometry_get_value(num)];
|
|
}
|
|
if (num == SYNC_TYPE) {
|
|
return sync_names[geometry_get_value(num)];
|
|
}
|
|
if (num == VSYNC_TYPE) {
|
|
return vsync_names[geometry_get_value(num)];
|
|
}
|
|
if (num == FB_SIZEX2) {
|
|
return fb_sizex2_names[geometry_get_value(num)];
|
|
}
|
|
if (num == VIDEO_TYPE) {
|
|
return deint_names[geometry_get_value(num)];
|
|
}
|
|
if (num == FB_BPP) {
|
|
return bpp_names[geometry_get_value(num)];
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
void geometry_set_value(int num, int value) {
|
|
if (value < params[num].min) {
|
|
value = params[num].min;
|
|
}
|
|
if (value > params[num].max) {
|
|
value = params[num].max;
|
|
}
|
|
switch (num) {
|
|
case SETUP_MODE:
|
|
geometry->setup_mode = value;
|
|
if (value == SETUP_FINE) {
|
|
params[CLOCK].step = 1;
|
|
} else {
|
|
params[CLOCK].step = 1000;
|
|
}
|
|
break;
|
|
case H_OFFSET:
|
|
geometry->h_offset = value & 0xfffffffc;
|
|
break;
|
|
case V_OFFSET:
|
|
geometry->v_offset = value;
|
|
break;
|
|
case MIN_H_WIDTH:
|
|
geometry->min_h_width = value & 0xfffffff8;
|
|
break;
|
|
case MIN_V_HEIGHT:
|
|
geometry->min_v_height = value & 0xfffffffe;
|
|
break;
|
|
case MAX_H_WIDTH:
|
|
geometry->max_h_width = value & 0xfffffff8;
|
|
break;
|
|
case MAX_V_HEIGHT:
|
|
geometry->max_v_height = value & 0xfffffffe;
|
|
break;
|
|
case H_ASPECT:
|
|
geometry->h_aspect = value;
|
|
break;
|
|
case V_ASPECT:
|
|
geometry->v_aspect = value;
|
|
break;
|
|
case FB_SIZEX2:
|
|
geometry->fb_sizex2 = value;
|
|
break;
|
|
case FB_BPP:
|
|
geometry->fb_bpp = value;
|
|
break;
|
|
case CLOCK:
|
|
geometry->clock = value;
|
|
break;
|
|
case LINE_LEN:
|
|
geometry->line_len = value;
|
|
break;
|
|
case CLOCK_PPM:
|
|
geometry->clock_ppm = value;
|
|
break;
|
|
case LINES_FRAME:
|
|
geometry->lines_per_frame = value;
|
|
break;
|
|
case SYNC_TYPE:
|
|
geometry->sync_type = value;
|
|
break;
|
|
case VSYNC_TYPE:
|
|
geometry->vsync_type = value;
|
|
break;
|
|
case VIDEO_TYPE:
|
|
geometry->video_type = value;
|
|
break;
|
|
case PX_SAMPLING:
|
|
if (use_px_sampling == 0) {
|
|
geometry->px_sampling = 0;
|
|
} else {
|
|
geometry->px_sampling = value;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
param_t *geometry_get_params() {
|
|
return params;
|
|
}
|
|
|
|
void set_gscaling(int value) {
|
|
scaling = value;
|
|
}
|
|
|
|
int get_gscaling() {
|
|
return scaling;
|
|
}
|
|
|
|
void set_setup_mode(int mode) {
|
|
geometry_set_value(SETUP_MODE, mode);
|
|
//log_info("setup mode = %d", mode);
|
|
}
|
|
|
|
void geometry_get_fb_params(capture_info_t *capinfo) {
|
|
int top = 0;
|
|
int bottom = 0;
|
|
int left = 0;
|
|
int right = 0;
|
|
|
|
if (get_startup_overscan() != 0) {
|
|
set_config_overscan(0, 0, 0, 0);
|
|
}
|
|
|
|
capinfo->sync_type = geometry->sync_type;
|
|
capinfo->vsync_type = geometry->vsync_type;
|
|
capinfo->video_type = geometry->video_type;
|
|
capinfo->autoswitch = get_parameter(F_AUTO_SWITCH);
|
|
capinfo->timingset = modeset;
|
|
capinfo->sync_edge = cpld->get_sync_edge();
|
|
|
|
if (capinfo->video_type == VIDEO_LINE_DOUBLED) {
|
|
capinfo->video_type = VIDEO_PROGRESSIVE;
|
|
}
|
|
|
|
if (capinfo->vsync_type == VSYNC_FORCE_INTERLACE) {
|
|
capinfo->vsync_type = VSYNC_INTERLACED;
|
|
}
|
|
|
|
capinfo->sizex2 = geometry->fb_sizex2;
|
|
switch(geometry->fb_bpp) {
|
|
case BPP_4:
|
|
capinfo->bpp = 4;
|
|
break;
|
|
default:
|
|
case BPP_8:
|
|
capinfo->bpp = 8;
|
|
break;
|
|
case BPP_16:
|
|
capinfo->bpp = 16;
|
|
break;
|
|
}
|
|
|
|
capinfo->mode7 = 0;
|
|
if (capinfo->video_type == VIDEO_TELETEXT) {
|
|
capinfo->mode7 = 1;
|
|
if (capinfo->bpp != 4) {
|
|
capinfo->video_type = VIDEO_INTERLACED;
|
|
}
|
|
}
|
|
|
|
if (capinfo->video_type == VIDEO_INTERLACED && capinfo->detected_sync_type & SYNC_BIT_INTERLACED && (menu_active() || osd_active())) {
|
|
capinfo->video_type = VIDEO_PROGRESSIVE;
|
|
}
|
|
|
|
if (capinfo->video_type == VIDEO_TELETEXT) {
|
|
capinfo->bpp = 4; //force 4bpp for teletext
|
|
} else if (capinfo->sample_width >= SAMPLE_WIDTH_9LO && capinfo->bpp == 4) {
|
|
capinfo->bpp = 8; //force at least 8bpp in 12 bit modes as no capture loops for capture into 4bpp buffer
|
|
} else if (capinfo->sample_width == SAMPLE_WIDTH_6 && capinfo->bpp < 8) {
|
|
capinfo->bpp = 8; //force 8bpp in 6 bit modes as no capture loops for 6 bit capture into 4 bpp buffer
|
|
} else if (capinfo->sample_width == SAMPLE_WIDTH_6 && capinfo->bpp > 8 && (get_parameter(F_PALETTE_CONTROL) == PALETTECONTROL_C64_LUMACODE || get_parameter(F_PALETTE_CONTROL) == PALETTECONTROL_C64_YUV)
|
|
&& (get_parameter(F_NTSC_COLOUR) == 0 || (capinfo->sizex2 & SIZEX2_DOUBLE_WIDTH) == 0)) {
|
|
capinfo->bpp = 8; //force 8bpp in 6 bit modes when pal artifact disabled
|
|
} else if (capinfo->sample_width == SAMPLE_WIDTH_6 && capinfo->bpp > 8 && (get_parameter(F_PALETTE_CONTROL) == PALETTECONTROL_ATARI_LUMACODE)
|
|
&& (get_parameter(F_SCANLINES) == 0 || (capinfo->sizex2 & SIZEX2_DOUBLE_WIDTH) == 0)) {
|
|
capinfo->bpp = 8; //force 8bpp in 6 bit modes when scanlines disabled
|
|
} else if (capinfo->sample_width == SAMPLE_WIDTH_6 && capinfo->bpp > 8 && (get_parameter(F_PALETTE_CONTROL) == PALETTECONTROL_ATARI_GTIA || get_parameter(F_PALETTE_CONTROL) == PALETTECONTROL_ATARI2600_LUMACODE)) {
|
|
capinfo->bpp = 8; //force 8bpp in 6 bit modes when Atari GTIA or 2600 as no 16 bit capture loops
|
|
} else if (capinfo->sample_width == SAMPLE_WIDTH_6 && capinfo->bpp > 8
|
|
&& get_parameter(F_PALETTE_CONTROL) >= PALETTECONTROL_NTSCARTIFACT_CGA && get_parameter(F_PALETTE_CONTROL) <= PALETTECONTROL_NTSCARTIFACT_BW_AUTO
|
|
&& (get_core_1_available() == 0 || get_parameter(F_NTSC_TYPE) == NTSCTYPE_SIMPLE)) {
|
|
capinfo->bpp = 8; //force 8bpp in 6 bit modes when simple ntsc artifact
|
|
} else if (capinfo->sample_width <= SAMPLE_WIDTH_3 && capinfo->bpp > 8) {
|
|
capinfo->bpp = 8; //force 8bpp in 1 & 3 bit modes as no capture loops for 1 or 3 bit capture into 16bpp buffer
|
|
}
|
|
|
|
#ifdef USE_ARM_CAPTURE
|
|
if ((_get_hardware_id() == _RPI2 || _get_hardware_id() == _RPI3) && capinfo->video_type != VIDEO_TELETEXT) {
|
|
capinfo->sizex2 &= SIZEX2_DOUBLE_WIDTH; //in ARM build have to inhibit double height on Pi Zero 2Pi2 / Pi 3 otherwise you get stalling
|
|
}
|
|
if (_get_hardware_id() == _RPI && capinfo->video_type != VIDEO_TELETEXT && capinfo->sample_width >= SAMPLE_WIDTH_9LO) {
|
|
capinfo->sizex2 &= SIZEX2_DOUBLE_WIDTH; //in ARM build have to inhibit double height on Pi zero / Pi 1 in 9/12bpp capture
|
|
}
|
|
#endif
|
|
|
|
if (capinfo->bpp <= 8 && get_parameter(F_SCANLINES) && (get_parameter(F_PALETTE_CONTROL) == PALETTECONTROL_ATARI_LUMACODE || get_parameter(F_PALETTE_CONTROL) == PALETTECONTROL_ATARI_GTIA)) {
|
|
capinfo->sizex2 &= SIZEX2_DOUBLE_WIDTH; //inhibit double height for Atari 800 in 8bpp mode
|
|
}
|
|
|
|
if ((capinfo->detected_sync_type & SYNC_BIT_INTERLACED) && capinfo->video_type != VIDEO_PROGRESSIVE) {
|
|
capinfo->sizex2 |= SIZEX2_DOUBLE_HEIGHT;
|
|
} else {
|
|
if (get_parameter(F_SCANLINES) && !(menu_active() || osd_active())) {
|
|
if ((capinfo->sizex2 & SIZEX2_DOUBLE_HEIGHT) == 0) {
|
|
capinfo->sizex2 |= SIZEX2_BASIC_SCANLINES; //flag basic scanlines
|
|
}
|
|
capinfo->sizex2 |= SIZEX2_DOUBLE_HEIGHT; // force double height
|
|
}
|
|
}
|
|
|
|
if (get_true_vdisplay() <= 288) {
|
|
capinfo->sizex2 &= SIZEX2_DOUBLE_WIDTH; //inhibit double height when using 288 or 240 pixel modes
|
|
}
|
|
|
|
int geometry_h_offset = geometry->h_offset;
|
|
int geometry_v_offset = geometry->v_offset;
|
|
int geometry_min_h_width = geometry->min_h_width;
|
|
int geometry_min_v_height = geometry->min_v_height;
|
|
int geometry_max_h_width = geometry->max_h_width;
|
|
int geometry_max_v_height = geometry->max_v_height;
|
|
int h_aspect = geometry->h_aspect;
|
|
int v_aspect = geometry->v_aspect;
|
|
|
|
if (get_parameter(F_SWAP_ASPECT)) {
|
|
if (geometry->lines_per_frame > 287) {
|
|
if (h_aspect == v_aspect) {
|
|
h_aspect = 4;
|
|
v_aspect = 5;
|
|
} else if ((h_aspect << 1) == v_aspect) {
|
|
h_aspect = 2;
|
|
v_aspect = 5;
|
|
} else if (h_aspect == (v_aspect << 1)) {
|
|
h_aspect = 8;
|
|
v_aspect = 5;
|
|
} else if (h_aspect == 7 && v_aspect == 4) {
|
|
v_aspect = 5;
|
|
}
|
|
if (geometry_min_v_height > 250) {
|
|
geometry_min_v_height = geometry_min_v_height * 4 / 5;
|
|
}
|
|
geometry_max_v_height = geometry_max_v_height * 4 / 5;
|
|
} else {
|
|
if (h_aspect == 4 && v_aspect == 5) {
|
|
v_aspect = 4;
|
|
} else if (h_aspect == 2 && v_aspect == 5) {
|
|
v_aspect = 4;
|
|
} else if (h_aspect == 8 && v_aspect == 5) {
|
|
v_aspect = 4;
|
|
} else if (h_aspect == 7 && v_aspect == 5) {
|
|
v_aspect = 4;
|
|
}
|
|
//geometry_max_v_height = geometry_max_v_height * 5 / 4;
|
|
}
|
|
}
|
|
|
|
//if (get_parameter(F_CROP_BORDER) == OVERSCAN_AUTO && (geometry->setup_mode == SETUP_NORMAL || geometry->setup_mode == SETUP_CLOCK)) {
|
|
//reduce max area by 4% to hide offscreen imperfections
|
|
// geometry_max_h_width = ((geometry_max_h_width * 96) / 100) & 0xfffffff8;
|
|
// geometry_max_v_height = ((geometry_max_v_height * 96) / 100) & 0xfffffffe;
|
|
//}
|
|
|
|
if (geometry_max_h_width < geometry_min_h_width) {
|
|
geometry_max_h_width = geometry_min_h_width;
|
|
}
|
|
if (geometry_max_v_height < geometry_min_v_height) {
|
|
geometry_max_v_height = geometry_min_v_height;
|
|
}
|
|
|
|
if (use_px_sampling != 0) {
|
|
capinfo->px_sampling = geometry->px_sampling;
|
|
} else {
|
|
capinfo->px_sampling = 0;
|
|
}
|
|
|
|
if (geometry->setup_mode == SETUP_NORMAL) {
|
|
if (((get_parameter(F_PALETTE_CONTROL) == PALETTECONTROL_NTSCARTIFACT_CGA && get_parameter(F_NTSC_COLOUR) != 0)
|
|
|| (get_parameter(F_PALETTE_CONTROL) == PALETTECONTROL_NTSCARTIFACT_BW)
|
|
|| (get_parameter(F_PALETTE_CONTROL) == PALETTECONTROL_NTSCARTIFACT_BW_AUTO))
|
|
&& capinfo->bpp == 8 && capinfo->sample_width <= SAMPLE_WIDTH_6) {
|
|
capinfo->border = get_parameter(F_BORDER_COLOUR);
|
|
} else {
|
|
capinfo->border = get_parameter(F_BORDER_COLOUR);
|
|
if (get_parameter(F_OUTPUT_INVERT) == INVERT_Y) {
|
|
capinfo->border ^= 0x12;
|
|
}
|
|
}
|
|
} else {
|
|
capinfo->border = 0x12; // max green/Y
|
|
}
|
|
|
|
capinfo->ntscphase = get_adjusted_ntscphase() | (get_parameter(F_NTSC_COLOUR) << NTSC_ARTIFACT_SHIFT);
|
|
if (get_parameter(F_OUTPUT_INVERT) == INVERT_Y) {
|
|
capinfo->ntscphase |= NTSC_Y_INVERT;
|
|
}
|
|
if (get_parameter(F_OUTPUT_INVERT) == INVERT_RGB) {
|
|
capinfo->ntscphase |= NTSC_RGB_INVERT;
|
|
}
|
|
if (get_parameter(F_HDMI_MODE_STANDBY)) {
|
|
capinfo->ntscphase |= NTSC_HDMI_BLANK_ENABLE;
|
|
}
|
|
|
|
if (get_parameter(F_FFOSD)) {
|
|
capinfo->ntscphase |= NTSC_FFOSD_ENABLE;
|
|
}
|
|
|
|
get_config_overscan(&left, &right, &top, &bottom);
|
|
int h_size = get_hdisplay() - left - right;
|
|
int v_size = get_vdisplay() - top - bottom;
|
|
|
|
double ratio = (double) h_size / v_size;
|
|
int h_size43 = h_size;
|
|
int v_size43 = v_size;
|
|
|
|
|
|
if (scaling == GSCALING_INTEGER) {
|
|
if (ratio > 1.34) {
|
|
h_size43 = v_size * 4 / 3;
|
|
}
|
|
if (ratio < 1.24) { // was 1.32 but don't correct 5:4 aspect ratio (1.25) to 4:3 as it does good integer scaling for 640x256 and 640x200
|
|
v_size43 = h_size * 3 / 4;
|
|
}
|
|
} else {
|
|
if (ratio > 1.34) {
|
|
h_size43 = v_size * 4 / 3;
|
|
}
|
|
if (ratio < 1.24) {
|
|
v_size43 = h_size * 3 / 4;
|
|
}
|
|
}
|
|
|
|
if (scaling == GSCALING_INTEGER && v_size43 == v_size && h_size > h_size43) {
|
|
//if ((geometry_max_h_width >= 512 && geometry_max_h_width <= 800) || (geometry_max_h_width > 360 && geometry_max_h_width <= 400)) {
|
|
//h_size43 = (h_size43 * 912) / 720; //adjust 4:3 ratio on widescreen resolutions to account for up to 900 pixel wide integer sample capture
|
|
if (geometry_min_h_width > 800) {
|
|
h_size43 = h_size;
|
|
} else {
|
|
h_size43 = (h_size43 * 800) / 720; //adjust 4:3 ratio on widescreen resolutions to account for up to 800 pixel wide integer sample capture
|
|
}
|
|
|
|
//if (h_size43 > h_size) {
|
|
// h_size43 = h_size;
|
|
//}
|
|
}
|
|
|
|
int double_width = (capinfo->sizex2 & SIZEX2_DOUBLE_WIDTH) >> 1;
|
|
int double_height = capinfo->sizex2 & SIZEX2_DOUBLE_HEIGHT;
|
|
if ((geometry_min_h_width << double_width) > h_size43) {
|
|
double_width = 0;
|
|
}
|
|
if ((geometry_min_v_height << double_height) > v_size43) {
|
|
double_height = 0;
|
|
}
|
|
if (double_height && (capinfo->sizex2 & SIZEX2_BASIC_SCANLINES)) {
|
|
capinfo->sizex2 = double_height | (double_width << 1) | SIZEX2_BASIC_SCANLINES;
|
|
} else {
|
|
capinfo->sizex2 = double_height | (double_width << 1);
|
|
}
|
|
|
|
//log_info("unadjusted integer = %d, %d, %d, %d, %d, %d", geometry_h_offset, geometry_v_offset, geometry_min_h_width, geometry_min_v_height, geometry_max_h_width, geometry_max_v_height);
|
|
|
|
switch (geometry->setup_mode) {
|
|
case SETUP_NORMAL:
|
|
case SETUP_CLOCK:
|
|
case SETUP_FINE:
|
|
default:
|
|
{
|
|
int scaled_min_h_width;
|
|
int scaled_min_v_height;
|
|
double max_aspect = (double)geometry_max_h_width / (double)geometry_max_v_height;
|
|
double min_aspect = (double)geometry_min_h_width / (double)geometry_min_v_height;
|
|
if (min_aspect > max_aspect) {
|
|
scaled_min_h_width = geometry_min_h_width;
|
|
scaled_min_v_height = ((int)((double)scaled_min_h_width / max_aspect));
|
|
if (scaled_min_v_height < geometry_min_v_height) {
|
|
scaled_min_v_height = geometry_min_v_height;
|
|
}
|
|
} else {
|
|
scaled_min_v_height = geometry_min_v_height;
|
|
scaled_min_h_width = ((int)((double)scaled_min_v_height * max_aspect));
|
|
if (scaled_min_h_width < geometry_min_h_width) {
|
|
scaled_min_h_width = geometry_min_h_width;
|
|
}
|
|
}
|
|
geometry_max_h_width = (geometry_max_h_width - ((geometry_max_h_width - scaled_min_h_width) * get_parameter(F_CROP_BORDER) / (NUM_OVERSCAN - 1))) & 0xfffffff8;
|
|
geometry_max_v_height = (geometry_max_v_height - ((geometry_max_v_height - scaled_min_v_height) * get_parameter(F_CROP_BORDER) / (NUM_OVERSCAN - 1))) & 0xfffffffe;
|
|
if (geometry_max_h_width < geometry_min_h_width) {
|
|
geometry_max_h_width = geometry_min_h_width;
|
|
}
|
|
if (geometry_max_v_height < geometry_min_v_height) {
|
|
geometry_max_v_height = geometry_min_v_height;
|
|
}
|
|
if (scaling != GSCALING_INTEGER) {
|
|
geometry_h_offset = geometry_h_offset - (((geometry_max_h_width - geometry_min_h_width) >> 3) << 2);
|
|
geometry_v_offset = geometry_v_offset - ((geometry_max_v_height - geometry_min_v_height) >> 1);
|
|
geometry_min_h_width = geometry_max_h_width;
|
|
geometry_min_v_height = geometry_max_v_height;
|
|
}
|
|
}
|
|
break;
|
|
case SETUP_MIN:
|
|
geometry_max_h_width = geometry_min_h_width;
|
|
geometry_max_v_height = geometry_min_v_height;
|
|
break;
|
|
case SETUP_MAX:
|
|
geometry_h_offset = geometry_h_offset - (((geometry_max_h_width - geometry_min_h_width) >> 3) << 2);
|
|
geometry_v_offset = geometry_v_offset - ((geometry_max_v_height - geometry_min_v_height) >> 1);
|
|
geometry_min_h_width = geometry_max_h_width;
|
|
geometry_min_v_height = geometry_max_v_height;
|
|
break;
|
|
|
|
}
|
|
|
|
//log_info("adjusted integer = %d, %d, %d, %d, %d, %d", geometry_h_offset, geometry_v_offset, geometry_min_h_width, geometry_min_v_height, geometry_max_h_width, geometry_max_v_height);
|
|
|
|
int h_size43_adj = h_size43;
|
|
if ((capinfo->mode7 && get_parameter(F_MODE7_SCALING) == SCALING_UNEVEN)
|
|
|| (!capinfo->mode7 && get_parameter(F_NORMAL_SCALING) == SCALING_UNEVEN && geometry->h_aspect == 3 && (geometry->v_aspect == 2 || geometry->v_aspect == 4))) {
|
|
h_size43_adj = h_size43 * 3 / 4;
|
|
if (h_aspect == 3 && v_aspect == 2) {
|
|
h_aspect = 1;
|
|
v_aspect = 1;
|
|
} else if (h_aspect == 3 && v_aspect == 4) {
|
|
h_aspect = 1;
|
|
v_aspect = 2;
|
|
}
|
|
}
|
|
|
|
int hscale = h_size43_adj / geometry_min_h_width;
|
|
int vscale = v_size43 / geometry_min_v_height;
|
|
if (hscale < 1) {
|
|
hscale = 1;
|
|
}
|
|
if (vscale < 1) {
|
|
vscale = 1;
|
|
}
|
|
|
|
|
|
if (get_hdisplay() > 3000 && hscale > 4 && vscale > 4) { //even up scaling of small sources on 4K monitors
|
|
hscale = (hscale >> 1) << 1;
|
|
vscale = (vscale >> 1) << 1;
|
|
}
|
|
|
|
if (h_aspect != 0 && v_aspect !=0 && get_parameter(F_INTEGER_ASPECT) == 0) {
|
|
int new_hs = hscale;
|
|
int new_vs = vscale;
|
|
double h_ratio;
|
|
double v_ratio;
|
|
int abort_count = 0;
|
|
do {
|
|
h_ratio = (double)hscale / h_aspect;
|
|
v_ratio = (double)vscale / v_aspect;
|
|
if (h_ratio != v_ratio) {
|
|
if (h_ratio > v_ratio) {
|
|
new_hs = ((int)v_ratio) * h_aspect;
|
|
} else {
|
|
new_vs = ((int)h_ratio) * v_aspect;
|
|
}
|
|
//log_info("Aspect doesn't match: %d, %d, %d, %d, %f, %f, %d, %d", hscale, vscale, h_aspect, v_aspect, h_ratio, v_ratio, new_hs, new_vs);
|
|
if (new_hs !=0 && new_vs != 0) {
|
|
hscale = new_hs;
|
|
vscale = new_vs;
|
|
|
|
}
|
|
//log_info("Aspect after loop: %d, %d", hscale, vscale);
|
|
}
|
|
abort_count++;
|
|
} while (new_hs !=0 && new_vs != 0 && h_ratio != v_ratio && abort_count < 10);
|
|
}
|
|
//log_info("Final aspect: %d, %d", hscale, vscale);
|
|
|
|
if (scaling == GSCALING_INTEGER) {
|
|
int new_geometry_min_h_width = h_size43_adj / hscale;
|
|
if (new_geometry_min_h_width > geometry_max_h_width) {
|
|
new_geometry_min_h_width = geometry_max_h_width;
|
|
}
|
|
int new_geometry_min_v_height = v_size43 / vscale;
|
|
if (new_geometry_min_v_height > geometry_max_v_height) {
|
|
new_geometry_min_v_height = geometry_max_v_height;
|
|
}
|
|
geometry_h_offset = geometry_h_offset - (((new_geometry_min_h_width - geometry_min_h_width) >> 3) << 2);
|
|
geometry_v_offset = geometry_v_offset - ((new_geometry_min_v_height - geometry_min_v_height) >> 1);
|
|
geometry_min_h_width = new_geometry_min_h_width;
|
|
geometry_min_v_height = new_geometry_min_v_height;
|
|
}
|
|
|
|
capinfo->delay = (cpld->get_delay() ^ 3) & 3; // save delay for simple mode software implementation
|
|
|
|
geometry_h_offset = geometry_h_offset * lumacode_multiplier() - ((cpld->get_delay() >> 2) << 2);
|
|
|
|
if (geometry_h_offset < 0) {
|
|
geometry_min_h_width += (geometry_h_offset << 1);
|
|
geometry_h_offset = 0;
|
|
}
|
|
if (geometry_v_offset < 0) {
|
|
geometry_min_v_height += (geometry_v_offset << 1);
|
|
geometry_v_offset = 0;
|
|
}
|
|
|
|
//log_info("adjusted integer2 = %d, %d, %d, %d, %d, %d, %d", cpld->get_delay() >> 2, geometry_h_offset, geometry_v_offset, geometry_min_h_width, geometry_min_v_height, geometry_max_h_width, geometry_max_v_height);
|
|
|
|
switch (capinfo->sample_width) {
|
|
case SAMPLE_WIDTH_1 :
|
|
capinfo->h_offset = geometry_h_offset >> 3;
|
|
break;
|
|
default:
|
|
case SAMPLE_WIDTH_3:
|
|
capinfo->h_offset = geometry_h_offset >> 2;
|
|
break;
|
|
case SAMPLE_WIDTH_6 :
|
|
capinfo->h_offset = (geometry_h_offset >> 2) << 1;
|
|
break;
|
|
case SAMPLE_WIDTH_9LO :
|
|
case SAMPLE_WIDTH_9HI :
|
|
case SAMPLE_WIDTH_12 :
|
|
capinfo->h_offset = (geometry_h_offset >> 2) << 2;
|
|
break;
|
|
}
|
|
|
|
capinfo->v_offset = geometry_v_offset;
|
|
|
|
|
|
capinfo->chars_per_line = ((geometry_min_h_width + 7) >> 3) << double_width;
|
|
capinfo->nlines = geometry_min_v_height;
|
|
|
|
//log_info("scaling size = %d, %d, %d, %f",standard_width, adjusted_width, adjusted_height, ratio);
|
|
//log_info("scaling h = %d, %d, %f, %d, %d, %d, %d",h_size, h_size43, hscalef, hscale, hborder, hborder43, newhborder43);
|
|
//log_info("scaling v = %d, %d, %f, %d, %d, %d, %d",v_size, v_size43, vscalef, vscale, vborder, vborder43, newvborder43);
|
|
|
|
caphscale = hscale;
|
|
capvscale = vscale;
|
|
|
|
if (caphscale == capvscale) {
|
|
caphscale = 1;
|
|
capvscale = 1;
|
|
}
|
|
while ((caphscale & 1) == 0 && (capvscale & 1) == 0) {
|
|
caphscale >>= 1;
|
|
capvscale >>= 1;
|
|
}
|
|
|
|
fhaspect = caphscale;
|
|
fvaspect = capvscale;
|
|
|
|
if (caphscale == 1 && capvscale == 1 && geometry->min_h_width < 512) {
|
|
caphscale = 2;
|
|
capvscale = 2;
|
|
}
|
|
|
|
//log_info("Final aspect: %dx%d, %dx%d, %dx%d %d", h_aspect, v_aspect, hscale, vscale, caphscale, capvscale, geometry_min_h_width );
|
|
|
|
switch (scaling) {
|
|
case GSCALING_INTEGER:
|
|
{
|
|
|
|
int adjusted_width = geometry_min_h_width << double_width;
|
|
int adjusted_height = geometry_min_v_height << double_height;
|
|
|
|
int hborder = ((h_size - geometry_min_h_width * hscale) << double_width) / hscale;
|
|
if ((hborder + adjusted_width) > h_size) {
|
|
log_info("Handling invalid H ratio");
|
|
hborder = (h_size - adjusted_width) / hscale;
|
|
}
|
|
|
|
int vborder = ((v_size - geometry_min_v_height * vscale) << double_height) / vscale;
|
|
if ((vborder + adjusted_height) > v_size) {
|
|
log_info("Handling invalid V ratio");
|
|
vborder = (v_size - adjusted_height) / vscale;
|
|
}
|
|
|
|
capinfo->width = adjusted_width + hborder;
|
|
capinfo->height = adjusted_height + vborder;
|
|
|
|
if ((capinfo->mode7 && get_parameter(F_MODE7_SCALING) == SCALING_UNEVEN) // workaround mode 7 width so it looks like other modes
|
|
||(!capinfo->mode7 && get_parameter(F_NORMAL_SCALING) == SCALING_UNEVEN && geometry->h_aspect == 3 && (geometry->v_aspect == 2 || geometry->v_aspect == 4))) {
|
|
capinfo->width = capinfo->width * 3 / 4;
|
|
}
|
|
|
|
if (get_parameter(F_SCREENCAP_SIZE) == SCREENCAP_FULL || get_parameter(F_SCREENCAP_SIZE) == SCREENCAP_FULL43) {
|
|
caphscale = ((h_size << double_width) / capinfo->width);
|
|
capvscale = ((v_size << double_height) / capinfo->height);
|
|
}
|
|
}
|
|
break;
|
|
case GSCALING_MANUAL43:
|
|
{
|
|
double hscalef = (double) h_size43 / geometry_min_h_width;
|
|
double vscalef = (double) v_size43 / geometry_min_v_height;
|
|
capinfo->width = (geometry_max_h_width << double_width ) + (int)((double)((h_size - h_size43) << double_width) / hscalef);
|
|
capinfo->height = (geometry_max_v_height << double_height) + (int)((double)((v_size - v_size43) << double_height) / vscalef);
|
|
}
|
|
break;
|
|
case GSCALING_MANUAL:
|
|
{
|
|
capinfo->width = geometry_max_h_width << double_width; //adjust the width for capinfo according to sizex2 setting;
|
|
capinfo->height = geometry_max_v_height << double_height; //adjust the height for capinfo according to sizex2 setting
|
|
}
|
|
break;
|
|
};
|
|
|
|
capinfo->width &= 0xfffffffe;
|
|
capinfo->height &= 0xfffffffe;
|
|
|
|
/*
|
|
int pitchinchars = capinfo->pitch;
|
|
|
|
switch(capinfo->bpp) {
|
|
case 4:
|
|
pitchinchars >>= 2;
|
|
break;
|
|
case 8:
|
|
pitchinchars >>= 3;
|
|
break;
|
|
case 16:
|
|
pitchinchars >>= 4;
|
|
break;
|
|
}
|
|
|
|
if (capinfo->chars_per_line > pitchinchars) {
|
|
//log_info("Clipping capture width to pitch: %d, %d", capinfo->chars_per_line, pitchinchars);
|
|
capinfo->chars_per_line = pitchinchars;
|
|
}
|
|
*/
|
|
|
|
if (capinfo->nlines > (capinfo->height >> double_height)) {
|
|
capinfo->nlines = (capinfo->height >> double_height);
|
|
}
|
|
int lines = get_lines_per_vsync(1);
|
|
int width = get_vsync_width_lines();
|
|
if ((capinfo->nlines + capinfo->v_offset) > (lines - width - 1)) {
|
|
capinfo->nlines = (lines - width - 1) - capinfo->v_offset;
|
|
//log_info("Clipping capture height to %d", capinfo->nlines);
|
|
}
|
|
|
|
if (capinfo->video_type != VIDEO_PROGRESSIVE && capinfo->detected_sync_type & SYNC_BIT_INTERLACED) {
|
|
capvscale >>= 1;
|
|
if (double_width) {
|
|
caphscale >>= 1;
|
|
}
|
|
} else {
|
|
if (osd_active() || get_parameter(F_SCANLINES)) {
|
|
if (double_width) {
|
|
caphscale >>= 1;
|
|
}
|
|
if (double_height) {
|
|
capvscale >>= 1;
|
|
}
|
|
} else {
|
|
if (double_width) {
|
|
caphscale |= 0x80000000;
|
|
}
|
|
if (double_height) {
|
|
capvscale |= 0x80000000;
|
|
}
|
|
}
|
|
}
|
|
//log_info("Final aspect2: %dx%d, %dx%d, %dx%d", h_aspect, v_aspect, hscale, vscale, caphscale, capvscale);
|
|
calculate_cpu_timings();
|
|
//log_info("size= %d, %d, %d, %d, %d, %d, %d",capinfo->chars_per_line, capinfo->nlines, geometry_min_h_width, geometry_min_v_height,capinfo->width, capinfo->height, capinfo->sizex2);
|
|
|
|
if (geometry->video_type == VIDEO_LINE_DOUBLED && (capinfo->sizex2 & SIZEX2_DOUBLE_HEIGHT) != 0) {
|
|
capinfo->nlines <<= 1;
|
|
capinfo->sizex2 &= SIZEX2_DOUBLE_WIDTH;
|
|
}
|
|
|
|
int uneven = ((capinfo->mode7 && get_parameter(F_MODE7_SCALING) == SCALING_UNEVEN) ||(!capinfo->mode7 && get_parameter(F_NORMAL_SCALING) == SCALING_UNEVEN));
|
|
|
|
if (get_startup_overscan() != 0) { //for 16bpp modes reduce the screen area to the actual capture size and make up the rest with overscan on Pi zero due to bandwidth issues
|
|
int apparent_width = get_hdisplay();
|
|
int apparent_height = get_vdisplay();
|
|
double_width = (capinfo->sizex2 & SIZEX2_DOUBLE_WIDTH) >> 1;
|
|
double_height = capinfo->sizex2 & SIZEX2_DOUBLE_HEIGHT;
|
|
hscale >>= double_width;
|
|
//if (_get_hardware_id() == _RPI && !uneven && (capinfo->bpp == 16 || (capinfo->bpp != 16 && capinfo->nlines > 288))) {
|
|
if (_get_hardware_id() == _RPI && capinfo->bpp == 16 && !uneven && get_true_vdisplay() > 288) {
|
|
if (get_gscaling() == GSCALING_INTEGER) {
|
|
int actual_width = (capinfo->chars_per_line << 3);
|
|
int actual_height = capinfo->nlines;
|
|
left = (apparent_width - (actual_width * hscale)) / 2;
|
|
top = (apparent_height - (actual_height * vscale)) / 2;
|
|
if (left >=0 && top >=0) {
|
|
right = left;
|
|
bottom = top;
|
|
capinfo->width = actual_width;
|
|
capinfo->height = actual_height << double_height;
|
|
} else {
|
|
left = 0;
|
|
right = 0;
|
|
top = 0;
|
|
bottom = 0;
|
|
}
|
|
//log_info("sizes = %d %d %d %d %d %d %d %d %d %d", apparent_width,apparent_height,actual_width, actual_height ,hscale,vscale,left,right,top,bottom);
|
|
} else {
|
|
top = 0;
|
|
bottom = 0;
|
|
double aspect = (double) apparent_width / (double) apparent_height;
|
|
int apparent_width_limit = (apparent_width * 1600 / 1920) & ~1;
|
|
if (aspect >= 1.6 && get_gscaling() != GSCALING_MANUAL) {
|
|
left = (apparent_width - apparent_width_limit) / 2;
|
|
right = left;
|
|
capinfo->width = capinfo->width * 1600 / 1920;
|
|
} else {
|
|
left = 0;
|
|
right = 0;
|
|
}
|
|
|
|
//log_info("sizes = %d %d %d %d", apparent_width,capinfo->width, left,right);
|
|
}
|
|
} else {
|
|
left = 0;
|
|
right = 0;
|
|
top = 0;
|
|
bottom = 0;
|
|
}
|
|
set_config_overscan(left, right, top, bottom);
|
|
}
|
|
|
|
}
|
|
|
|
int get_hscale() {
|
|
return caphscale;
|
|
}
|
|
int get_vscale() {
|
|
return capvscale;
|
|
}
|
|
int get_haspect() {
|
|
return fhaspect;
|
|
}
|
|
int get_vaspect() {
|
|
return fvaspect;
|
|
}
|
|
|
|
int get_hdisplay() {
|
|
int v_size = (*PIXELVALVE2_VERTB) & 0xFFFF;
|
|
#if defined(RPI4)
|
|
int h_size = ((*PIXELVALVE2_HORZB) & 0xFFFF) << 1;
|
|
if (v_size <= 288) {
|
|
h_size <<= 1;
|
|
}
|
|
if (h_size == 0 && v_size == 0) {
|
|
#else
|
|
int h_size = (*PIXELVALVE2_HORZB) & 0xFFFF;
|
|
if (h_size == 720 && v_size == 240) {
|
|
#endif
|
|
log_info("HDMI readback of screen size indicates HDMI not connected (%dx%d) - rebooting", h_size, v_size);
|
|
delay_in_arm_cycles_cpu_adjust(1000000000);
|
|
reboot();
|
|
}
|
|
//workaround for 640x480 and 800x480 @50Hz using double rate clock so width gets doubled
|
|
if (v_size == 480 && h_size == 1280) {
|
|
h_size = 640;
|
|
} else if (v_size == 480 && h_size == 1600) {
|
|
h_size = 800;
|
|
} else if (v_size <= 288) {
|
|
h_size >>= 1;
|
|
}
|
|
return h_size;
|
|
}
|
|
|
|
int get_vdisplay() {
|
|
int v_size = (*PIXELVALVE2_VERTB) & 0xFFFF;
|
|
if (v_size == 2160 && get_hdisplay() == 1920){
|
|
v_size = 1080;
|
|
} else if (v_size <= 288) {
|
|
v_size <<= 1;
|
|
}
|
|
return v_size;
|
|
}
|
|
|
|
int get_true_vdisplay() {
|
|
int v_size = (*PIXELVALVE2_VERTB) & 0xFFFF;
|
|
return v_size;
|
|
}
|
|
|
|
void geometry_get_clk_params(clk_info_t *clkinfo) {
|
|
clkinfo->clock = geometry->clock;
|
|
clkinfo->line_len = (double) geometry->line_len;
|
|
// workaround for 16.363Mhz Apple II GS pixel clock
|
|
if (clkinfo->clock > 16250000 && clkinfo->clock < 16370000 && clkinfo->line_len == 1042) {
|
|
clkinfo->line_len = 1042.285714285f;
|
|
}
|
|
clkinfo->lines_per_frame = geometry->lines_per_frame;
|
|
if (geometry->setup_mode == SETUP_NORMAL) {
|
|
clkinfo->clock_ppm = geometry->clock_ppm;
|
|
} else {
|
|
clkinfo->clock_ppm = 0;
|
|
}
|
|
}
|
|
|
|
void geometry_hide_pixel_sampling() {
|
|
params[PX_SAMPLING].key = -1;
|
|
use_px_sampling = 0;
|
|
}
|