summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAnton Kling <anton@kling.gg>2024-06-25 18:56:42 +0200
committerAnton Kling <anton@kling.gg>2024-06-25 18:56:42 +0200
commit31743482bbdceeb2a0e52ae430ce1afad853e7e9 (patch)
treec6d6980d6613d4cc0eb3ac3b824b39660589dab5
parent90a8be18547040cab8c395c64d681be1f95ec517 (diff)
Optimize mouse driver to perform more work in kernel
Instead of sending every event to userland they now get handeld in the kernel when possible. It will now only send out events when buttons are clicked or the mouse position is requested by userland.
-rw-r--r--kernel/drivers/mouse.c101
-rw-r--r--userland/windowserver/ws.c52
2 files changed, 114 insertions, 39 deletions
diff --git a/kernel/drivers/mouse.c b/kernel/drivers/mouse.c
index 0eb6df6..47133b8 100644
--- a/kernel/drivers/mouse.c
+++ b/kernel/drivers/mouse.c
@@ -5,29 +5,69 @@
#include <fs/fifo.h>
#include <fs/vfs.h>
#include <interrupts.h>
+#include <math.h>
#include <typedefs.h>
u8 mouse_cycle = 0;
u8 mouse_u8[3];
-u8 mouse_x = 0;
-u8 mouse_y = 0;
-vfs_inode_t *mouse_inode;
+int mouse_x = 0;
+int mouse_y = 0;
+
+u8 mouse_left_button = 0;
+u8 mouse_middle_button = 0;
+u8 mouse_right_button = 0;
+
+vfs_inode_t *mouse_inode = NULL;
struct mouse_event {
u8 buttons;
- u8 x;
- u8 y;
+ int x;
+ int y;
+};
+
+struct mouse_event previous_event = {
+ .buttons = 0,
+ .x = 0,
+ .y = 0,
};
int fs_mouse_has_data(vfs_inode_t *inode) {
+ if (mouse_x != previous_event.x || mouse_y != previous_event.y) {
+ return 1;
+ }
+
const struct ringbuffer *rb = inode->internal_object;
return !ringbuffer_isempty(rb);
}
int fs_mouse_read(u8 *buffer, u64 offset, u64 len, vfs_fd_t *fd) {
+ mouse_middle_button = mouse_u8[0] & (1 << 2);
+ mouse_right_button = mouse_u8[0] & (1 << 1);
+ mouse_left_button = mouse_u8[0] & (1 << 0);
+
struct ringbuffer *rb = fd->inode->internal_object;
u32 rc = ringbuffer_read(rb, buffer, len);
if (0 == rc && len > 0) {
+ if (mouse_x != previous_event.x || mouse_y != previous_event.y) {
+ int read_len = min(len, sizeof(struct mouse_event));
+
+ struct mouse_event e;
+ e.x = mouse_x;
+ e.y = mouse_y;
+ e.buttons = 0;
+ if (mouse_middle_button) {
+ e.buttons |= (1 << 2);
+ }
+ if (mouse_right_button) {
+ e.buttons |= (1 << 1);
+ }
+ if (mouse_left_button) {
+ e.buttons |= (1 << 0);
+ }
+ memcpy(buffer, &e, read_len);
+ previous_event = e;
+ return read_len;
+ }
return -EAGAIN;
}
return rc;
@@ -56,19 +96,60 @@ void int_mouse(reg_t *r) {
mouse_u8[1] = inb(0x60);
mouse_cycle++;
break;
- case 2:
+ case 2: {
mouse_u8[2] = inb(0x60);
- mouse_x = mouse_u8[1];
- mouse_y = mouse_u8[2];
+ int16_t x = mouse_u8[1];
+ int16_t y = mouse_u8[2];
+ uint8_t xs = mouse_u8[0] & (1 << 4);
+ uint8_t ys = mouse_u8[0] & (1 << 5);
+ if (xs)
+ x |= 0xFF00;
+ if (ys)
+ y |= 0xFF00;
+
+ mouse_x += x;
+ mouse_y -= y;
+
+ if (mouse_x < 0)
+ mouse_x = 0;
+ if (mouse_y < 0)
+ mouse_y = 0;
+
+ mouse_middle_button = mouse_u8[0] & (1 << 2);
+ mouse_right_button = mouse_u8[0] & (1 << 1);
+ mouse_left_button = mouse_u8[0] & (1 << 0);
+
mouse_cycle = 0;
+
+ // If there is a change in the mouse buttons that event should be written.
+ // The mouse movements will be generated upon request. This avoids
+ // filling the ringbuffer with a ton of small mouse movements.
+
+ int button_change = 0;
+ if (mouse_middle_button != (previous_event.buttons & (1 << 2))) {
+ button_change = 1;
+ } else if (mouse_right_button != (previous_event.buttons & (1 << 1))) {
+ button_change = 1;
+ } else if (mouse_left_button != (previous_event.buttons & (1 << 0))) {
+ button_change = 1;
+ }
+
+ if (!button_change) {
+ break;
+ }
+
struct mouse_event e;
e.buttons = mouse_u8[0];
e.x = mouse_x;
e.y = mouse_y;
- struct ringbuffer *rb = mouse_inode->internal_object;
- ringbuffer_write(rb, (u8 *)&e, sizeof(e));
+ previous_event = e;
+ if (mouse_inode) {
+ struct ringbuffer *rb = mouse_inode->internal_object;
+ ringbuffer_write(rb, (u8 *)&e, sizeof(e));
+ }
break;
}
+ }
EOI(0xC);
}
diff --git a/userland/windowserver/ws.c b/userland/windowserver/ws.c
index b177358..7a1b7d6 100644
--- a/userland/windowserver/ws.c
+++ b/userland/windowserver/ws.c
@@ -5,13 +5,13 @@
#include <fcntl.h>
#include <math.h>
#include <poll.h>
-#include <sys/socket.h>
#include <stddef.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/mman.h>
+#include <sys/socket.h>
#include <unistd.h>
#define WINDOW_SERVER_SOCKET "/windowserver"
@@ -347,8 +347,8 @@ int windowserver_key_events(struct KEY_EVENT ev, int *redraw) {
struct mouse_event {
uint8_t buttons;
- uint8_t x;
- uint8_t y;
+ int x;
+ int y;
};
void send_resize(WINDOW *w, int x, int y) {
@@ -360,42 +360,36 @@ void send_resize(WINDOW *w, int x, int y) {
}
void parse_mouse_event(int fd) {
- int16_t xc = 0;
- int16_t yc = 0;
+ int xc = 0;
+ int yc = 0;
int middle_button = 0;
int right_button = 0;
int left_button = 0;
- struct mouse_event e[100];
- for (;;) {
- int rc = read(fd, e, sizeof(e));
- if (rc <= 0)
- break;
+ struct mouse_event e;
+ int rc = read(fd, &e, sizeof(e));
+ if (rc <= 0)
+ return;
- int n = rc / sizeof(e[0]);
- for (int i = 0; i < n; i++) {
- uint8_t xs = e[i].buttons & (1 << 4);
- uint8_t ys = e[i].buttons & (1 << 5);
- middle_button = e[i].buttons & (1 << 2);
- right_button = e[i].buttons & (1 << 1);
- left_button = e[i].buttons & (1 << 0);
- int16_t x = e[i].x;
- int16_t y = e[i].y;
- if (xs)
- x |= 0xFF00;
- if (ys)
- y |= 0xFF00;
- xc += x;
- yc += y;
- }
- }
- mouse_x += xc;
- mouse_y -= yc;
+ uint8_t xs = e.buttons & (1 << 4);
+ uint8_t ys = e.buttons & (1 << 5);
+ middle_button = e.buttons & (1 << 2);
+ right_button = e.buttons & (1 << 1);
+ left_button = e.buttons & (1 << 0);
+
+ xc = -mouse_x;
+ yc = mouse_y;
+
+ mouse_x = e.x;
+ mouse_y = e.y;
if (mouse_x < 0) {
mouse_x = 0;
}
if (mouse_y < 0) {
mouse_y = 0;
}
+
+ xc += mouse_x;
+ yc -= mouse_y;
if (mouse_left_down && !left_button) {
mouse_left_up = 1;
} else {