kopia lustrzana https://github.com/hoglet67/RGBtoHDMI
Pi Firmware: Autocal optimization pass uses stored data, so much faster
Change-Id: I1807b7872c7677d7e37fca32294464da30feed14pull/11/head
rodzic
430a2a161a
commit
632d739db8
|
@ -2,6 +2,7 @@
|
|||
#include <stdlib.h>
|
||||
#include <inttypes.h>
|
||||
#include <limits.h>
|
||||
#include <string.h>
|
||||
#include "defs.h"
|
||||
#include "cpld.h"
|
||||
#include "osd.h"
|
||||
|
@ -207,6 +208,10 @@ static int cpld_get_version() {
|
|||
return cpld_version;
|
||||
}
|
||||
|
||||
static int sum_channels(int *rgb) {
|
||||
return rgb[CHAN_RED] + rgb[CHAN_GREEN] + rgb[CHAN_BLUE];
|
||||
}
|
||||
|
||||
static void cpld_calibrate(int elk, int chars_per_line) {
|
||||
int min_i = 0;
|
||||
int metric; // this is a point value (at one sample offset)
|
||||
|
@ -219,6 +224,8 @@ static void cpld_calibrate(int elk, int chars_per_line) {
|
|||
int *metrics;
|
||||
int *errors;
|
||||
|
||||
int rgb_metrics[8][NUM_OFFSETS * NUM_CHANNELS];
|
||||
|
||||
if (mode7) {
|
||||
log_info("Calibrating mode 7");
|
||||
range = 8;
|
||||
|
@ -231,33 +238,41 @@ static void cpld_calibrate(int elk, int chars_per_line) {
|
|||
errors = &errors_default;
|
||||
}
|
||||
|
||||
// Measure the error metrics at all possible offset values
|
||||
min_metric = INT_MAX;
|
||||
config->half_px_delay = 0;
|
||||
config->full_px_delay = 0;
|
||||
for (int i = 0; i < range; i++) {
|
||||
for (int j = 0; j < NUM_OFFSETS; j++) {
|
||||
config->sp_offset[j] = i;
|
||||
printf("INFO: ");
|
||||
for (int i = 0; i < NUM_OFFSETS; i++) {
|
||||
printf("%6c", 'A' + i);
|
||||
}
|
||||
printf(" total\r\n");
|
||||
for (int value = 0; value < range; value++) {
|
||||
for (int i = 0; i < NUM_OFFSETS; i++) {
|
||||
config->sp_offset[i] = value;
|
||||
}
|
||||
write_config(config);
|
||||
rgb_metric = diff_N_frames_by_sample(NUM_CAL_FRAMES, mode7, elk, chars_per_line);
|
||||
|
||||
metric = 0;
|
||||
printf("INFO: offset = %d: metrics = ", i);
|
||||
for (int j = 0; j < NUM_OFFSETS; j++) {
|
||||
printf("INFO: value = %d: metrics = ", value);
|
||||
for (int i = 0; i < NUM_OFFSETS; i++) {
|
||||
int per_sample = 0;
|
||||
for (int c = 0; c < NUM_CHANNELS; c++) {
|
||||
per_sample += rgb_metric[j * NUM_CHANNELS + c];
|
||||
for (int j = 0; j < NUM_CHANNELS; j++) {
|
||||
per_sample += rgb_metric[i * NUM_CHANNELS + j];
|
||||
}
|
||||
metric += per_sample;
|
||||
printf("%6d", per_sample);
|
||||
}
|
||||
printf("; total = %7d\r\n", metric);
|
||||
metrics[i] = metric;
|
||||
printf("%8d\r\n", metric);
|
||||
metrics[value] = metric;
|
||||
osd_sp(config, 1, metric);
|
||||
if (metric < min_metric) {
|
||||
min_metric = metric;
|
||||
}
|
||||
// Save the metrics in case the second phase is needed
|
||||
memcpy(rgb_metrics[value], rgb_metric, NUM_CHANNELS * NUM_OFFSETS * sizeof(int));
|
||||
}
|
||||
|
||||
// Use a 3 sample window to find the minimum and maximum
|
||||
min_win_metric = INT_MAX;
|
||||
for (int i = 0; i < range; i++) {
|
||||
|
@ -271,62 +286,66 @@ static void cpld_calibrate(int elk, int chars_per_line) {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If the min metric is at the limit, make use of the half pixel delay
|
||||
if (mode7 && min_metric > 0 && (min_i <= 1 || min_i >= 6)) {
|
||||
log_info("Enabling half pixel delay");
|
||||
config->half_px_delay = 1;
|
||||
min_i ^= 4;
|
||||
// Swap the metrics as well
|
||||
for (int i = 0; i < range; i++) {
|
||||
for (int j = 0; j < NUM_OFFSETS * NUM_CHANNELS; j++) {
|
||||
int tmp = rgb_metrics[i][j];
|
||||
rgb_metrics[i][j] = rgb_metrics[i ^ 4][j];
|
||||
rgb_metrics[i ^ 4][j] = tmp;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// In all modes, start with the min metric
|
||||
for (int i = 0; i < NUM_OFFSETS; i++) {
|
||||
config->sp_offset[i] = min_i;
|
||||
}
|
||||
log_sp(config);
|
||||
|
||||
// If the metric is non zero, there is scope for further optimization in mode7
|
||||
if (mode7 && min_metric > 0) {
|
||||
int ref = min_metric;
|
||||
log_info("Optimizing calibration");
|
||||
log_sp(config);
|
||||
log_debug("ref = %d", ref);
|
||||
for (int i = 0; i < NUM_OFFSETS; i++) {
|
||||
// Start with current value of the sample point i
|
||||
int value = config->sp_offset[i];
|
||||
// Look up the current metric for this value
|
||||
int ref = sum_channels(rgb_metrics[value] + i * NUM_CHANNELS);
|
||||
// Loop up the metric if we decrease this by one
|
||||
int left = INT_MAX;
|
||||
if (value > 0) {
|
||||
left = sum_channels(rgb_metrics[value - 1] + i * NUM_CHANNELS);
|
||||
}
|
||||
// Look up the metric if we increase this by one
|
||||
int right = INT_MAX;
|
||||
if (config->sp_offset[i] > 0) {
|
||||
config->sp_offset[i]--;
|
||||
write_config(config);
|
||||
rgb_metric = diff_N_frames(NUM_CAL_FRAMES, mode7, elk, chars_per_line);
|
||||
left = rgb_metric[CHAN_RED] + rgb_metric[CHAN_GREEN] + rgb_metric[CHAN_BLUE];
|
||||
osd_sp(config, 1, left);
|
||||
config->sp_offset[i]++;
|
||||
}
|
||||
if (config->sp_offset[i] < 7) {
|
||||
config->sp_offset[i]++;
|
||||
write_config(config);
|
||||
rgb_metric = diff_N_frames(NUM_CAL_FRAMES, mode7, elk, chars_per_line);
|
||||
right = rgb_metric[CHAN_RED] + rgb_metric[CHAN_GREEN] + rgb_metric[CHAN_BLUE];
|
||||
osd_sp(config, 1, right);
|
||||
config->sp_offset[i]--;
|
||||
if (value < 7) {
|
||||
right = sum_channels(rgb_metrics[value + 1] + i * NUM_CHANNELS);
|
||||
}
|
||||
// Make the actual decision
|
||||
if (left < right && left < ref) {
|
||||
config->sp_offset[i]--;
|
||||
ref = left;
|
||||
log_info("nudged %d left, metric = %d", i, ref);
|
||||
} else if (right < left && right < ref) {
|
||||
config->sp_offset[i]++;
|
||||
ref = right;
|
||||
log_info("nudged %d right, metric = %d", i, ref);
|
||||
}
|
||||
}
|
||||
log_sp(config);
|
||||
}
|
||||
|
||||
// Determine mode 7 alignment
|
||||
if (mode7 && supports_delay) {
|
||||
write_config(config);
|
||||
config->full_px_delay = analyze_mode7_alignment();
|
||||
}
|
||||
|
||||
// Perform a final test of errors
|
||||
write_config(config);
|
||||
rgb_metric = diff_N_frames(NUM_CAL_FRAMES, mode7, elk, chars_per_line);
|
||||
*errors = rgb_metric[CHAN_RED] + rgb_metric[CHAN_GREEN] + rgb_metric[CHAN_BLUE];
|
||||
*errors = sum_channels(rgb_metric);
|
||||
osd_sp(config, 1, *errors);
|
||||
log_info("Calibration complete");
|
||||
log_sp(config);
|
||||
|
|
|
@ -633,6 +633,26 @@ int *diff_N_frames_by_sample(int n, int mode7, int elk, int chars_per_line) {
|
|||
#ifdef INSTRUMENT_CAL
|
||||
t_compare += _get_cycle_counter() - t;
|
||||
#endif
|
||||
// At this point the diffs correspond to the sample points in
|
||||
// an unusual order: A F C B E D
|
||||
//
|
||||
// This happens for three reasons:
|
||||
// - the CPLD starts with sample point B, so you get B C D E F A
|
||||
// - the firmware skips the first quad, so you get F A B C D E
|
||||
// - the frame buffer swaps odd and even pixels, so you get A F C B E D
|
||||
//
|
||||
// Mutate the result to correctly order the sample points:
|
||||
// A F C B E D => A B C D E F
|
||||
//
|
||||
// Then the downstream algorithms don't have to worry
|
||||
for (int j = 0; j < NUM_CHANNELS; j++) {
|
||||
int f = diff[j + 1 * NUM_CHANNELS];
|
||||
int b = diff[j + 3 * NUM_CHANNELS];
|
||||
int d = diff[j + 5 * NUM_CHANNELS];
|
||||
diff[j + 1 * NUM_CHANNELS] = b;
|
||||
diff[j + 3 * NUM_CHANNELS] = d;
|
||||
diff[j + 5 * NUM_CHANNELS] = f;
|
||||
}
|
||||
|
||||
// Accumulate the result
|
||||
for (int j = 0; j < NUM_CHANNELS * NUM_OFFSETS; j++) {
|
||||
|
|
Ładowanie…
Reference in New Issue