Skip to content

Commit 8d6cccb

Browse files
committed
fix some issues
- fix unsigned underflow when adding cursor movement in user_input.c - some cursor support refactors - use gbm_bo_write for uploading cursor icon instead of mmapping - probably more compatible - remove KMS dumb buffer path for cursor support - extract cursor hotspot calculation to separate function - account for cursor hotspot in kms_window_move_cursor_locked - add vec2f_sub, vec2i_add, vec2i_sub
1 parent 05ac7e0 commit 8d6cccb

File tree

3 files changed

+91
-165
lines changed

3 files changed

+91
-165
lines changed

src/user_input.c

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1219,7 +1219,7 @@ static int process_libinput_events(struct user_input *input, uint64_t timestamp)
12191219
}
12201220

12211221
int user_input_on_fd_ready(struct user_input *input) {
1222-
unsigned int cursor_x, cursor_y, cursor_x_before, cursor_y_before;
1222+
int cursor_x, cursor_y, cursor_x_before, cursor_y_before;
12231223
uint64_t timestamp;
12241224
bool cursor_enabled, cursor_enabled_before;
12251225
int ok;
@@ -1240,8 +1240,8 @@ int user_input_on_fd_ready(struct user_input *input) {
12401240

12411241
// record cursor state before handling events
12421242
cursor_enabled_before = input->n_cursor_devices > 0;
1243-
cursor_x_before = (unsigned int) round(input->cursor_x);
1244-
cursor_y_before = (unsigned int) round(input->cursor_y);
1243+
cursor_x_before = round(input->cursor_x);
1244+
cursor_y_before = round(input->cursor_y);
12451245

12461246
// handle all available libinput events
12471247
ok = process_libinput_events(input, timestamp);
@@ -1252,8 +1252,8 @@ int user_input_on_fd_ready(struct user_input *input) {
12521252

12531253
// record cursor state after handling events
12541254
cursor_enabled = input->n_cursor_devices > 0;
1255-
cursor_x = (unsigned int) round(input->cursor_x);
1256-
cursor_y = (unsigned int) round(input->cursor_y);
1255+
cursor_x = round(input->cursor_x);
1256+
cursor_y = round(input->cursor_y);
12571257

12581258
// make sure we've dispatched all the flutter pointer events
12591259
flush_pointer_events(input);

src/util/geometry.h

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,12 +18,25 @@ ATTR_CONST static inline struct vec2f vec2f_add(struct vec2f a, struct vec2f b)
1818
return VEC2F(a.x + b.x, a.y + b.y);
1919
}
2020

21+
ATTR_CONST static inline struct vec2f vec2f_sub(struct vec2f a, struct vec2f b) {
22+
return VEC2F(a.x - b.x, a.y - b.y);
23+
}
24+
25+
2126
struct vec2i {
2227
int x, y;
2328
};
2429

2530
#define VEC2I(_x, _y) ((struct vec2i){ .x = (_x), .y = (_y) })
2631

32+
ATTR_CONST static inline struct vec2i vec2i_add(struct vec2i a, struct vec2i b) {
33+
return VEC2I(a.x + b.x, a.y + b.y);
34+
}
35+
36+
ATTR_CONST static inline struct vec2i vec2i_sub(struct vec2i a, struct vec2i b) {
37+
return VEC2I(a.x - b.x, a.y - b.y);
38+
}
39+
2740
/**
2841
* @brief A quadrilateral with 4 2-dimensional float coordinates.
2942
*

src/window.c

Lines changed: 73 additions & 160 deletions
Original file line numberDiff line numberDiff line change
@@ -556,7 +556,7 @@ struct cursor_buffer {
556556

557557
struct gbm_bo *bo;
558558

559-
int hot_x, hot_y;
559+
struct vec2i hotspot;
560560
};
561561

562562
static const int pixel_size_for_cursor_size[] = {
@@ -581,82 +581,43 @@ UNUSED static enum cursor_size cursor_size_from_pixel_ratio(double device_pixel_
581581
return size;
582582
}
583583

584-
static void write_cursor_icon(
585-
void *map_void,
584+
static struct vec2i get_cursor_hotspot(
586585
enum cursor_size size,
587-
uint32_t pitch,
588-
size_t buffer_size,
589-
drm_plane_transform_t rotation,
590-
int *hot_x_out,
591-
int *hot_y_out
586+
drm_plane_transform_t rotation
592587
) {
593588
const struct cursor_icon *icon;
594589
int pixel_size;
595590
int hot_x, hot_y;
596-
597-
ASSERT_NOT_NULL(map_void);
591+
598592
assert(PLANE_TRANSFORM_IS_ONLY_ROTATION(rotation));
599593
icon = cursors + size;
600594
pixel_size = pixel_size_for_cursor_size[size];
601-
ASSERT_EQUALS(pixel_size, icon->width);
602-
ASSERT_EQUALS(pixel_size, icon->height);
603595

604-
if (rotation.rotate_0 == 0) {
605-
ASSERT_EQUALS(pixel_size * 4, pitch);
606-
memcpy(map_void, icon->data, buffer_size);
596+
if (rotation.rotate_0) {
607597
hot_x = icon->hot_x;
608598
hot_y = icon->hot_y;
599+
} else if (rotation.rotate_90) {
600+
hot_x = pixel_size - icon->hot_y - 1;
601+
hot_y = icon->hot_x;
602+
} else if (rotation.rotate_180) {
603+
hot_x = pixel_size - icon->hot_x - 1;
604+
hot_y = pixel_size - icon->hot_y - 1;
609605
} else {
610-
ASSUME(rotation.rotate_90 || rotation.rotate_180 || rotation.rotate_270);
611-
612-
uint32_t *map_uint32 = (uint32_t *) map_void;
613-
614-
for (int y = 0; y < pixel_size; y++) {
615-
for (int x = 0; x < pixel_size; x++) {
616-
int buffer_x, buffer_y;
617-
if (rotation.rotate_90) {
618-
buffer_x = pixel_size - y - 1;
619-
buffer_y = x;
620-
} else if (rotation.rotate_180) {
621-
buffer_x = pixel_size - y - 1;
622-
buffer_y = pixel_size - x - 1;
623-
} else {
624-
assert(rotation.rotate_270);
625-
buffer_x = y;
626-
buffer_y = pixel_size - x - 1;
627-
}
628-
629-
int buffer_offset = pitch * buffer_y + 4 * buffer_x;
630-
int cursor_offset = pixel_size * y + x;
631-
632-
map_uint32[buffer_offset / 4] = icon->data[cursor_offset];
633-
}
634-
}
635-
636-
if (rotation.rotate_90) {
637-
hot_x = pixel_size - icon->hot_y - 1;
638-
hot_y = icon->hot_x;
639-
} else if (rotation.rotate_180) {
640-
hot_x = pixel_size - icon->hot_x - 1;
641-
hot_y = pixel_size - icon->hot_y - 1;
642-
} else {
643-
assert(rotation.rotate_270);
644-
hot_x = icon->hot_y;
645-
hot_y = pixel_size - icon->hot_x - 1;
646-
}
606+
ASSUME(rotation.rotate_270);
607+
hot_x = icon->hot_y;
608+
hot_y = pixel_size - icon->hot_x - 1;
647609
}
648610

649-
*hot_x_out = hot_x;
650-
*hot_y_out = hot_y;
611+
return VEC2I(hot_x, hot_y);
651612
}
652613

653-
static struct cursor_buffer *cursor_buffer_new_using_gbm_bo(struct drmdev *drmdev, enum cursor_size size, drm_plane_transform_t rotation) {
614+
static struct cursor_buffer *cursor_buffer_new(struct drmdev *drmdev, enum cursor_size size, drm_plane_transform_t rotation) {
615+
const struct cursor_icon *icon;
654616
struct cursor_buffer *b;
655617
struct gbm_bo *bo;
656-
uint32_t stride;
657618
uint32_t fb_id;
658-
void *mapdata, *map;
659-
int pixel_size, hot_x, hot_y;
619+
int pixel_size;
620+
int ok;
660621

661622
ASSERT_NOT_NULL(drmdev);
662623
assert(PLANE_TRANSFORM_IS_ONLY_ROTATION(rotation));
@@ -680,15 +641,60 @@ static struct cursor_buffer *cursor_buffer_new_using_gbm_bo(struct drmdev *drmde
680641
goto fail_free_b;
681642
}
682643

683-
map = gbm_bo_map(bo, 0, 0, pixel_size, pixel_size, GBM_BO_TRANSFER_READ | GBM_BO_TRANSFER_WRITE, &stride, &mapdata);
684-
if (map == NULL) {
685-
LOG_ERROR("Couldn't map GBM bo for uploading mouse cursor icon. gbm_bo_map: %s\n", strerror(errno));
644+
if (gbm_bo_get_stride(bo) != pixel_size * 4) {
645+
LOG_ERROR("GBM BO has unsupported framebuffer stride %u, expected was: %d\n", gbm_bo_get_stride(bo), pixel_size * 4);
686646
goto fail_destroy_bo;
687647
}
688648

689-
write_cursor_icon(map, size, stride, stride * pixel_size, rotation, &hot_x, &hot_y);
649+
icon = cursors + size;
650+
ASSERT_EQUALS(pixel_size, icon->width);
651+
ASSERT_EQUALS(pixel_size, icon->height);
652+
653+
if (rotation.rotate_0) {
654+
ok = gbm_bo_write(bo, icon->data, gbm_bo_get_stride(bo) * pixel_size);
655+
if (ok != 0) {
656+
LOG_ERROR("Couldn't write cursor icon to GBM BO. gbm_bo_write: %s\n", strerror(errno));
657+
goto fail_destroy_bo;
658+
}
659+
} else {
660+
ASSUME(rotation.rotate_90 || rotation.rotate_180 || rotation.rotate_270);
661+
662+
uint32_t *rotated = malloc(pixel_size * pixel_size * 4);
663+
if (rotated == NULL) {
664+
goto fail_destroy_bo;
665+
}
666+
667+
for (int y = 0; y < pixel_size; y++) {
668+
for (int x = 0; x < pixel_size; x++) {
669+
int buffer_x, buffer_y;
670+
if (rotation.rotate_90) {
671+
buffer_x = pixel_size - y - 1;
672+
buffer_y = x;
673+
} else if (rotation.rotate_180) {
674+
buffer_x = pixel_size - y - 1;
675+
buffer_y = pixel_size - x - 1;
676+
} else {
677+
ASSUME(rotation.rotate_270);
678+
buffer_x = y;
679+
buffer_y = pixel_size - x - 1;
680+
}
681+
682+
int buffer_offset = pixel_size * buffer_y + buffer_x;
683+
int cursor_offset = pixel_size * y + x;
690684

691-
gbm_bo_unmap(bo, mapdata);
685+
rotated[buffer_offset] = icon->data[cursor_offset];
686+
}
687+
}
688+
689+
ok = gbm_bo_write(bo, rotated, pixel_size * pixel_size * 4);
690+
691+
free(rotated);
692+
693+
if (ok != 0) {
694+
LOG_ERROR("Couldn't write rotated cursor icon to GBM BO. gbm_bo_write: %s\n", strerror(errno));
695+
goto fail_destroy_bo;
696+
}
697+
}
692698

693699
fb_id = drmdev_add_fb(
694700
drmdev,
@@ -715,8 +721,7 @@ static struct cursor_buffer *cursor_buffer_new_using_gbm_bo(struct drmdev *drmde
715721
b->gem_handle = gbm_bo_get_handle(bo).u32;
716722
b->drm_fb_id = fb_id;
717723
b->bo = bo;
718-
b->hot_x = hot_x;
719-
b->hot_y = hot_y;
724+
b->hotspot = get_cursor_hotspot(size, rotation);
720725
return b;
721726

722727
fail_destroy_bo:
@@ -727,98 +732,6 @@ static struct cursor_buffer *cursor_buffer_new_using_gbm_bo(struct drmdev *drmde
727732
return NULL;
728733
}
729734

730-
static struct cursor_buffer *
731-
cursor_buffer_new_using_kms_dumb_buffers(struct drmdev *drmdev, enum cursor_size size, drm_plane_transform_t rotation) {
732-
const struct cursor_icon *icon;
733-
struct cursor_buffer *b;
734-
uint32_t gem_handle, pitch;
735-
uint32_t fb_id;
736-
size_t buffer_size;
737-
void *map_void;
738-
int pixel_size, hot_x, hot_y;
739-
int ok;
740-
741-
ASSERT_NOT_NULL(drmdev);
742-
assert(PLANE_TRANSFORM_IS_ONLY_ROTATION(rotation));
743-
744-
if (!drmdev_supports_dumb_buffers(drmdev)) {
745-
LOG_ERROR("KMS doesn't support dumb buffers. Can't upload mouse cursor icon.\n");
746-
return NULL;
747-
}
748-
749-
b = malloc(sizeof *b);
750-
if (b == NULL) {
751-
return NULL;
752-
}
753-
754-
pixel_size = pixel_size_for_cursor_size[size];
755-
756-
ok = drmdev_create_dumb_buffer(drmdev, pixel_size, pixel_size, 32, &gem_handle, &pitch, &buffer_size);
757-
if (ok != 0) {
758-
goto fail_free_b;
759-
}
760-
761-
fb_id = drmdev_add_fb(drmdev, pixel_size, pixel_size, kARGB8888_FpiPixelFormat, gem_handle, pitch, 0, true, DRM_FORMAT_MOD_LINEAR);
762-
if (fb_id == 0) {
763-
LOG_ERROR("Couldn't add mouse cursor buffer as KMS framebuffer.\n");
764-
goto fail_destroy_dumb_buffer;
765-
}
766-
767-
map_void = drmdev_map_dumb_buffer(drmdev, gem_handle, buffer_size);
768-
if (map_void == NULL) {
769-
goto fail_rm_fb;
770-
}
771-
772-
icon = cursors + size;
773-
ASSERT_EQUALS(pixel_size, icon->width);
774-
ASSERT_EQUALS(pixel_size, icon->height);
775-
776-
write_cursor_icon(map_void, size, pitch, buffer_size, rotation, &hot_x, &hot_y);
777-
778-
drmdev_unmap_dumb_buffer(drmdev, map_void, buffer_size);
779-
780-
b->n_refs = REFCOUNT_INIT_1;
781-
b->format = kARGB8888_FpiPixelFormat;
782-
b->width = pixel_size;
783-
b->height = pixel_size;
784-
b->size = size;
785-
b->rotation = rotation;
786-
b->drmdev = drmdev_ref(drmdev);
787-
b->gem_handle = gem_handle;
788-
b->drm_fb_id = fb_id;
789-
b->bo = NULL;
790-
b->hot_x = hot_x;
791-
b->hot_y = hot_y;
792-
return b;
793-
794-
fail_rm_fb:
795-
drmdev_rm_fb(drmdev, fb_id);
796-
797-
fail_destroy_dumb_buffer:
798-
drmdev_destroy_dumb_buffer(drmdev, gem_handle);
799-
800-
fail_free_b:
801-
free(b);
802-
return NULL;
803-
}
804-
805-
static struct cursor_buffer *cursor_buffer_new(struct drmdev *drmdev, enum cursor_size size, drm_plane_transform_t rotation) {
806-
struct cursor_buffer *b;
807-
808-
b = cursor_buffer_new_using_kms_dumb_buffers(drmdev, size, rotation);
809-
810-
if (b == NULL) {
811-
b = cursor_buffer_new_using_gbm_bo(drmdev, size, rotation);
812-
}
813-
814-
if (b == NULL) {
815-
LOG_ERROR("Couldn't upload mouse cursor icon using any method.\n");
816-
return NULL;
817-
}
818-
819-
return b;
820-
}
821-
822735
static void cursor_buffer_destroy(struct cursor_buffer *buffer) {
823736
drmdev_rm_fb(buffer->drmdev, buffer->drm_fb_id);
824737
drmdev_destroy_dumb_buffer(buffer->drmdev, buffer->gem_handle);
@@ -1295,8 +1208,8 @@ static int kms_window_push_composition(struct window *window, struct fl_layer_co
12951208
.src_y = 0,
12961209
.src_w = ((uint16_t) window->kms.cursor->width) << 16,
12971210
.src_h = ((uint16_t) window->kms.cursor->height) << 16,
1298-
.dst_x = window->cursor_pos.x - window->kms.cursor->hot_x,
1299-
.dst_y = window->cursor_pos.y - window->kms.cursor->hot_y,
1211+
.dst_x = window->cursor_pos.x - window->kms.cursor->hotspot.x,
1212+
.dst_y = window->cursor_pos.y - window->kms.cursor->hotspot.y,
13001213
.dst_w = window->kms.cursor->width,
13011214
.dst_h = window->kms.cursor->height,
13021215
.has_rotation = false,
@@ -1626,6 +1539,6 @@ static int kms_window_move_cursor_locked(struct window *window, struct vec2i pos
16261539
window->cursor_pos = pos;
16271540

16281541
/// TODO: Draw a new frame or redraw the last frame with new cursor pos here.
1629-
drmdev_move_cursor(window->kms.drmdev, window->kms.crtc->id, pos);
1542+
drmdev_move_cursor(window->kms.drmdev, window->kms.crtc->id, vec2i_sub(pos, window->kms.cursor->hotspot));
16301543
return 0;
16311544
}

0 commit comments

Comments
 (0)