From 5d8efbfeb9e44416ed522cb3a4fa94186de2bf38 Mon Sep 17 00:00:00 2001 From: kd-11 Date: Fri, 2 Oct 2026 17:42:49 +0300 Subject: [PATCH] rsx/lv2: Implement hardware bitmap cursor --- rpcs3/Emu/Cell/lv2/sys_rsx.cpp | 78 +++++++++++++++++++++++ rpcs3/Emu/RSX/Overlays/overlay_controls.h | 20 ++++++ rpcs3/Emu/RSX/Overlays/overlay_cursor.cpp | 55 ++++++++++++++++ rpcs3/Emu/RSX/Overlays/overlay_cursor.h | 18 ++++++ 4 files changed, 171 insertions(+) diff --git a/rpcs3/Emu/Cell/lv2/sys_rsx.cpp b/rpcs3/Emu/Cell/lv2/sys_rsx.cpp index 6548d9b4fa..68ec717219 100644 --- a/rpcs3/Emu/Cell/lv2/sys_rsx.cpp +++ b/rpcs3/Emu/Cell/lv2/sys_rsx.cpp @@ -9,6 +9,8 @@ #include "Emu/Memory/vm_locking.h" #include "Emu/RSX/Core/RSXEngLock.hpp" #include "Emu/RSX/Core/RSXReservationLock.hpp" +#include "Emu/RSX/Overlays/overlay_cursor.h" +#include "Emu/RSX/Overlays/overlay_manager.h" #include "Emu/RSX/RSXThread.h" #include "util/asm.hpp" #include "sys_event.h" @@ -36,6 +38,62 @@ void fmt_class_string::format(std::string& out, u64 arg) }); } +// ---- Hardware cursor ---- +// The hardware cursor is part of the display circuitry. It is not rendered directly by PGRAPH or any of the other 2D objects. +// Emulation is implemented using the overlay system. It has a fixed 64x64 bitmap size. + +rsx::overlays::bitmap_cursor* _sys_rsx_get_cursor() +{ + if (auto manager = g_fxo->try_get()) + { + return manager->get().get(); + } + + return nullptr; +} + +void _sys_rsx_init_cursor_overlay() +{ + if (auto manager = g_fxo->try_get()) + { + manager->create(); + } +} + +void _sys_rsx_enable_cursor_overlay() +{ + if (auto cursor = _sys_rsx_get_cursor()) + { + cursor->enable(); + } +} + +void _sys_rsx_disable_cursor_overlay() +{ + if (auto cursor = _sys_rsx_get_cursor()) + { + cursor->disable(); + } +} + +void _sys_rsx_move_cursor_overlay(s32 x, s32 y) +{ + if (auto cursor = _sys_rsx_get_cursor()) + { + cursor->set_pos(x, y); + } +} + +void _sys_rsx_update_cursor_image(u32 cursor_offset) +{ + if (auto cursor = _sys_rsx_get_cursor()) + { + cursor->set_bitmap(cursor_offset); + } +} + +// ---- Util ---- + static u64 rsx_timeStamp() { return get_timebased_time(); @@ -142,6 +200,8 @@ bool rsx::thread::send_event(u64 data1, u64 event_flags, u64 data3) return true; } +// ---- Event Queue ---- + void _sys_rsx_drain_event_queue(rsx::thread* rsxthr, u64 event_flags = umax, u64 wait_timeout_ms = 1000ull) { const auto& driverInfo = *vm::_ptr(rsxthr->driver_info); @@ -204,6 +264,8 @@ void _sys_rsx_drain_event_queue(rsx::thread* rsxthr, u64 event_flags = umax, u64 } } +// ---- LV2 ---- + error_code sys_rsx_device_open(cpu_thread& cpu) { cpu.state += cpu_flag::wait; @@ -780,11 +842,27 @@ error_code sys_rsx_context_attribute(u32 context_id, u32 package_id, u64 a3, u64 case 0x10b: // when a4=3, cellGcmSetCursorPosition(a5=xpos, a6=ypos) // when a4=2, cellGcmSetCursorImageOffset(a5=offset) + if (a4 == 3) + _sys_rsx_move_cursor_overlay(static_cast(a5), static_cast(a6)); + else if (a4 == 2) + _sys_rsx_update_cursor_image(static_cast(a5)); + else + sys_rsx.error("Unknown subfunction 0x%llx (package=0x10b)", a4); + break; case 0x10c: // when a4=1, cellGcmSetCursorEnable() // when a4=2, cellGcmSetCursorDisable() + if (a4 == 1) + _sys_rsx_enable_cursor_overlay(); + else if (a4 == 2) + _sys_rsx_disable_cursor_overlay(); + else + sys_rsx.error("Unknown subfunction 0x%llx (package=0x10c)", a4); + break; case 0x10d: // cellGcmInitCursor(a3=1, a4=1, a5=0, a6=0) + ensure(a4 == 1); + _sys_rsx_init_cursor_overlay(); break; case 0x300: // Tiles diff --git a/rpcs3/Emu/RSX/Overlays/overlay_controls.h b/rpcs3/Emu/RSX/Overlays/overlay_controls.h index 935880d2b9..f63fe7b12b 100644 --- a/rpcs3/Emu/RSX/Overlays/overlay_controls.h +++ b/rpcs3/Emu/RSX/Overlays/overlay_controls.h @@ -72,6 +72,26 @@ namespace rsx static std::unique_ptr load_icon(const std::string& icon_path, const std::string& archive_path); }; + struct memory_image_info : public image_info_base + { + public: + memory_image_info() = default; + + memory_image_info(u16 w, u16 h, u8 bpp, const u8* data) + { + this->w = w; + this->h = h; + this->bpp = bpp; + this->m_data_ptr = data; + } + + const u8* get_data() const override { return m_data_ptr; } + usz size_bytes() const override { return static_cast(w * h * bpp); } + + private: + const u8* m_data_ptr = nullptr; + }; + struct resource_config { enum standard_image_resource : u8 diff --git a/rpcs3/Emu/RSX/Overlays/overlay_cursor.cpp b/rpcs3/Emu/RSX/Overlays/overlay_cursor.cpp index e20074d1b8..bcd4f417db 100644 --- a/rpcs3/Emu/RSX/Overlays/overlay_cursor.cpp +++ b/rpcs3/Emu/RSX/Overlays/overlay_cursor.cpp @@ -2,9 +2,13 @@ #include "overlay_cursor.h" #include "overlay_manager.h" #include "Emu/Cell/timers.hpp" +#include "Emu/Memory/vm.h" +#include "Emu/RSX/gcm_enums.h" namespace rsx { + extern u32 get_address(u32 offset, u32 location, u32 size_to_check = 0, std::source_location src_loc = std::source_location::current()); + namespace overlays { cursor_item::cursor_item() @@ -151,5 +155,56 @@ namespace rsx } } + void bitmap_cursor::enable() + { + m_visible = true; + } + + void bitmap_cursor::disable() + { + m_visible = false; + } + + void bitmap_cursor::set_pos(s32 x, s32 y) + { + std::lock_guard lock(m_mutex); + + m_position.x = ::narrow(x); + m_position.y = ::narrow(y); + + if (m_bitmap) + { + m_bitmap->set_pos(m_position.x, m_position.y); + } + } + + void bitmap_cursor::set_bitmap(u32 address) + { + std::lock_guard lock(m_mutex); + + if (!m_bitmap) + { + m_bitmap = std::make_unique(); + m_bitmap->set_size(64, 64); + m_bitmap->set_pos(m_position.x, m_position.y); + } + + auto vm_address = rsx::get_address(address, CELL_GCM_CONTEXT_DMA_MEMORY_FRAME_BUFFER); + auto data = vm::get_super_ptr(vm_address); + m_image_storage = { 64, 64, 4, data }; + m_bitmap->set_raw_image(&m_image_storage); + } + + compiled_resource bitmap_cursor::get_compiled() + { + std::lock_guard lock(m_mutex); + + if (!m_visible || !m_bitmap) + { + return {}; + } + + return m_bitmap->get_compiled(); + } } // namespace overlays } // namespace rsx diff --git a/rpcs3/Emu/RSX/Overlays/overlay_cursor.h b/rpcs3/Emu/RSX/Overlays/overlay_cursor.h index d464c509fe..3f5711a508 100644 --- a/rpcs3/Emu/RSX/Overlays/overlay_cursor.h +++ b/rpcs3/Emu/RSX/Overlays/overlay_cursor.h @@ -50,6 +50,24 @@ namespace rsx std::map m_cursors; }; + class bitmap_cursor final : public overlay + { + public: + void enable(); + void disable(); + void set_pos(s32 x, s32 y); + void set_bitmap(u32 address); + compiled_resource get_compiled() override; + + private: + bool m_visible = false; + position2_base m_position = {}; + std::unique_ptr m_bitmap; + overlays::memory_image_info m_image_storage; + + shared_mutex m_mutex; + }; + void set_cursor(u32 id, s16 x, s16 y, const color4f& color, u64 duration_us, bool force_update); } // namespace overlays