diff --git a/software/libdvi/tmds_encode.S b/software/libdvi/tmds_encode.S index 1992f17..350d2ef 100644 --- a/software/libdvi/tmds_encode.S +++ b/software/libdvi/tmds_encode.S @@ -569,7 +569,7 @@ decl_func_y tmds_fullres_encode_loop_16bpp_leftshift_y b 2f .align 2 1: -.rept 8 +.rept 10 ldmia r0!, {r3, r5} lsrs r4, r3, #14 lsls r3, #2 diff --git a/software/libdvi/tmds_encode.c b/software/libdvi/tmds_encode.c index e4c5b0d..472b1a9 100644 --- a/software/libdvi/tmds_encode.c +++ b/software/libdvi/tmds_encode.c @@ -19,10 +19,6 @@ const uint32_t __scratch_y("tmds_table_fullres_y") tmds_table_fullres_y[] = { #include "tmds_table_fullres.h" }; -const uint32_t tmds_table_fullres_noncritical[] = { -#include "tmds_table_fullres.h" -}; - // Configure an interpolator to extract a single colour channel from each of a pair // of pixels, with the first pixel's lsb at pixel_lsb, and the pixels being // pixel_width wide. Produce a LUT address for the first pixel's colour data on @@ -171,6 +167,46 @@ void __not_in_flash_func(tmds_encode_data_channel_fullres_16bpp)(const uint32_t #endif } +static const int8_t imbalance_lookup[16] = { -4, -2, -2, 0, -2, 0, 0, 2, -2, 0, 0, 2, 0, 2, 2, 4 }; + +static inline int byte_imbalance(uint32_t x) +{ + return imbalance_lookup[x >> 4] + imbalance_lookup[x & 0xF]; +} + +static void tmds_encode_symbols(uint8_t pixel, uint32_t* negative_balance_sym, uint32_t* positive_balance_sym) +{ + int pixel_imbalance = byte_imbalance(pixel); + uint32_t sym = pixel & 1; + if (pixel_imbalance > 0 || (pixel_imbalance == 0 && sym == 0)) { + for (int i = 0; i < 7; ++i) { + sym |= (~((sym >> i) ^ (pixel >> (i + 1))) & 1) << (i + 1); + } + } + else { + for (int i = 0; i < 7; ++i) { + sym |= ( ((sym >> i) ^ (pixel >> (i + 1))) & 1) << (i + 1); + } + sym |= 0x100; + } + + int imbalance = byte_imbalance(sym & 0xFF); + if (imbalance == 0) { + if ((sym & 0x100) == 0) sym ^= 0x2ff; + *positive_balance_sym = sym; + *negative_balance_sym = sym; + return; + } + else if (imbalance > 0) { + *negative_balance_sym = (sym ^ 0x2ff) | (((-imbalance + imbalance_lookup[2 ^ (sym >> 8)] + 2) & 0x3F) << 26); + *positive_balance_sym = sym | ((imbalance + imbalance_lookup[sym >> 8] + 2) << 26); + } + else { + *negative_balance_sym = sym | (((imbalance + imbalance_lookup[sym >> 8] + 2) & 0x3F) << 26); + *positive_balance_sym = (sym ^ 0x2ff) | ((-imbalance + imbalance_lookup[2 ^ (sym >> 8)] + 2) << 26); + } +} + // This takes a 16-bit (RGB 565) colour palette and makes palettes of TMDS symbols suitable // for performing fullres encode. // The TMDS palette buffer should be 6 * n_palette words long. @@ -180,15 +216,30 @@ void tmds_setup_palette_symbols(const uint16_t *palette, uint32_t *tmds_palette, uint32_t* tmds_palette_green = tmds_palette + 2 * n_palette; uint32_t* tmds_palette_red = tmds_palette + 4 * n_palette; for (int i = 0; i < n_palette; ++i) { - uint16_t blue = (palette[i] << 1) & 0x3e; - uint16_t green = (palette[i] >> 5) & 0x3f; - uint16_t red = (palette[i] >> 10) & 0x3e; - tmds_palette_blue[i] = tmds_table_fullres_noncritical[blue]; - tmds_palette_blue[i + n_palette] = tmds_table_fullres_noncritical[64 + blue]; - tmds_palette_green[i] = tmds_table_fullres_noncritical[green]; - tmds_palette_green[i + n_palette] = tmds_table_fullres_noncritical[64 + green]; - tmds_palette_red[i] = tmds_table_fullres_noncritical[red]; - tmds_palette_red[i + n_palette] = tmds_table_fullres_noncritical[64 + red]; + uint16_t blue = (palette[i] << 3) & 0xf8; + uint16_t green = (palette[i] >> 3) & 0xfc; + uint16_t red = (palette[i] >> 8) & 0xf8; + tmds_encode_symbols(blue, &tmds_palette_blue[i], &tmds_palette_blue[i + n_palette]); + tmds_encode_symbols(green, &tmds_palette_green[i], &tmds_palette_green[i + n_palette]); + tmds_encode_symbols(red, &tmds_palette_red[i], &tmds_palette_red[i + n_palette]); + } +} + +// This takes a 24-bit (RGB 888) colour palette and makes palettes of TMDS symbols suitable +// for performing fullres encode. +// The TMDS palette buffer should be 6 * n_palette words long. +// n_palette must be a power of 2 <= 256. +void tmds_setup_palette24_symbols(const uint32_t *palette, uint32_t *tmds_palette, size_t n_palette) { + uint32_t* tmds_palette_blue = tmds_palette; + uint32_t* tmds_palette_green = tmds_palette + 2 * n_palette; + uint32_t* tmds_palette_red = tmds_palette + 4 * n_palette; + for (int i = 0; i < n_palette; ++i) { + uint16_t blue = palette[i] & 0xff; + uint16_t green = (palette[i] >> 8) & 0xff; + uint16_t red = (palette[i] >> 16) & 0xff; + tmds_encode_symbols(blue, &tmds_palette_blue[i], &tmds_palette_blue[i + n_palette]); + tmds_encode_symbols(green, &tmds_palette_green[i], &tmds_palette_green[i + n_palette]); + tmds_encode_symbols(red, &tmds_palette_red[i], &tmds_palette_red[i + n_palette]); } } diff --git a/software/libdvi/tmds_encode.h b/software/libdvi/tmds_encode.h index 18695a5..ee8e244 100644 --- a/software/libdvi/tmds_encode.h +++ b/software/libdvi/tmds_encode.h @@ -9,6 +9,7 @@ void tmds_encode_data_channel_16bpp(const uint32_t *pixbuf, uint32_t *symbuf, si void tmds_encode_data_channel_8bpp(const uint32_t *pixbuf, uint32_t *symbuf, size_t n_pix, uint channel_msb, uint channel_lsb); void tmds_encode_data_channel_fullres_16bpp(const uint32_t *pixbuf, uint32_t *symbuf, size_t n_pix, uint channel_msb, uint channel_lsb); void tmds_setup_palette_symbols(const uint16_t *palette, uint32_t *symbuf, size_t n_palette); +void tmds_setup_palette24_symbols(const uint32_t *palette, uint32_t *symbuf, size_t n_palette); void tmds_encode_palette_data(const uint32_t *pixbuf, const uint32_t *tmds_palette, uint32_t *symbuf, size_t n_pix, uint32_t palette_bits); // Functions from tmds_encode.S