1
0
Fork 0

Fix custom cursor flickering in web builds

Implement caching of the custom cursor state in `DisplayServerWeb` to prevent redundant updates to the browser's cursor. This change computes a hash based on the cursor resource, shape, and hotspot, and only updates the browser's cursor when the hash changes. This mitigates the flickering observed in web exports when `set_custom_mouse_cursor()` is called every frame.
This commit is contained in:
Jakub Marcowski 2025-02-25 14:49:23 +00:00 committed by Jakub Marcowski
parent e7ac8e45a3
commit 6dc2a886e7
No known key found for this signature in database
GPG Key ID: 10D9E07CFFBC0E6F
2 changed files with 37 additions and 0 deletions

View File

@ -514,8 +514,42 @@ DisplayServer::CursorShape DisplayServerWeb::cursor_get_shape() const {
return cursor_shape;
}
uint64_t DisplayServerWeb::_compute_cursor_hash(const Ref<Resource> &p_cursor, CursorShape p_shape, const Vector2 &p_hotspot) const {
if (!p_cursor.is_valid()) {
return 0;
}
uint64_t seed = 0;
// Local functor for combining hash values.
struct Combiner {
uint64_t &seed;
void combine(uint64_t value) const {
// This uses a 64-bit constant akin to `boost::hash_combine`.
seed ^= value + 0x9e3779b97f4a7c15ULL + (seed << 6) + (seed >> 2);
}
};
Combiner combiner{ seed };
combiner.combine(p_cursor->get_instance_id());
combiner.combine(static_cast<uint64_t>(p_shape));
combiner.combine(static_cast<uint64_t>(static_cast<int>(p_hotspot.x)));
combiner.combine(static_cast<uint64_t>(static_cast<int>(p_hotspot.y)));
return seed;
}
void DisplayServerWeb::cursor_set_custom_image(const Ref<Resource> &p_cursor, CursorShape p_shape, const Vector2 &p_hotspot) {
ERR_FAIL_INDEX(p_shape, CURSOR_MAX);
uint64_t new_cursor_hash = _compute_cursor_hash(p_cursor, p_shape, p_hotspot);
if (new_cursor_hash == current_cursor_hash) {
return;
}
current_cursor_hash = new_cursor_hash;
if (p_cursor.is_valid()) {
Ref<Image> image = _get_cursor_image_from_resource(p_cursor, p_hotspot);
ERR_FAIL_COND(image.is_null());

View File

@ -82,6 +82,9 @@ private:
uint64_t last_click_ms = 0;
MouseButton last_click_button_index = MouseButton::NONE;
uint64_t current_cursor_hash;
uint64_t _compute_cursor_hash(const Ref<Resource> &p_cursor, CursorShape p_shape, const Vector2 &p_hotspot) const;
bool ime_active = false;
bool ime_started = false;
String ime_text;