Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add dithering toggle/options and misc #4

Open
wants to merge 13 commits into
base: master
Choose a base branch
from
2 changes: 1 addition & 1 deletion sharp.dts
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@
disp-gpios = <&gpio 22 0>;

spi-cs-high = <1>;
spi-max-frequency = <8000000>;
spi-max-frequency = <3000000>;
buswidth = <8>;
debug = <0>;
};
Expand Down
105 changes: 101 additions & 4 deletions src/drm_iface.c
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,34 @@
#define CMD_WRITE_LINE 0b10000000
#define CMD_CLEAR_SCREEN 0b00100000

// Whiter whites
static int ditherMatrix1[4] = {
1, 154,
103, 52
};

// Uniform range
static int ditherMatrix2[4] = {
51, 204,
153, 102
};

// Whiter whites
static int ditherMatrix3[16] = {
1, 83, 21, 103,
123, 42, 143, 62,
32, 113, 11, 93,
154, 72, 134, 52
};

// Uniform range
static int ditherMatrix4[16] = {
15, 195, 60, 240,
135, 75, 180, 120,
45, 225, 30, 210,
165, 105, 150, 90
};

struct sharp_memory_panel {
struct drm_device drm;
struct drm_simple_display_pipe pipe;
Expand Down Expand Up @@ -77,7 +105,7 @@ static void vcom_timer_callback(struct timer_list *t)

// Toggle the GPIO pin
vcom_setting = (vcom_setting) ? 0 : 1;
gpiod_set_value(panel->gpio_vcom, 1);
gpiod_set_value(panel->gpio_vcom, vcom_setting);

// Reschedule the timer
mod_timer(&panel->vcom_timer, jiffies + msecs_to_jiffies(1000));
Expand Down Expand Up @@ -177,6 +205,69 @@ static void draw_indicators(struct sharp_memory_panel *panel, u8* buf, int width
}
}

static size_t sharp_memory_gray8_to_mono_tagged_dither(u8 *buf, int width, int height, int y0)
{
int line, b8, b1, msize, *dM;
unsigned char d;
int const tagged_line_len = 2 + width / 8;

if (g_param_dither == 1) {
*dM=ditherMatrix1;
msize=2;
} else if (g_param_dither == 2) {
*dM=ditherMatrix2;
msize=2;
} else if (g_param_dither == 3) {
*dM=ditherMatrix3;
msize=4;
} else {
*dM=ditherMatrix4;
msize=4;
}

// Iterate over lines from [0, height)
for (line = 0; line < height; line++) {

// Iterate over chunks of 8 source grayscale bytes
// Each 8-byte source chunk will map to one destination mono byte
for (b8 = 0; b8 < width; b8 += 8) {
d = 0;

// Iterate over each of the 8 grayscale bytes in the chunk
// Build up the destination mono byte
for (b1 = 0; b1 < 8; b1++) {

// Apply dithering
if (buf[line * width + b8 + b1] >= dM[(b8 + b1) % msize + line % msize * msize])
d |= 0b10000000 >> b1;
}

// Apply inversion
if (g_param_mono_invert) {
d = ~d;
}

// Without the line number and trailer tags, each destination
// mono line would have a length `width / 8`. However, we are
// inserting the line number at the beginning of the line and
// the zero-byte trailer at the end.
// So the destination mono line is at index
// `line * tagged_line_len = line * (2 + width / 8)`
// The destination mono byte is offset by 1 to make room for
// the line tag, written at the end of converting the current
// line.
buf[(line * tagged_line_len) + 1 + (b8 / 8)] = d;
}

// Write the line number and trailer tags
buf[line * tagged_line_len] = sharp_memory_reverse_byte((u8)(y0 + 1)); // Indexed from 1
buf[(line * tagged_line_len) + tagged_line_len - 1] = 0;
y0++;
}

return height * tagged_line_len;
}

static size_t sharp_memory_gray8_to_mono_tagged(u8 *buf, int width, int height, int y0)
{
int line, b8, b1;
Expand Down Expand Up @@ -265,9 +356,15 @@ static int sharp_memory_clip_mono_tagged(struct sharp_memory_panel* panel, size_
}
}

// Convert in-place from 8-bit grayscale to mono
*result_len = sharp_memory_gray8_to_mono_tagged(buf,
(clip->x2 - clip->x1), (clip->y2 - clip->y1), clip->y1);
if (g_param_dither) {
// Convert in-place from 8-bit grayscale to dithered mono
*result_len = sharp_memory_gray8_to_mono_tagged_dither(buf,
(clip->x2 - clip->x1), (clip->y2 - clip->y1), clip->y1);
} else {
// Convert in-place from 8-bit grayscale to mono
*result_len = sharp_memory_gray8_to_mono_tagged(buf,
(clip->x2 - clip->x1), (clip->y2 - clip->y1), clip->y1);
}

// Success
return 0;
Expand Down
13 changes: 9 additions & 4 deletions src/params_iface.c
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
int g_param_mono_cutoff = 32;
int g_param_mono_invert = 0;
int g_param_indicators = 1;
int g_param_dither = 0;

static int set_param_u8(const char *val, const struct kernel_param *kp)
{
Expand All @@ -20,8 +21,8 @@ static int set_param_u8(const char *val, const struct kernel_param *kp)

rc = param_set_int(val, kp);

// Refresh framebuffer
(void)drm_refresh();
// Refresh framebuffer (disabled for stability)
//(void)drm_refresh();

return rc;
}
Expand All @@ -41,6 +42,10 @@ MODULE_PARM_DESC(mono_invert, "0 for no inversion, 1 for inversion");
module_param_cb(indicators, &u8_param_ops, &g_param_indicators, 0660);
MODULE_PARM_DESC(indicators, "0 for no indicators, 1 for indicators");

module_param_cb(dither, &u8_param_ops, &g_param_dither, 0660);
MODULE_PARM_DESC(dither,
"0: no dithering, 1: limited 2x2, 2: full 2x2, 3: limited 4x4, 4: full 4x4");

int params_probe(void)
{
return 0;
Expand All @@ -55,6 +60,6 @@ void params_set_mono_invert(int setting)
{
g_param_mono_invert = setting;

// Refresh framebuffer
(void)drm_refresh();
// Refresh framebuffer (disabled for stability)
//(void)drm_refresh();
}
1 change: 1 addition & 0 deletions src/params_iface.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
extern int g_param_mono_cutoff;
extern int g_param_mono_invert;
extern int g_param_indicators;
extern int g_param_dither;

int params_probe(void);
void params_remove(void);
Expand Down