Pi Firmware: Added alternative pixel sampling modes (subsample, pixel double)

Change-Id: If6a1bd8219cc5a4d650a63692f07f922e40e3d7e
pull/29/head
David Banks 2018-12-13 15:38:34 +00:00
rodzic 75e7d7cf59
commit 522138da0d
11 zmienionych plików z 250 dodań i 44 usunięć

Wyświetl plik

@ -63,6 +63,8 @@ file( GLOB core_files
rgb_to_hdmi.c
rgb_to_fb.S
capture_line_default_4bpp.S
capture_line_default_4bpp_double.S
capture_line_default_4bpp_subsample.S
capture_line_default_8bpp.S
capture_line_atom_4bpp.S
capture_line_atom_8bpp.S

Wyświetl plik

@ -0,0 +1,68 @@
#include "rpi-base.h"
#include "defs.h"
#include "macros.S"
.text
.global capture_line_default_4bpp_double
.macro CAPTURE_BITS_DOUBLE
// Pixel 0 in GPIO 4.. 2 -> 7.. 4 and 3.. 0
// Pixel 1 in GPIO 7.. 5 -> 15..12 and 11.. 8
// Pixel 2 in GPIO 10.. 8 -> 23..20 and 19..16
// Pixel 3 in GPIO 13..11 -> 31..28 and 27..24
and r10, r8, #(7 << PIXEL_BASE)
and r9, r8, #(7 << (PIXEL_BASE + 3))
mov r10, r10, lsl #(4 - PIXEL_BASE)
orr r10, r10, r9, lsl #(12 - (PIXEL_BASE + 3))
and r9, r8, #(7 << (PIXEL_BASE + 6))
and r8, r8, #(7 << (PIXEL_BASE + 9))
orr r10, r10, r9, lsl #(20 - (PIXEL_BASE + 6))
orr r10, r10, r8, lsl #(28 - (PIXEL_BASE + 9))
// Pixel double
orr r10, r10, lsr #4
.endm
// The capture line function is provided the following:
// r0 = pointer to current line in frame buffer
// r1 = number of 8-pixel blocks to capture (=param_chars_per_line)
// r2 = frame buffer line pitch in bytes (=param_fb_pitch)
// r3 = flags register
// r4 = GPLEV0 constant
// r5 = frame buffer height (=param_fb_height)
// r6 = scan line count modulo 10
//
// All registers are available as scratch registers (i.e. nothing needs to be preserved)
capture_line_default_4bpp_double:
push {lr}
mov r6, #0
mov r7, #0
tst r3, #BIT_VSYNC_MARKER
ldrne r7, =0x11111111
loop:
WAIT_FOR_PSYNC_EDGE // expects GPLEV0 in r4, result in r8
CAPTURE_BITS_DOUBLE // input in r8, result in r10, corrupts r9/r14
// Orr in the VSync indicator
orr r10, r10, r7
// Line double always in Modes 0-6 regardless of interlace
// On the multi core Pi this introduces stalling artefacts
#ifndef HAS_MULTICORE
tst r3, #BIT_SCANLINES
streq r10, [r0, r2]
strne r6, [r0, r2]
#endif
str r10, [r0], #4
subs r1, r1, #1
bne loop
pop {pc}

Wyświetl plik

@ -0,0 +1,83 @@
#include "rpi-base.h"
#include "defs.h"
#include "macros.S"
.text
.global capture_line_default_4bpp_subsample
.macro CAPTURE_LOW_BITS_SUBSAMPLE
// Pixel 0 in GPIO 4.. 2 -> 7.. 4
// Pixel 1 ignored
// Pixel 2 in GPIO 10.. 8 -> 15..12
// Pixel 3 ignored
and r10, r8, #(7 << PIXEL_BASE)
mov r10, r10, lsl #(4 - PIXEL_BASE)
and r9, r8, #(7 << (PIXEL_BASE + 6))
orr r10, r10, r9, lsl #(6 - PIXEL_BASE)
.endm
.macro CAPTURE_HIGH_BITS_SUBSAMPLE
// Pixel 4 in GPIO 4.. 2 -> 23..20
// Pixel 5 ignored
// Pixel 6 in GPIO 10.. 8 -> 31..28
// Pixel 7 ignored
and r9, r8, #(7 << PIXEL_BASE)
orr r10, r10, r9, lsl #(20 - PIXEL_BASE)
and r9, r8, #(7 << (PIXEL_BASE + 6))
orr r10, r10, r9, lsl #(22 - PIXEL_BASE)
.endm
// The capture line function is provided the following:
// r0 = pointer to current line in frame buffer
// r1 = number of 8-pixel blocks to capture (=param_chars_per_line)
// r2 = frame buffer line pitch in bytes (=param_fb_pitch)
// r3 = flags register
// r4 = GPLEV0 constant
// r5 = frame buffer height (=param_fb_height)
// r6 = scan line count modulo 10
//
// All registers are available as scratch registers (i.e. nothing needs to be preserved)
capture_line_default_4bpp_subsample:
push {lr}
mov r6, #0
mov r7, #0
tst r3, #BIT_VSYNC_MARKER
ldrne r7, =0x11111111
loop:
WAIT_FOR_PSYNC_EDGE // expects GPLEV0 in r4, result in r8
CAPTURE_LOW_BITS_SUBSAMPLE // input in r8, result in r10, corrupts r9/r14
WAIT_FOR_PSYNC_EDGE // expects GPLEV0 in r4, result in r8
CAPTURE_HIGH_BITS_SUBSAMPLE // input in r8, result in r10, corrupts r9/r14
// Pixel double
orr r10, r10, lsr #4
// Orr in the VSync indicator
orr r10, r10, r7
// Line double always in Modes 0-6 regardless of interlace
// On the multi core Pi this introduces stalling artefacts
#ifndef HAS_MULTICORE
tst r3, #BIT_SCANLINES
streq r10, [r0, r2]
strne r6, [r0, r2]
#endif
str r10, [r0], #4
subs r1, r1, #1
bne loop
pop {pc}

Wyświetl plik

@ -5,6 +5,7 @@
#include <string.h>
#include "defs.h"
#include "cpld.h"
#include "geometry.h"
#include "osd.h"
#include "logging.h"
#include "rgb_to_fb.h"
@ -392,7 +393,13 @@ static void cpld_set_mode(capture_info_t *capinfo, int mode) {
if (capinfo->bpp == 8) {
capinfo->capture_line = capture_line_default_8bpp;
} else {
capinfo->capture_line = capture_line_default_4bpp;
if (capinfo->px_sampling == PS_DOUBLE) {
capinfo->capture_line = capture_line_default_4bpp_double;
} else if (capinfo->px_sampling == PS_SUBSAMPLE) {
capinfo->capture_line = capture_line_default_4bpp_subsample;
} else {
capinfo->capture_line = capture_line_default_4bpp;
}
}
}
}

Wyświetl plik

@ -127,6 +127,7 @@ typedef struct {
int v_offset; // vertical offset (in lines)
int ncapture; // number of fields to capture, or -1 to capture forever
int (*capture_line)(); // the capture line function to use
int px_sampling; // whether to sample normally, sub-sample or pixel double
} capture_info_t;
typedef struct {

Wyświetl plik

@ -11,21 +11,29 @@ enum {
FB_BPP,
CLOCK,
LINE_LEN,
CLOCK_PPM
CLOCK_PPM,
PX_SAMPLING
};
static const char *px_sampling_names[] = {
"Normal",
"Sub Sample",
"Pixel Double"
};
static param_t params[] = {
{ H_OFFSET, "H offset", 0, 59, 1 },
{ V_OFFSET, "V offset", 0, 39, 1 },
{ H_WIDTH, "H width", 1, 100, 1 },
{ V_HEIGHT, "V height", 1, 300, 1 },
{ FB_WIDTH, "FB width", 400, 800, 1 },
{ FB_HEIGHT, "FB height", 320, 600, 1 },
{ FB_BPP, "FB bits/pixel", 4, 8, 4 },
{ CLOCK, "Clock freq", 75000000, 100000000, 1 },
{ LINE_LEN, "Line length", 1000, 9999, 1 },
{ CLOCK_PPM, "Clock tolerance", 0, 100000, 1 },
{ -1, NULL, 0, 0, 0 }
{ H_OFFSET, "H offset", 0, 59, 1 },
{ V_OFFSET, "V offset", 0, 39, 1 },
{ H_WIDTH, "H width", 1, 100, 1 },
{ V_HEIGHT, "V height", 1, 300, 1 },
{ FB_WIDTH, "FB width", 400, 800, 1 },
{ FB_HEIGHT, "FB height", 320, 600, 1 },
{ FB_BPP, "FB bits/pixel", 4, 8, 4 },
{ CLOCK, "Clock freq", 75000000, 100000000, 1 },
{ LINE_LEN, "Line length", 1000, 9999, 1 },
{ CLOCK_PPM, "Clock tolerance", 0, 100000, 1 },
{ PX_SAMPLING, "Pixel sampling", 0, NUM_PS-1, 1 },
{ -1, NULL, 0, 0, 0 }
};
typedef struct {
@ -39,6 +47,7 @@ typedef struct {
int clock; // cpld clock (in Hz)
int line_len; // number of clocks per horizontal line
int clock_ppm; // cpld tolerance (in ppm)
int px_sampling; // pixel sampling mode
} geometry_t;
static int mode7;
@ -64,26 +73,28 @@ static void update_param_range() {
void geometry_init(int version) {
// These are Beeb specific defaults so the geometry property can be ommitted
mode7_geometry.h_offset = 24;
mode7_geometry.v_offset = 21;
mode7_geometry.h_width = 504 / (32 / 4);
mode7_geometry.v_height = 270;
mode7_geometry.fb_width = 504;
mode7_geometry.fb_height = 540;
mode7_geometry.fb_bpp = 4;
mode7_geometry.clock = 96000000;
mode7_geometry.line_len = 96 * 64;
mode7_geometry.clock_ppm = 5000;
default_geometry.h_offset = 32;
default_geometry.v_offset = 21;
default_geometry.h_width = 672 / (32 / 4);
default_geometry.v_height = 270;
default_geometry.fb_width = 672;
default_geometry.fb_height = 540;
default_geometry.fb_bpp = 4;
default_geometry.clock = 96000000;
default_geometry.line_len = 96 * 64;
default_geometry.clock_ppm = 5000;
mode7_geometry.h_offset = 24;
mode7_geometry.v_offset = 21;
mode7_geometry.h_width = 504 / (32 / 4);
mode7_geometry.v_height = 270;
mode7_geometry.fb_width = 504;
mode7_geometry.fb_height = 540;
mode7_geometry.fb_bpp = 4;
mode7_geometry.clock = 96000000;
mode7_geometry.line_len = 96 * 64;
mode7_geometry.clock_ppm = 5000;
mode7_geometry.px_sampling = PS_NORMAL;
default_geometry.h_offset = 32;
default_geometry.v_offset = 21;
default_geometry.h_width = 672 / (32 / 4);
default_geometry.v_height = 270;
default_geometry.fb_width = 672;
default_geometry.fb_height = 540;
default_geometry.fb_bpp = 4;
default_geometry.clock = 96000000;
default_geometry.line_len = 96 * 64;
default_geometry.clock_ppm = 5000;
default_geometry.px_sampling = PS_NORMAL;
// For backwards compatibility with CPLDv1
int supports_delay = (((version >> VERSION_DESIGN_BIT) & 0x0F) == 0) &&
(((version >> VERSION_MAJOR_BIT ) & 0x0F) >= 2);
@ -123,10 +134,19 @@ int geometry_get_value(int num) {
return geometry->line_len;
case CLOCK_PPM:
return geometry->clock_ppm;
case PX_SAMPLING:
return geometry->px_sampling;
}
return -1;
}
const char *geometry_get_value_string(int num) {
if (num == PX_SAMPLING) {
return px_sampling_names[geometry_get_value(num)];
}
return NULL;
}
void geometry_set_value(int num, int value) {
switch (num) {
case H_OFFSET:
@ -160,6 +180,9 @@ void geometry_set_value(int num, int value) {
case CLOCK_PPM:
geometry->clock_ppm = value;
break;
case PX_SAMPLING:
geometry->px_sampling = value;
break;
}
}
@ -175,6 +198,7 @@ void geometry_get_fb_params(capture_info_t *capinfo) {
capinfo->width = geometry->fb_width;
capinfo->height = geometry->fb_height;
capinfo->bpp = geometry->fb_bpp;
capinfo->px_sampling = geometry->px_sampling;
}
void geometry_get_clk_params(clk_info_t *clkinfo) {

Wyświetl plik

@ -4,12 +4,20 @@
#include "defs.h"
#include "cpld.h"
void geometry_init(int version);
void geometry_set_mode(int mode);
int geometry_get_value(int num);
void geometry_set_value(int num, int value);
param_t *geometry_get_params();
void geometry_get_fb_params(capture_info_t *capinfo);
void geometry_get_clk_params(clk_info_t *clkinfo);
enum {
PS_NORMAL, // Each sampled pixel is mapped to one pixel in the frame buffer
PS_SUBSAMPLE, // Even pixels are replicated, odd pixels are ignored
PS_DOUBLE, // Each sampled pixel is mapped to two pixels in the frame buffer
NUM_PS
};
void geometry_init(int version);
void geometry_set_mode(int mode);
int geometry_get_value(int num);
const char *geometry_get_value_string(int num);
void geometry_set_value(int num, int value);
param_t *geometry_get_params();
void geometry_get_fb_params(capture_info_t *capinfo);
void geometry_get_clk_params(clk_info_t *clkinfo);
#endif

Wyświetl plik

@ -544,6 +544,11 @@ static const char *get_param_string(param_menu_item_t *param_item) {
return nbuffer_names[value];
#endif
}
} else if (type == I_GEOMETRY) {
const char *value_str = geometry_get_value_string(param->key);
if (value_str) {
return value_str;
}
}
if (is_boolean_param(param_item)) {
return value ? "On" : "Off";

Wyświetl plik

@ -23,6 +23,10 @@ extern int capture_line_atom_8bpp();
extern int capture_line_default_4bpp();
extern int capture_line_default_4bpp_subsample();
extern int capture_line_default_4bpp_double();
extern int capture_line_default_8bpp();
extern int capture_line_mode7_4bpp();

Wyświetl plik

@ -1207,6 +1207,7 @@ void rgb_to_hdmi_main() {
int result;
int last_mode7;
int mode_changed;
int fb_size_changed;
int active_size_decreased;
int clk_changed;
@ -1313,6 +1314,7 @@ void rgb_to_hdmi_main() {
last_mode7 = mode7;
mode7 = result & BIT_MODE7 & (!m7disable);
mode_changed = (mode7 != last_mode7) || (capinfo->px_sampling != last_capinfo.px_sampling);
if (active_size_decreased) {
clear = BIT_CLEAR;
@ -1327,7 +1329,7 @@ void rgb_to_hdmi_main() {
recalculate_hdmi_clock_line_locked_update();
}
} while (mode7 == last_mode7 && !fb_size_changed);
} while (!mode_changed && !fb_size_changed);
osd_clear();
}

Wyświetl plik

@ -66,6 +66,7 @@
# - Clock 75000000 100000000 96000000 96000000 | an Electron
# - Line Length 1000 9999 6144 6144 |
# - Clock tolerance 0 100000 5000 5000 |
# - Pixel sampling 0 2 0 0 |
#
# Any number of these parameters can be specified but typically you would specify:
#
@ -84,6 +85,7 @@
# - Clock: the nominal sampling clock fed to the CPLD (in Hz)
# - Line Length: the length of a horizontal line (in sampling clocks)
# - Clock tolerance: the maximum correctable error in the sampling clock (in ppm)
# - Pixel sampling: 0=normal, 1=subsample, 2=pixel double
#
# info: the default info screen
# - 0 is the calibration summary
@ -188,10 +190,10 @@ sampling06=3 sampling7=0,2,2,2,2,2,2,0,8,5 info=1 palette=0 deinterlace=6 scanli
#sampling=0,5,5,5,5,5,5,0 geometry=3,37,66,200,528,400,4,85909091,5472 nbuffers=2 m7disable=1
#
# Here's an example that might work with an Atom (CPLDv1) (wider border)
#sampling=0,5,5,5,5,5,5,0 geometry=0,31,69,212,552,424,4,85909091,5472 nbuffers=2 m7disable=1
#sampling=0,5,5,5,5,5,5,0 geometry=0,26,69,212,552,424,4,85909091,5472 nbuffers=2 m7disable=1
#
# Here's an example that might work with an Atom (CPLDv1) (wider border, 8x sampling clock)
#sampling=0,4,4,4,4,4,4,0,8 geometry=8,26,69,212,552,424,4,114545440,7296 nbuffers=2 m7disable=1
# Here's an example that might work with an Atom (CPLDv1) (wider border, sub-sample pixels)
#sampling=0,5,5,5,5,5,5,0 geometry=0,26,69,212,552,424,4,85909091,5472,5000,1 nbuffers=2 m7disable=1
#
# Here's an example that might work with an Atom (CPLDv2) (even wider border)
#sampling=0,5,5,5,5,5,5,0 geometry=24,16,76,240,608,480,4,85909091,5472 nbuffers=2 m7disable=1