Compare commits

..

13 Commits

Author SHA1 Message Date
Bananymous 4efaf65d3f BuildSystem: Use usb-tablet instead of usb-mouse
This allows sharing mouse between host and guest!
2025-07-19 18:02:07 +03:00
Bananymous aa0249fadb WindowServer: Support absolute position mouse 2025-07-19 18:01:23 +03:00
Bananymous 2c65590134 Kernel: Add support for absolute position mouse 2025-07-19 18:00:39 +03:00
Bananymous a0d1a9ad67 Kernel: Fix PIT::prescheduler_sleep_ns
I don't even know what I was doing here :D
2025-07-19 01:25:46 +03:00
Bananymous 5df6270e32 Kernel: Clobber flags in `rdrand` 2025-07-18 19:36:37 +03:00
Bananymous 7af6e1cd34 Kernel: Ignore HID main item tag 0
This for some reason exists in vmware's usb devices
2025-07-18 19:11:12 +03:00
Bananymous cceb066284 Kernel: Don't use IST on 32 bit target
This only exists in 64 bit
2025-07-18 19:10:48 +03:00
Bananymous 7a054787ca Kernel: Don't print error if `root` is empty
This is used when loading filesystem from initrd
2025-07-18 19:09:43 +03:00
Bananymous d27891c79f Kernel: Fix correct IOAPIC lookup based on gsi 2025-07-18 19:09:20 +03:00
Bananymous 5874fd640e Kernel: Fix TmpFS for 32 bit target
There was a problem when sizeof(size_t) != sizeof(PageInfo)
2025-07-18 19:07:32 +03:00
Bananymous 11ae220dbe LibImage: Optimize image resizing algorithms 2025-07-18 18:20:37 +03:00
Bananymous 22542a3a71 BuildSystem: Enable sse and sse2 for all programs and libraries
This is default on x86_64 but not on the 32 bit target. banan-os
already requires the CPU to support SSE even on 32 bit platforms.
2025-07-18 18:20:37 +03:00
Bananymous e16fb6a8e9 Kernel: Don't validate allowed null pointers on syscalls 2025-07-17 22:14:04 +03:00
23 changed files with 357 additions and 153 deletions

View File

@ -28,7 +28,7 @@ namespace Kernel
// 1x singly indirect
// 1x doubly indirect
// 1x triply indirect
BAN::Array<paddr_t, 5> block;
BAN::Array<size_t, 5> block;
static constexpr size_t direct_block_count = 2;
#elif ARCH(i686)
uint32_t __padding;
@ -36,8 +36,8 @@ namespace Kernel
// 1x singly indirect
// 1x doubly indirect
// 1x triply indirect
BAN::Array<paddr_t, 8> block;
static constexpr size_t direct_block_count = 5;
BAN::Array<size_t, 16> block;
static constexpr size_t direct_block_count = 13;
#else
#error
#endif

View File

@ -58,8 +58,9 @@ namespace Kernel
virtual void start_report() = 0;
virtual void stop_report() = 0;
virtual void handle_variable(uint16_t usage_page, uint16_t usage, int64_t state) = 0;
virtual void handle_array(uint16_t usage_page, uint16_t usage) = 0;
virtual void handle_variable(uint16_t usage_page, uint16_t usage, int64_t state) = 0;
virtual void handle_variable_absolute(uint16_t usage_page, uint16_t usage, int64_t state, int64_t min, int64_t max) = 0;
};
class USBHIDDriver final : public USBClassDriver

View File

@ -14,8 +14,9 @@ namespace Kernel
void start_report() override;
void stop_report() override;
void handle_variable(uint16_t usage_page, uint16_t usage, int64_t state) override;
void handle_array(uint16_t usage_page, uint16_t usage) override;
void handle_variable(uint16_t usage_page, uint16_t usage, int64_t state) override;
void handle_variable_absolute(uint16_t usage_page, uint16_t usage, int64_t state, int64_t min, int64_t max) override;
void update() override;

View File

@ -14,8 +14,9 @@ namespace Kernel
void start_report() override;
void stop_report() override;
void handle_variable(uint16_t usage_page, uint16_t usage, int64_t state) override;
void handle_array(uint16_t usage_page, uint16_t usage) override;
void handle_variable(uint16_t usage_page, uint16_t usage, int64_t state) override;
void handle_variable_absolute(uint16_t usage_page, uint16_t usage, int64_t state, int64_t min, int64_t max) override;
private:
USBMouse()
@ -23,13 +24,25 @@ namespace Kernel
{}
~USBMouse() = default;
private:
struct AbsInfo
{
int64_t val { -1 };
int64_t min { 0 };
int64_t max { 0 };
bool valid() const { return min <= val && val <= max; }
};
private:
BAN::Array<bool, 5> m_button_state { false };
BAN::Array<bool, 5> m_button_state_temp { false };
int64_t m_pointer_x { 0 };
int64_t m_pointer_y { 0 };
int64_t m_rel_x { 0 };
int64_t m_rel_y { 0 };
int64_t m_wheel { 0 };
AbsInfo m_abs_x;
AbsInfo m_abs_y;
friend class BAN::RefPtr<USBMouse>;
};

View File

@ -470,7 +470,7 @@ namespace Kernel
IOAPIC* ioapic = nullptr;
for (IOAPIC& io : m_io_apics)
{
if (io.gsi_base <= gsi && gsi <= io.gsi_base + io.max_redirs)
if (io.gsi_base <= gsi && gsi < io.gsi_base + io.max_redirs)
{
ioapic = &io;
break;
@ -512,7 +512,7 @@ namespace Kernel
bool found_ioapic = false;
for (const auto& io : m_io_apics)
{
if (io.gsi_base <= gsi && gsi <= io.gsi_base + io.max_redirs)
if (io.gsi_base <= gsi && gsi < io.gsi_base + io.max_redirs)
{
found_ioapic = true;
break;
@ -529,7 +529,7 @@ namespace Kernel
int bit = gsi % 8;
if (m_reserved_gsis[byte] & (1 << bit))
{
dwarnln("GSI {} is already reserved", gsi);
dwarnln("GSI {} is already reserved (IRQ {})", gsi, irq);
return BAN::Error::from_errno(EFAULT);
}
m_reserved_gsis[byte] |= 1 << bit;
@ -566,7 +566,7 @@ namespace Kernel
IOAPIC* ioapic = nullptr;
for (IOAPIC& io : m_io_apics)
{
if (io.gsi_base <= gsi && gsi <= io.gsi_base + io.max_redirs)
if (io.gsi_base <= gsi && gsi < io.gsi_base + io.max_redirs)
{
ioapic = &io;
break;

View File

@ -284,7 +284,9 @@ namespace Kernel
paddr_t page_to_free;
PageTable::with_fast_page(layer1_page.paddr(), [&] {
auto& allocated_pages = PageTable::fast_page_as_sized<size_t>(page_infos_per_page - 1);
static_assert(sizeof(size_t) <= sizeof(PageInfo));
auto& allocated_pages = PageTable::fast_page_as<size_t>(PAGE_SIZE - sizeof(size_t));
ASSERT(allocated_pages > 0);
allocated_pages--;
@ -405,8 +407,9 @@ namespace Kernel
PageTable::with_fast_page(layer1_page.paddr(), [&] {
constexpr size_t pages_per_block = page_infos_per_page - 1;
static_assert(sizeof(size_t) <= sizeof(PageInfo));
auto& allocated_pages = PageTable::fast_page_as_sized<size_t>(pages_per_block);
auto& allocated_pages = PageTable::fast_page_as<size_t>(PAGE_SIZE - sizeof(size_t));
if (allocated_pages == pages_per_block)
return;

View File

@ -61,7 +61,7 @@ namespace Kernel
if (filesystem_or_error.is_error())
panic("Failed to create fallback filesystem: {}", filesystem_or_error.error());
dwarnln("Attempting to load fallback filesystem from {} modules", g_boot_info.modules.size());
dprintln("Loading fallback filesystem from {} modules", g_boot_info.modules.size());
auto filesystem = BAN::RefPtr<FileSystem>::adopt(filesystem_or_error.release_value());
@ -78,6 +78,9 @@ namespace Kernel
static BAN::RefPtr<FileSystem> load_root_filesystem(BAN::StringView root_path)
{
if (root_path.empty())
return load_fallback_root_filesystem();
enum class RootType
{
PartitionUUID,

View File

@ -65,7 +65,9 @@ namespace Kernel
{
memset(&m_tss, 0x00, sizeof(TaskStateSegment));
m_tss.iopb = sizeof(TaskStateSegment);
#if ARCH(x86_64)
m_tss.ist1 = reinterpret_cast<vaddr_t>(g_boot_stack_top);
#endif
uintptr_t base = reinterpret_cast<uintptr_t>(&m_tss);

View File

@ -410,9 +410,11 @@ namespace Kernel
desc.offset1 = (uint16_t)((uintptr_t)handler >> 16);
#if ARCH(x86_64)
desc.offset2 = (uint32_t)((uintptr_t)handler >> 32);
desc.IST = ist;
#else
(void)ist;
#endif
desc.IST = ist;
desc.selector = 0x08;
desc.flags = 0x8E;
}
@ -454,8 +456,10 @@ namespace Kernel
ISR_LIST_X
#undef X
#if ARCH(x86_64)
idt->register_interrupt_handler(DoubleFault, isr8, 1);
static_assert(DoubleFault == 8);
#endif
#define X(num) idt->register_interrupt_handler(IRQ_VECTOR_BASE + num, irq ## num);
IRQ_LIST_X

View File

@ -1420,9 +1420,11 @@ namespace Kernel
address_region2->unpin();
});
address_region1 = TRY(validate_and_pin_pointer_access(address_len, sizeof(address_len), true));
const socklen_t address_len_safe = address_len ? *address_len : 0;
address_region2 = TRY(validate_and_pin_pointer_access(address, address_len_safe, true));
if (address_len)
{
address_region1 = TRY(validate_and_pin_pointer_access(address_len, sizeof(address_len), true));
address_region2 = TRY(validate_and_pin_pointer_access(address, *address_len, true));
}
auto inode = TRY(m_open_file_descriptors.inode_of(socket));
if (!inode->mode().ifsock())
@ -1498,7 +1500,8 @@ namespace Kernel
});
message_region = TRY(validate_and_pin_pointer_access(arguments.message, arguments.length, false));
address_region = TRY(validate_and_pin_pointer_access(arguments.dest_addr, arguments.dest_len, false));
if (arguments.dest_addr)
address_region = TRY(validate_and_pin_pointer_access(arguments.dest_addr, arguments.dest_len, false));
auto message = BAN::ConstByteSpan(static_cast<const uint8_t*>(arguments.message), arguments.length);
return TRY(m_open_file_descriptors.sendto(arguments.socket, message, arguments.dest_addr, arguments.dest_len));
@ -1532,9 +1535,12 @@ namespace Kernel
});
buffer_region = TRY(validate_and_pin_pointer_access(arguments.buffer, arguments.length, true));
address_region1 = TRY(validate_and_pin_pointer_access(arguments.address_len, sizeof(*arguments.address_len), true));
const socklen_t address_len_safe = arguments.address_len ? *arguments.address_len : 0;
address_region2 = TRY(validate_and_pin_pointer_access(arguments.address, address_len_safe, true));
if (arguments.address_len)
{
address_region1 = TRY(validate_and_pin_pointer_access(arguments.address_len, sizeof(*arguments.address_len), true));
address_region2 = TRY(validate_and_pin_pointer_access(arguments.address, *arguments.address_len, true));
}
auto message = BAN::ByteSpan(static_cast<uint8_t*>(arguments.buffer), arguments.length);
return TRY(m_open_file_descriptors.recvfrom(arguments.socket, message, arguments.address, arguments.address_len));
@ -1570,9 +1576,12 @@ namespace Kernel
errorfd_region->unpin();
});
readfd_region = TRY(validate_and_pin_pointer_access(arguments.readfds, sizeof(fd_set), true));
writefd_region = TRY(validate_and_pin_pointer_access(arguments.writefds, sizeof(fd_set), true));
errorfd_region = TRY(validate_and_pin_pointer_access(arguments.errorfds, sizeof(fd_set), true));
if (arguments.readfds)
readfd_region = TRY(validate_and_pin_pointer_access(arguments.readfds, sizeof(fd_set), true));
if (arguments.writefds)
writefd_region = TRY(validate_and_pin_pointer_access(arguments.writefds, sizeof(fd_set), true));
if (arguments.errorfds)
errorfd_region = TRY(validate_and_pin_pointer_access(arguments.errorfds, sizeof(fd_set), true));
const auto old_sigmask = Thread::current().m_signal_block_mask;
if (arguments.sigmask)

View File

@ -21,13 +21,14 @@ namespace Kernel
if (ecx & CPUID::ECX_RDRND)
{
#if ARCH(x86_64)
asm volatile("rdrand %0" : "=r"(s_rand_seed));
asm volatile("rdrand %0" : "=r"(s_rand_seed) :: "flags");
#elif ARCH(i686)
uint32_t lo, hi;
asm volatile(
"rdrand %[lo];"
"rdrand %[hi];"
: [lo]"=r"(lo), [hi]"=r"(hi)
:: "flags"
);
s_rand_seed = ((uint64_t)hi << 32) | lo;
#else

View File

@ -15,10 +15,10 @@
#define SELECT_CHANNEL1 0x40
#define SELECT_CHANNEL2 0x80
#define ACCESS_HI 0x10
#define ACCESS_LO 0x20
#define ACCESS_LO 0x10
#define ACCESS_HI 0x20
#define MODE_RATE_GENERATOR 0x05
#define MODE_RATE_GENERATOR 0x04
#define BASE_FREQUENCY 1193182
@ -116,10 +116,7 @@ namespace Kernel
while (elapsed_ticks < target_ticks)
{
const uint8_t current_ticks = IO::inb(TIMER0_CTL);
if (last_ticks <= current_ticks)
elapsed_ticks += current_ticks - last_ticks;
else
elapsed_ticks += 0xFF + current_ticks - last_ticks;
elapsed_ticks += static_cast<uint8_t>(last_ticks - current_ticks);
last_ticks = current_ticks;
}

View File

@ -376,17 +376,26 @@ namespace Kernel
continue;
}
const int64_t physical =
(input.physical_maximum - input.physical_minimum) *
(logical - input.logical_minimum) /
(input.logical_maximum - input.logical_minimum) +
input.physical_minimum;
const uint32_t usage_base = input.usage_id ? input.usage_id : input.usage_minimum;
if (input.flags & 0x02)
device_input.device->handle_variable(input.usage_page, usage_base + i, physical);
const bool relative = !!(input.flags & 0x04);
const bool variable = !!(input.flags & 0x02);
if (!variable)
device_input.device->handle_array(input.usage_page, usage_base + logical);
else
device_input.device->handle_array(input.usage_page, usage_base + physical);
{
const int64_t physical =
(input.physical_maximum - input.physical_minimum) *
(logical - input.logical_minimum) /
(input.logical_maximum - input.logical_minimum) +
input.physical_minimum;
if (relative)
device_input.device->handle_variable(input.usage_page, usage_base + i, physical);
else
device_input.device->handle_variable_absolute(input.usage_page, usage_base + i, physical, input.physical_minimum, input.physical_maximum);
}
bit_offset += input.report_size;
}
@ -558,6 +567,8 @@ namespace Kernel
{
switch (item_tag)
{
case 0b0000:
break;
case 0b1000: // input
if (collection_stack.empty())
{

View File

@ -102,21 +102,6 @@ namespace Kernel
m_keyboard_lock.unlock(m_lock_state);
}
void USBKeyboard::handle_variable(uint16_t usage_page, uint16_t usage, int64_t state)
{
ASSERT(m_keyboard_lock.current_processor_has_lock());
if (usage_page != 0x07)
{
dprintln_if(DEBUG_USB_KEYBOARD, "Unsupported keyboard usage page {2H}", usage_page);
return;
}
if (!state)
return;
if (usage >= 4 && usage < m_keyboard_state_temp.size())
m_keyboard_state_temp[usage] = state;
}
void USBKeyboard::handle_array(uint16_t usage_page, uint16_t usage)
{
ASSERT(m_keyboard_lock.current_processor_has_lock());
@ -130,6 +115,31 @@ namespace Kernel
m_keyboard_state_temp[usage] = true;
}
void USBKeyboard::handle_variable(uint16_t usage_page, uint16_t usage, int64_t state)
{
(void)usage_page;
(void)usage;
(void)state;
dprintln_if(DEBUG_USB_KEYBOARD, "Unsupported keyboard relative usage page {2H}", usage_page);
}
void USBKeyboard::handle_variable_absolute(uint16_t usage_page, uint16_t usage, int64_t state, int64_t min, int64_t max)
{
(void)min; (void)max;
ASSERT(m_keyboard_lock.current_processor_has_lock());
if (usage_page != 0x07)
{
dprintln_if(DEBUG_USB_KEYBOARD, "Unsupported keyboard usage page {2H}", usage_page);
return;
}
if (!state)
return;
if (usage >= 4 && usage < m_keyboard_state_temp.size())
m_keyboard_state_temp[usage] = state;
}
void USBKeyboard::update()
{
using KeyModifier = LibInput::KeyEvent::Modifier;

View File

@ -6,24 +6,43 @@ namespace Kernel
void USBMouse::start_report()
{
m_wheel = 0;
m_rel_x = 0;
m_rel_y = 0;
m_abs_x = {};
m_abs_y = {};
for (auto& val : m_button_state_temp)
val = false;
}
void USBMouse::stop_report()
{
if (m_pointer_x || m_pointer_y)
if (m_abs_x.valid() && m_abs_y.valid())
{
dprintln_if(DEBUG_USB_MOUSE, "Mouse move event {}, {}", m_pointer_x, m_pointer_y);
dprintln_if(DEBUG_USB_MOUSE, "Mouse move absolute event {}, {}", m_abs_x.val, m_abs_y.val);
LibInput::MouseEvent event;
event.type = LibInput::MouseEventType::MouseMoveAbsEvent;
event.move_abs_event.abs_x = m_abs_x.val;
event.move_abs_event.min_x = m_abs_x.min;
event.move_abs_event.max_x = m_abs_x.max;
event.move_abs_event.abs_y = m_abs_y.val;
event.move_abs_event.min_y = m_abs_y.min;
event.move_abs_event.max_y = m_abs_y.max;
add_event(BAN::ConstByteSpan::from(event));
}
if (m_rel_x || m_rel_y)
{
dprintln_if(DEBUG_USB_MOUSE, "Mouse move event {}, {}", m_rel_x, m_rel_y);
LibInput::MouseEvent event;
event.type = LibInput::MouseEventType::MouseMoveEvent;
event.move_event.rel_x = m_pointer_x;
event.move_event.rel_y = -m_pointer_y;
event.move_event.rel_x = m_rel_x;
event.move_event.rel_y = -m_rel_y;
add_event(BAN::ConstByteSpan::from(event));
m_pointer_x = 0;
m_pointer_y = 0;
}
if (m_wheel)
@ -34,8 +53,6 @@ namespace Kernel
event.type = LibInput::MouseEventType::MouseScrollEvent;
event.scroll_event.scroll = m_wheel;
add_event(BAN::ConstByteSpan::from(event));
m_wheel = 0;
}
for (size_t i = 0; i < m_button_state.size(); i++)
@ -57,6 +74,11 @@ namespace Kernel
}
}
void USBMouse::handle_array(uint16_t usage_page, uint16_t usage)
{
dprintln_if(DEBUG_USB_MOUSE, "Unhandled array report {2H}:{2H}", usage_page, usage);
}
void USBMouse::handle_variable(uint16_t usage_page, uint16_t usage, int64_t state)
{
switch (usage_page)
@ -65,16 +87,50 @@ namespace Kernel
switch (usage)
{
case 0x30:
m_pointer_x = state;
m_rel_x = state;
break;
case 0x31:
m_pointer_y = state;
m_rel_y = state;
break;
case 0x38:
m_wheel = state;
break;
default:
dprintln_if(DEBUG_USB_MOUSE, "Unsupported mouse usage {2H} on page {2H}", usage, usage_page);
dprintln_if(DEBUG_USB_MOUSE, "Unsupported relative mouse usage {2H} on page {2H}", usage, usage_page);
break;
}
break;
default:
dprintln_if(DEBUG_USB_MOUSE, "Unsupported relative mouse usage page {2H}", usage_page);
break;
}
}
void USBMouse::handle_variable_absolute(uint16_t usage_page, uint16_t usage, int64_t state, int64_t min, int64_t max)
{
(void)min; (void)max;
switch (usage_page)
{
case 0x01: // pointer
switch (usage)
{
case 0x30:
m_abs_x = {
.val = state,
.min = min,
.max = max,
};
break;
case 0x31:
m_abs_y = {
.val = state,
.min = min,
.max = max,
};
break;
default:
dprintln_if(DEBUG_USB_MOUSE, "Unsupported absolute mouse usage {2H} on page {2H}", usage, usage_page);
break;
}
break;
@ -84,14 +140,9 @@ namespace Kernel
m_button_state_temp[usage - 1] = state;
break;
default:
dprintln_if(DEBUG_USB_MOUSE, "Unsupported mouse usage page {2H}", usage_page);
dprintln_if(DEBUG_USB_MOUSE, "Unsupported absolute mouse usage page {2H}", usage_page);
break;
}
}
void USBMouse::handle_array(uint16_t usage_page, uint16_t usage)
{
dprintln_if(DEBUG_USB_MOUSE, "Unhandled array report {2H}:{2H}", usage_page, usage);
}
}

View File

@ -32,7 +32,7 @@ fi
NET_ARGS='-netdev user,id=net'
NET_ARGS="-device e1000e,netdev=net $NET_ARGS"
USB_ARGS='-device qemu-xhci -device usb-kbd,port=1 -device usb-hub,port=2 -device usb-mouse,port=2.1'
USB_ARGS='-device qemu-xhci -device usb-kbd,port=1 -device usb-hub,port=2 -device usb-tablet,port=2.1'
SOUND_ARGS='-device ac97'

View File

@ -23,7 +23,7 @@ foreach(library ${USERSPACE_LIBRARIES})
# This is to allow cmake to link when libc updates
target_link_options(${library_lower} PRIVATE -nolibc)
# Default compile options
target_compile_options(${library_lower} PRIVATE -g -O2 -Wall -Wextra -Werror)
target_compile_options(${library_lower} PRIVATE -g -O2 -Wall -Wextra -Werror -msse -msse2)
# set SONAME as cmake doesn't set it for some reason??
set_target_properties(${library_lower} PROPERTIES LINK_FLAGS "-Wl,-soname,${library_lower}.so")

View File

@ -8,6 +8,8 @@
#include <fcntl.h>
#include <sys/mman.h>
#include <immintrin.h>
namespace LibImage
{
@ -62,33 +64,41 @@ namespace LibImage
return BAN::Error::from_errno(ENOTSUP);
}
struct FloatingColor
{
double r, g, b, a;
__m128 vals;
constexpr FloatingColor() {}
constexpr FloatingColor(double r, double g, double b, double a)
: r(r), g(g), b(b), a(a)
FloatingColor() {}
FloatingColor(float b, float g, float r, float a)
: vals { b, g, r, a }
{}
constexpr FloatingColor(Image::Color c)
: r(c.r), g(c.g), b(c.b), a(c.a)
FloatingColor(Image::Color c)
: FloatingColor(c.b, c.g, c.r, c.a)
{}
constexpr FloatingColor operator*(double value) const
FloatingColor operator*(float value) const
{
return FloatingColor(r * value, g * value, b * value, a * value);
FloatingColor color;
color.vals = _mm_mul_ps(vals, _mm_set1_ps(value));
return color;
}
constexpr FloatingColor operator+(FloatingColor other) const
FloatingColor operator+(FloatingColor other) const
{
return FloatingColor(r + other.r, g + other.g, b + other.b, a + other.a);
FloatingColor color;
color.vals = _mm_add_ps(this->vals, other.vals);
return color;
}
constexpr Image::Color as_color() const
Image::Color as_color() const
{
__m128i int32 = _mm_cvttps_epi32(this->vals);
__m128i int16 = _mm_packs_epi32(int32, _mm_setzero_si128());
__m128i int8 = _mm_packus_epi16(int16, _mm_setzero_si128());
const uint32_t temp = _mm_cvtsi128_si32(int8);
return Image::Color {
.b = static_cast<uint8_t>(b < 0.0 ? 0.0 : b > 255.0 ? 255.0 : b),
.g = static_cast<uint8_t>(g < 0.0 ? 0.0 : g > 255.0 ? 255.0 : g),
.r = static_cast<uint8_t>(r < 0.0 ? 0.0 : r > 255.0 ? 255.0 : r),
.a = static_cast<uint8_t>(a < 0.0 ? 0.0 : a > 255.0 ? 255.0 : a),
.b = reinterpret_cast<const uint8_t*>(&temp)[0],
.g = reinterpret_cast<const uint8_t*>(&temp)[1],
.r = reinterpret_cast<const uint8_t*>(&temp)[2],
.a = reinterpret_cast<const uint8_t*>(&temp)[3],
};
}
};
@ -98,8 +108,8 @@ namespace LibImage
if (!validate_size(new_width, new_height))
return BAN::Error::from_errno(EOVERFLOW);
const double ratio_x = (double)width() / new_width;
const double ratio_y = (double)height() / new_height;
const float ratio_x = static_cast<float>(width()) / new_width;
const float ratio_y = static_cast<float>(height()) / new_height;
const auto get_clamped_color =
[this](int64_t x, int64_t y)
@ -125,26 +135,38 @@ namespace LibImage
BAN::Vector<Color> bilinear_bitmap;
TRY(bilinear_bitmap.resize(new_width * new_height));
const uint64_t temp_w = width() + 1;
const uint64_t temp_h = height() + 1;
BAN::Vector<FloatingColor> floating_bitmap;
TRY(floating_bitmap.resize(temp_w * temp_h));
for (uint64_t y = 0; y < temp_h; y++)
for (uint64_t x = 0; x < temp_w; x++)
floating_bitmap[y * temp_w + x] = get_clamped_color(x, y);
for (uint64_t y = 0; y < new_height; y++)
{
for (uint64_t x = 0; x < new_width; x++)
{
const double src_x = x * ratio_x;
const double src_y = y * ratio_y;
const double weight_x = src_x - BAN::Math::floor(src_x);
const double weight_y = src_y - BAN::Math::floor(src_y);
const float src_x = x * ratio_x;
const float src_y = y * ratio_y;
const Color avg_t = Color::average(
get_clamped_color(src_x + 0.0, src_y),
get_clamped_color(src_x + 1.0, src_y),
weight_x
);
const Color avg_b = Color::average(
get_clamped_color(src_x + 0.0, src_y + 1.0),
get_clamped_color(src_x + 0.0, src_y + 1.0),
weight_x
);
bilinear_bitmap[y * new_width + x] = Color::average(avg_t, avg_b, weight_y);
const float weight_x = BAN::Math::fmod(src_x, 1.0f);
const float weight_y = BAN::Math::fmod(src_y, 1.0f);
const uint64_t src_x_u64 = BAN::Math::clamp<uint64_t>(src_x, 0, width() - 1);
const uint64_t src_y_u64 = BAN::Math::clamp<uint64_t>(src_y, 0, height() - 1);
const auto tl = floating_bitmap[(src_y_u64 + 0) * temp_w + (src_x_u64 + 0)];
const auto tr = floating_bitmap[(src_y_u64 + 0) * temp_w + (src_x_u64 + 1)];
const auto bl = floating_bitmap[(src_y_u64 + 1) * temp_w + (src_x_u64 + 0)];
const auto br = floating_bitmap[(src_y_u64 + 1) * temp_w + (src_x_u64 + 1)];
const auto avg_t = tl * (1.0f - weight_x) + tr * weight_x;
const auto avg_b = bl * (1.0f - weight_x) + br * weight_x;
const auto avg = avg_t * (1.0f - weight_y) + avg_b * weight_y;
bilinear_bitmap[y * new_width + x] = avg.as_color();
}
}
@ -153,35 +175,52 @@ namespace LibImage
case ResizeAlgorithm::Cubic:
{
BAN::Vector<Color> bicubic_bitmap;
TRY(bicubic_bitmap.resize(new_width * new_height));
TRY(bicubic_bitmap.resize(new_width * new_height, {}));
constexpr auto cubic_interpolate =
[](FloatingColor p[4], double x)
[](const FloatingColor p[4], float weight) -> FloatingColor
{
const auto a = (p[0] * -0.5) + (p[1] * 1.5) + (p[2] * -1.5) + (p[3] * 0.5);
const auto b = p[0] + (p[1] * -2.5) + (p[2] * 2.0) + (p[3] * -0.5);
const auto c = (p[0] * -0.5) + (p[2] * 0.5);
const auto d = p[1];
return ((a * x + b) * x + c) * x + d;
return ((a * weight + b) * weight + c) * weight + d;
};
const uint64_t temp_w = width() + 3;
const uint64_t temp_h = height() + 3;
BAN::Vector<FloatingColor> floating_bitmap;
TRY(floating_bitmap.resize(temp_w * temp_h, {}));
for (uint64_t y = 0; y < temp_h; y++)
for (uint64_t x = 0; x < temp_w; x++)
floating_bitmap[y * temp_w + x] = get_clamped_color(
static_cast<int64_t>(x) - 1,
static_cast<int64_t>(y) - 1
);
for (uint64_t y = 0; y < new_height; y++)
{
for (uint64_t x = 0; x < new_width; x++)
{
const double src_x = x * ratio_x;
const double src_y = y * ratio_y;
const double weight_x = src_x - BAN::Math::floor(src_x);
const double weight_y = src_y - BAN::Math::floor(src_y);
const float src_x = x * ratio_x;
const float src_y = y * ratio_y;
const float weight_x = BAN::Math::fmod(src_x, 1.0f);
const float weight_y = BAN::Math::fmod(src_y, 1.0f);
const uint64_t src_x_u64 = BAN::Math::clamp<uint64_t>(src_x, 0, width() - 1) + 1;
const uint64_t src_y_u64 = BAN::Math::clamp<uint64_t>(src_y, 0, height() - 1) + 1;
FloatingColor values[4];
for (int64_t m = -1; m <= 2; m++)
{
FloatingColor p[4];
p[0] = get_clamped_color(src_x - 1.0, src_y + m);
p[1] = get_clamped_color(src_x + 0.0, src_y + m);
p[2] = get_clamped_color(src_x + 1.0, src_y + m);
p[3] = get_clamped_color(src_x + 2.0, src_y + m);
const FloatingColor p[4] {
floating_bitmap[(src_y_u64 + m) * temp_w + (src_x_u64 - 1)],
floating_bitmap[(src_y_u64 + m) * temp_w + (src_x_u64 + 0)],
floating_bitmap[(src_y_u64 + m) * temp_w + (src_x_u64 + 1)],
floating_bitmap[(src_y_u64 + m) * temp_w + (src_x_u64 + 2)],
};
values[m + 1] = cubic_interpolate(p, weight_x);
}

View File

@ -22,6 +22,16 @@ namespace LibInput
int32_t rel_y;
};
struct MouseMoveAbsEvent
{
int32_t abs_x;
int32_t abs_y;
int32_t min_x;
int32_t min_y;
int32_t max_x;
int32_t max_y;
};
struct MouseScrollEvent
{
int32_t scroll;
@ -31,6 +41,7 @@ namespace LibInput
{
MouseButtonEvent,
MouseMoveEvent,
MouseMoveAbsEvent,
MouseScrollEvent,
};
@ -41,6 +52,7 @@ namespace LibInput
{
MouseButtonEvent button_event;
MouseMoveEvent move_event;
MouseMoveAbsEvent move_abs_event;
MouseScrollEvent scroll_event;
};
};

View File

@ -57,5 +57,5 @@ foreach(project ${USERSPACE_PROGRAMS})
# This is to allow cmake to link when libc updates
target_link_options(${project} PRIVATE -nolibc)
# Default compile options
target_compile_options(${project} PRIVATE -g -O2 -Wall -Wextra -Werror)
target_compile_options(${project} PRIVATE -g -O2 -Wall -Wextra -Werror -msse -msse2)
endforeach()

View File

@ -613,36 +613,9 @@ void WindowServer::on_mouse_button(LibInput::MouseButtonEvent event)
}
}
void WindowServer::on_mouse_move(LibInput::MouseMoveEvent event)
void WindowServer::on_mouse_move_impl(int32_t new_x, int32_t new_y)
{
if (m_is_mouse_captured)
{
ASSERT(m_focused_window);
LibGUI::EventPacket::MouseMoveEvent packet;
packet.event.x = event.rel_x;
packet.event.y = -event.rel_y;
if (auto ret = packet.send_serialized(m_focused_window->client_fd()); ret.is_error())
dwarnln("could not send mouse move event: {}", ret.error());
return;
}
const auto [new_x, new_y] =
[&]() -> Position
{
const int32_t new_x = m_cursor.x + event.rel_x;
const int32_t new_y = m_cursor.y - event.rel_y;
return (m_state == State::Fullscreen)
? Position {
.x = BAN::Math::clamp(new_x, m_focused_window->client_x(), m_focused_window->client_x() + m_focused_window->client_width()),
.y = BAN::Math::clamp(new_y, m_focused_window->client_y(), m_focused_window->client_y() + m_focused_window->client_height())
}
: Position {
.x = BAN::Math::clamp(new_x, 0, m_framebuffer.width),
.y = BAN::Math::clamp(new_y, 0, m_framebuffer.height)
};
}();
LibInput::MouseMoveEvent event;
event.rel_x = new_x - m_cursor.x;
event.rel_y = new_y - m_cursor.y;
if (event.rel_x == 0 && event.rel_y == 0)
@ -706,6 +679,74 @@ void WindowServer::on_mouse_move(LibInput::MouseMoveEvent event)
}
}
void WindowServer::on_mouse_move(LibInput::MouseMoveEvent event)
{
if (m_is_mouse_captured)
{
ASSERT(m_focused_window);
LibGUI::EventPacket::MouseMoveEvent packet;
packet.event.x = event.rel_x;
packet.event.y = -event.rel_y;
if (auto ret = packet.send_serialized(m_focused_window->client_fd()); ret.is_error())
dwarnln("could not send mouse move event: {}", ret.error());
return;
}
int32_t min_x, max_x;
int32_t min_y, max_y;
if (m_state == State::Fullscreen)
{
min_x = m_focused_window->client_x();
min_y = m_focused_window->client_y();
max_x = m_focused_window->client_x() + m_focused_window->client_width();
max_y = m_focused_window->client_y() + m_focused_window->client_height();
}
else
{
min_x = 0;
min_y = 0;
max_x = m_framebuffer.width;
max_y = m_framebuffer.height;
}
const int32_t new_x = BAN::Math::clamp(m_cursor.x + event.rel_x, min_x, max_x);
const int32_t new_y = BAN::Math::clamp(m_cursor.y + event.rel_y, min_y, max_y);
return on_mouse_move_impl(new_x, new_y);
}
void WindowServer::on_mouse_move_abs(LibInput::MouseMoveAbsEvent event)
{
constexpr auto map =
[](int32_t val, int32_t in_min, int32_t in_max, int32_t out_min, int32_t out_max) -> int32_t
{
return (val - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
};
int32_t out_min_x, out_max_x;
int32_t out_min_y, out_max_y;
if (m_state == State::Fullscreen)
{
out_min_x = m_focused_window->client_x();
out_min_y = m_focused_window->client_y();
out_max_x = m_focused_window->client_x() + m_focused_window->client_width();
out_max_y = m_focused_window->client_y() + m_focused_window->client_height();
}
else
{
out_min_x = 0;
out_min_y = 0;
out_max_x = m_framebuffer.width;
out_max_y = m_framebuffer.height;
}
const int32_t new_x = map(event.abs_x, event.min_x, event.max_x, out_min_x, out_max_x);
const int32_t new_y = map(event.abs_y, event.min_y, event.max_y, out_min_y, out_max_y);
return on_mouse_move_impl(new_x, new_y);
}
void WindowServer::on_mouse_scroll(LibInput::MouseScrollEvent event)
{
if (m_focused_window)

View File

@ -46,6 +46,7 @@ public:
void on_key_event(LibInput::KeyEvent event);
void on_mouse_button(LibInput::MouseButtonEvent event);
void on_mouse_move(LibInput::MouseMoveEvent event);
void on_mouse_move_abs(LibInput::MouseMoveAbsEvent event);
void on_mouse_scroll(LibInput::MouseScrollEvent event);
void set_focused_window(BAN::RefPtr<Window> window);
@ -63,6 +64,8 @@ public:
bool is_stopped() const { return m_is_stopped; }
private:
void on_mouse_move_impl(int32_t new_x, int32_t new_y);
void mark_pending_sync(Rectangle area);
bool resize_window(BAN::RefPtr<Window> window, uint32_t width, uint32_t height) const;

View File

@ -290,6 +290,9 @@ int main()
case LibInput::MouseEventType::MouseMoveEvent:
window_server.on_mouse_move(event.move_event);
break;
case LibInput::MouseEventType::MouseMoveAbsEvent:
window_server.on_mouse_move_abs(event.move_abs_event);
break;
case LibInput::MouseEventType::MouseScrollEvent:
window_server.on_mouse_scroll(event.scroll_event);
break;