From d380e431660f8a18d311641b962743b5839f8136 Mon Sep 17 00:00:00 2001 From: Ali Salehi Date: Sun, 18 Feb 2024 21:28:30 +0100 Subject: [PATCH 01/14] Add xinput bindings to core:sys/windows --- core/sys/windows/xinput.odin | 227 +++++++++++++++++++++++++++++++++++ 1 file changed, 227 insertions(+) create mode 100644 core/sys/windows/xinput.odin diff --git a/core/sys/windows/xinput.odin b/core/sys/windows/xinput.odin new file mode 100644 index 000000000..2b1303e0d --- /dev/null +++ b/core/sys/windows/xinput.odin @@ -0,0 +1,227 @@ +// +build windows +package sys_windows + +foreign import "system:xinput.lib" + +// Device types available in XINPUT_CAPABILITIES +// Correspond to XINPUT_DEVTYPE_... +XINPUT_DEVTYPE :: enum BYTE { + GAMEPAD = 0x01, +} + +// Device subtypes available in XINPUT_CAPABILITIES +// Correspond to XINPUT_DEVSUBTYPE_... +XINPUT_DEVSUBTYPE :: enum BYTE { + UNKNOWN = 0x00, + GAMEPAD = 0x01, + WHEEL = 0x02, + ARCADE_STICK = 0x03, + FLIGHT_STICK = 0x04, + DANCE_PAD = 0x05, + GUITAR = 0x06, + GUITAR_ALTERNATE = 0x07, + DRUM_KIT = 0x08, + GUITAR_BASS = 0x0B, + ARCADE_PAD = 0x13, +} + +// Flags for XINPUT_CAPABILITIES +// Correspond to log2(XINPUT_CAPS_...) +XINPUT_CAP :: enum { + FFB_SUPPORTED = 0, + WIRELESS = 1, + VOICE_SUPPORTED = 2, + PMD_SUPPORTED = 3, + NO_NAVIGATION = 4, +} +XINPUT_CAPS :: bit_set[XINPUT_CAP;WORD] + +// Constants for gamepad buttons +// Correspond to log2(XINPUT_GAMEPAD_...) +XINPUT_GAMEPAD_BUTTON_BIT :: enum { + DPAD_UP = 0, + DPAD_DOWN = 1, + DPAD_LEFT = 2, + DPAD_RIGHT = 3, + START = 4, + BACK = 5, + LEFT_THUMB = 6, + RIGHT_THUMB = 7, + LEFT_SHOULDER = 8, + RIGHT_SHOULDER = 9, + A = 12, + B = 13, + X = 14, + Y = 15, +} +XINPUT_GAMEPAD_BUTTON :: bit_set[XINPUT_GAMEPAD_BUTTON_BIT;WORD] + +// Gamepad thresholds +XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE: SHORT : 7849 +XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE: SHORT : 8689 +XINPUT_GAMEPAD_TRIGGER_THRESHOLD: SHORT : 30 + +// Flags to pass to XInputGetCapabilities +// Corresponds to log2(XINPUT_FLAG_...) +XINPUT_FLAG_BIT :: enum { + GAMEPAD = 0, +} +XINPUT_FLAG :: bit_set[XINPUT_FLAG_BIT;DWORD] + +// Devices that support batteries +// Corresponds to BATTERY_DEVTYPE_... +BATTERY_DEVTYPE :: enum BYTE { + GAMEPAD = 0x00, + HEADSET = 0x01, +} + +// Flags for battery status level +// Correspond to BATTERY_TYPE_... +BATTERY_TYPE :: enum BYTE { + DISCONNECTED = 0x00, // This device is not connected + WIRED = 0x01, // Wired device, no battery + ALKALINE = 0x02, // Alkaline battery source + NIMH = 0x03, // Nickel Metal Hydride battery source + UNKNOWN = 0xFF, // Cannot determine the battery type +} + +// These are only valid for wireless, connected devices, with known battery types +// The amount of use time remaining depends on the type of device. +// Correspond to BATTERY_LEVEL_... +BATTERY_LEVEL :: enum BYTE { + EMPTY = 0x00, + LOW = 0x01, + MEDIUM = 0x02, + FULL = 0x03, +} + +// User index definitions + +// Index of the gamer associated with the device +XUSER :: enum DWORD { + One = 0, + Two = 1, + Three = 2, + Four = 3, + Any = 0x000000FF, // Can be only used with XInputGetKeystroke +} + +XUSER_MAX_COUNT :: 4 + +// Codes returned for the gamepad keystroke +// Corresponds to VK_PAD_... +VK_PAD :: enum WORD { + A = 0x5800, + B = 0x5801, + X = 0x5802, + Y = 0x5803, + RSHOULDER = 0x5804, + LSHOULDER = 0x5805, + LTRIGGER = 0x5806, + RTRIGGER = 0x5807, + DPAD_UP = 0x5810, + DPAD_DOWN = 0x5811, + DPAD_LEFT = 0x5812, + DPAD_RIGHT = 0x5813, + START = 0x5814, + BACK = 0x5815, + LTHUMB_PRESS = 0x5816, + RTHUMB_PRESS = 0x5817, + LTHUMB_UP = 0x5820, + LTHUMB_DOWN = 0x5821, + LTHUMB_RIGHT = 0x5822, + LTHUMB_LEFT = 0x5823, + LTHUMB_UPLEFT = 0x5824, + LTHUMB_UPRIGHT = 0x5825, + LTHUMB_DOWNRIGHT = 0x5826, + LTHUMB_DOWNLEFT = 0x5827, + RTHUMB_UP = 0x5830, + RTHUMB_DOWN = 0x5831, + RTHUMB_RIGHT = 0x5832, + RTHUMB_LEFT = 0x5833, + RTHUMB_UPLEFT = 0x5834, + RTHUMB_UPRIGHT = 0x5835, + RTHUMB_DOWNRIGHT = 0x5836, + RTHUMB_DOWNLEFT = 0x5837, +} + +// Flags used in XINPUT_KEYSTROKE +// Correspond to log2(XINPUT_KEYSTROKE_...) +XINPUT_KEYSTROKE_BIT :: enum { + KEYDOWN = 0, + KEYUP = 1, + REPEAT = 2, +} +XINPUT_KEYSTROKES :: bit_set[XINPUT_KEYSTROKE_BIT;WORD] + +// Structures used by XInput APIs +XINPUT_GAMEPAD :: struct { + wButtons: XINPUT_GAMEPAD_BUTTON, + bLeftTrigger: BYTE, + bRightTrigger: BYTE, + sThumbLX: SHORT, + sThumbLY: SHORT, + sThumbRX: SHORT, + sThumbRY: SHORT, +} + +XINPUT_STATE :: struct { + dwPacketNumber: DWORD, + Gamepad: XINPUT_GAMEPAD, +} + +XINPUT_VIBRATION :: struct { + wLeftMotorSpeed: WORD, + wRightMotorSpeed: WORD, +} + +XINPUT_CAPABILITIES :: struct { + Type: XINPUT_DEVTYPE, + SubType: XINPUT_DEVSUBTYPE, + Flags: XINPUT_CAPS, + Gamepad: XINPUT_GAMEPAD, + Vibration: XINPUT_VIBRATION, +} + +XINPUT_BATTERY_INFORMATION :: struct { + BatteryType: BATTERY_TYPE, + BatteryLevel: BATTERY_LEVEL, +} + +XINPUT_KEYSTROKE :: struct { + VirtualKey: VK_PAD, + Unicode: WCHAR, + Flags: XINPUT_KEYSTROKES, + UserIndex: XUSER, + HidCode: BYTE, +} + +// XInput APIs +@(default_calling_convention = "system") +foreign xinput { + + @(link_name = "XInputGetState") + XInputGetState :: proc(user: XUSER, pState: ^XINPUT_STATE) -> System_Error --- + + @(link_name = "XInputSetState") + XInputSetState :: proc(user: XUSER, pVibration: ^XINPUT_VIBRATION) -> System_Error --- + + @(link_name = "XInputGetCapabilities") + XInputGetCapabilities :: proc(user: XUSER, dwFlags: XINPUT_FLAG, pCapabilities: ^XINPUT_CAPABILITIES) -> System_Error --- + + @(link_name = "XInputEnable") + XInputEnable :: proc(enable: BOOL) --- + + @(link_name = "XInputGetAudioDeviceIds") + XInputGetAudioDeviceIds :: proc(user: XUSER, pRenderDeviceId: LPWSTR, pRenderCount: ^UINT, pCaptureDeviceId: LPWSTR, pCaptureCount: ^UINT) -> System_Error --- + + @(link_name = "XInputGetBatteryInformation") + XInputGetBatteryInformation :: proc(user: XUSER, devType: BATTERY_DEVTYPE, pBatteryInformation: ^XINPUT_BATTERY_INFORMATION) -> System_Error --- + + @(link_name = "XInputGetKeystroke") + XInputGetKeystroke :: proc(user: XUSER, dwReserved: DWORD, pKeystroke: ^XINPUT_KEYSTROKE) -> System_Error --- + + @(link_name = "XInputGetDSoundAudioDeviceGuids") + XInputGetDSoundAudioDeviceGuids :: proc(user: XUSER, pDSoundRenderGuid: ^GUID, pDSoundCaptureGuid: ^GUID) -> System_Error --- + +} From 8aab0f9e34ab8818b7599c285799819b22319cad Mon Sep 17 00:00:00 2001 From: Ali Salehi Date: Mon, 19 Feb 2024 15:55:57 +0100 Subject: [PATCH 02/14] Add distinct and remove unnecessary link_names --- core/sys/windows/xinput.odin | 33 ++++++++------------------------- 1 file changed, 8 insertions(+), 25 deletions(-) diff --git a/core/sys/windows/xinput.odin b/core/sys/windows/xinput.odin index 2b1303e0d..014d2573a 100644 --- a/core/sys/windows/xinput.odin +++ b/core/sys/windows/xinput.odin @@ -27,18 +27,18 @@ XINPUT_DEVSUBTYPE :: enum BYTE { // Flags for XINPUT_CAPABILITIES // Correspond to log2(XINPUT_CAPS_...) -XINPUT_CAP :: enum { +XINPUT_CAP :: enum WORD { FFB_SUPPORTED = 0, WIRELESS = 1, VOICE_SUPPORTED = 2, PMD_SUPPORTED = 3, NO_NAVIGATION = 4, } -XINPUT_CAPS :: bit_set[XINPUT_CAP;WORD] +XINPUT_CAPS :: distinct bit_set[XINPUT_CAP;WORD] // Constants for gamepad buttons // Correspond to log2(XINPUT_GAMEPAD_...) -XINPUT_GAMEPAD_BUTTON_BIT :: enum { +XINPUT_GAMEPAD_BUTTON_BIT :: enum WORD { DPAD_UP = 0, DPAD_DOWN = 1, DPAD_LEFT = 2, @@ -54,7 +54,7 @@ XINPUT_GAMEPAD_BUTTON_BIT :: enum { X = 14, Y = 15, } -XINPUT_GAMEPAD_BUTTON :: bit_set[XINPUT_GAMEPAD_BUTTON_BIT;WORD] +XINPUT_GAMEPAD_BUTTON :: distinct bit_set[XINPUT_GAMEPAD_BUTTON_BIT;WORD] // Gamepad thresholds XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE: SHORT : 7849 @@ -63,10 +63,10 @@ XINPUT_GAMEPAD_TRIGGER_THRESHOLD: SHORT : 30 // Flags to pass to XInputGetCapabilities // Corresponds to log2(XINPUT_FLAG_...) -XINPUT_FLAG_BIT :: enum { +XINPUT_FLAG_BIT :: enum WORD { GAMEPAD = 0, } -XINPUT_FLAG :: bit_set[XINPUT_FLAG_BIT;DWORD] +XINPUT_FLAG :: distinct bit_set[XINPUT_FLAG_BIT;DWORD] // Devices that support batteries // Corresponds to BATTERY_DEVTYPE_... @@ -147,12 +147,12 @@ VK_PAD :: enum WORD { // Flags used in XINPUT_KEYSTROKE // Correspond to log2(XINPUT_KEYSTROKE_...) -XINPUT_KEYSTROKE_BIT :: enum { +XINPUT_KEYSTROKE_BIT :: enum WORD { KEYDOWN = 0, KEYUP = 1, REPEAT = 2, } -XINPUT_KEYSTROKES :: bit_set[XINPUT_KEYSTROKE_BIT;WORD] +XINPUT_KEYSTROKES :: distinct bit_set[XINPUT_KEYSTROKE_BIT;WORD] // Structures used by XInput APIs XINPUT_GAMEPAD :: struct { @@ -199,29 +199,12 @@ XINPUT_KEYSTROKE :: struct { // XInput APIs @(default_calling_convention = "system") foreign xinput { - - @(link_name = "XInputGetState") XInputGetState :: proc(user: XUSER, pState: ^XINPUT_STATE) -> System_Error --- - - @(link_name = "XInputSetState") XInputSetState :: proc(user: XUSER, pVibration: ^XINPUT_VIBRATION) -> System_Error --- - - @(link_name = "XInputGetCapabilities") XInputGetCapabilities :: proc(user: XUSER, dwFlags: XINPUT_FLAG, pCapabilities: ^XINPUT_CAPABILITIES) -> System_Error --- - - @(link_name = "XInputEnable") XInputEnable :: proc(enable: BOOL) --- - - @(link_name = "XInputGetAudioDeviceIds") XInputGetAudioDeviceIds :: proc(user: XUSER, pRenderDeviceId: LPWSTR, pRenderCount: ^UINT, pCaptureDeviceId: LPWSTR, pCaptureCount: ^UINT) -> System_Error --- - - @(link_name = "XInputGetBatteryInformation") XInputGetBatteryInformation :: proc(user: XUSER, devType: BATTERY_DEVTYPE, pBatteryInformation: ^XINPUT_BATTERY_INFORMATION) -> System_Error --- - - @(link_name = "XInputGetKeystroke") XInputGetKeystroke :: proc(user: XUSER, dwReserved: DWORD, pKeystroke: ^XINPUT_KEYSTROKE) -> System_Error --- - - @(link_name = "XInputGetDSoundAudioDeviceGuids") XInputGetDSoundAudioDeviceGuids :: proc(user: XUSER, pDSoundRenderGuid: ^GUID, pDSoundCaptureGuid: ^GUID) -> System_Error --- - } From e5f32e145512a1fb0db142a214dee2d3b42ac073 Mon Sep 17 00:00:00 2001 From: Karl Zylinski Date: Sat, 21 Dec 2024 15:47:26 +0100 Subject: [PATCH 03/14] Makes tracking allocator default to crashing on a bad free instead of add to bad_free_array. The bad_free_array remains to not break old code. The new default behavior is implemented in a callback that you can override, there's a second provided callback that provides the old behavior where an element was added to bad_free_array. Rationale: Many people are just checking the allocation_map, but don't check the bad free array. Several examples throughout core that use tracking allocator don't check bad_free_array either, so people have been taught not to check it. --- core/mem/tracking_allocator.odin | 50 ++++++++++++++++++---- core/testing/runner.odin | 1 + tests/core/container/test_core_rbtree.odin | 1 + 3 files changed, 43 insertions(+), 9 deletions(-) diff --git a/core/mem/tracking_allocator.odin b/core/mem/tracking_allocator.odin index cf780de3f..25c547471 100644 --- a/core/mem/tracking_allocator.odin +++ b/core/mem/tracking_allocator.odin @@ -34,12 +34,18 @@ Tracking_Allocator_Bad_Free_Entry :: struct { location: runtime.Source_Code_Location, } +/* +Callback type for when tracking allocator runs into a bad free. +*/ +Tracking_Allocator_Bad_Free_Callback :: proc(t: ^Tracking_Allocator, memory: rawptr, location: runtime.Source_Code_Location) + /* Tracking allocator data. */ Tracking_Allocator :: struct { backing: Allocator, allocation_map: map[rawptr]Tracking_Allocator_Entry, + bad_free_callback: Tracking_Allocator_Bad_Free_Callback, bad_free_array: [dynamic]Tracking_Allocator_Bad_Free_Entry, mutex: sync.Mutex, clear_on_free_all: bool, @@ -61,6 +67,7 @@ allocate the tracked data. tracking_allocator_init :: proc(t: ^Tracking_Allocator, backing_allocator: Allocator, internals_allocator := context.allocator) { t.backing = backing_allocator t.allocation_map.allocator = internals_allocator + t.bad_free_callback = tracking_allocator_bad_free_callback_panic t.bad_free_array.allocator = internals_allocator if .Free_All in query_features(t.backing) { t.clear_on_free_all = true @@ -109,6 +116,33 @@ tracking_allocator_reset :: proc(t: ^Tracking_Allocator) { sync.mutex_unlock(&t.mutex) } +/* +Default behavior for a bad free: Crash with error message that says where the +bad free happened. + +Override Tracking_Allocator.bad_free_callback to have something else happen. For +example, you can use tracking_allocator_bad_free_callback_add_to_array to return +the tracking allocator to the old behavior, where the bad_free_array was used. +*/ +tracking_allocator_bad_free_callback_panic :: proc(t: ^Tracking_Allocator, memory: rawptr, location: runtime.Source_Code_Location) { + runtime.print_caller_location(location) + runtime.print_string(" Tracking allocator error: Bad free of pointer ") + runtime.print_uintptr(uintptr(memory)) + runtime.print_string("\n") + runtime.trap() +} + +/* +Alternative behavior for a bad free: Store in `bad_free_array`. If you use this, +then you must make sure to check Tracking_Allocator.bad_free_array at some point. +*/ +tracking_allocator_bad_free_callback_add_to_array :: proc(t: ^Tracking_Allocator, memory: rawptr, location: runtime.Source_Code_Location) { + append(&t.bad_free_array, Tracking_Allocator_Bad_Free_Entry { + memory = memory, + location = location, + }) +} + /* Tracking allocator. @@ -116,8 +150,10 @@ The tracking allocator is an allocator wrapper that tracks memory allocations. This allocator stores all the allocations in a map. Whenever a pointer that's not inside of the map is freed, the `bad_free_array` entry is added. -An example of how to use the `Tracking_Allocator` to track subsequent allocations -in your program and report leaks and bad frees: +Here follows an example of how to use the `Tracking_Allocator` to track +subsequent allocations in your program and report leaks. By default, the +tracking allocator will crash on bad frees. You can override that behavior by +overriding `track.bad_free_callback`. Example: @@ -137,9 +173,6 @@ Example: for _, leak in track.allocation_map { fmt.printf("%v leaked %m\n", leak.location, leak.size) } - for bad_free in track.bad_free_array { - fmt.printf("%v allocation %p was freed badly\n", bad_free.location, bad_free.memory) - } } */ @(require_results) @@ -191,10 +224,9 @@ tracking_allocator_proc :: proc( } if mode == .Free && old_memory != nil && old_memory not_in data.allocation_map { - append(&data.bad_free_array, Tracking_Allocator_Bad_Free_Entry{ - memory = old_memory, - location = loc, - }) + if data.bad_free_callback != nil { + data.bad_free_callback(data, old_memory, loc) + } } else { result = data.backing.procedure(data.backing.data, mode, size, alignment, old_memory, old_size, loc) or_return } diff --git a/core/testing/runner.odin b/core/testing/runner.odin index 6b9d610ed..83a5ac4e7 100644 --- a/core/testing/runner.odin +++ b/core/testing/runner.odin @@ -391,6 +391,7 @@ runner :: proc(internal_tests: []Internal_Test) -> bool { fmt.assertf(alloc_error == nil, "Error allocating memory for task allocator #%i: %v", i, alloc_error) when TRACKING_MEMORY { mem.tracking_allocator_init(&task_memory_trackers[i], mem.rollback_stack_allocator(&task_allocators[i])) + task_memory_trackers[i].bad_free_callback = mem.tracking_allocator_bad_free_callback_add_to_array } } diff --git a/tests/core/container/test_core_rbtree.odin b/tests/core/container/test_core_rbtree.odin index bdd23691c..d220b7ed6 100644 --- a/tests/core/container/test_core_rbtree.odin +++ b/tests/core/container/test_core_rbtree.odin @@ -11,6 +11,7 @@ import "core:log" test_rbtree_integer :: proc(t: ^testing.T, $Key: typeid, $Value: typeid) { track: mem.Tracking_Allocator mem.tracking_allocator_init(&track, context.allocator) + track.bad_free_callback = mem.tracking_allocator_bad_free_callback_add_to_array defer mem.tracking_allocator_destroy(&track) context.allocator = mem.tracking_allocator(&track) From 276dab69b69fb8429c3e2a2e4fc8f0cd994c010d Mon Sep 17 00:00:00 2001 From: Misomosi Date: Sun, 10 Nov 2024 10:41:16 -0500 Subject: [PATCH 04/14] Pack MDEI struct to fix issue #4407 --- core/sys/windows/dbghelp.odin | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/sys/windows/dbghelp.odin b/core/sys/windows/dbghelp.odin index 336992b4a..e32b4c874 100644 --- a/core/sys/windows/dbghelp.odin +++ b/core/sys/windows/dbghelp.odin @@ -15,7 +15,7 @@ MINIDUMP_DIRECTORY :: struct { Location: MINIDUMP_LOCATION_DESCRIPTOR, } -MINIDUMP_EXCEPTION_INFORMATION :: struct { +MINIDUMP_EXCEPTION_INFORMATION :: struct #max_field_align(4) { ThreadId: DWORD, ExceptionPointers: ^EXCEPTION_POINTERS, ClientPointers: BOOL, From b136aa26c8269c08c94380578dad0c2dcdcbfec1 Mon Sep 17 00:00:00 2001 From: Laytan Laats Date: Mon, 6 Jan 2025 21:14:37 +0100 Subject: [PATCH 05/14] sys/windows: fix xinput build tag --- core/sys/windows/xinput.odin | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/sys/windows/xinput.odin b/core/sys/windows/xinput.odin index 014d2573a..0089f88cb 100644 --- a/core/sys/windows/xinput.odin +++ b/core/sys/windows/xinput.odin @@ -1,4 +1,4 @@ -// +build windows +#+build windows package sys_windows foreign import "system:xinput.lib" From cdef798fbc11df248a20e46447aaf014e7c690d2 Mon Sep 17 00:00:00 2001 From: Lion Schitik Date: Wed, 8 Jan 2025 01:47:36 +0100 Subject: [PATCH 06/14] Add SetWindowSubclass and RegisterHotKey functions --- core/sys/windows/comctl32.odin | 1 + core/sys/windows/types.odin | 2 ++ core/sys/windows/user32.odin | 2 ++ 3 files changed, 5 insertions(+) diff --git a/core/sys/windows/comctl32.odin b/core/sys/windows/comctl32.odin index 477800413..69c502b06 100644 --- a/core/sys/windows/comctl32.odin +++ b/core/sys/windows/comctl32.odin @@ -6,4 +6,5 @@ foreign import "system:Comctl32.lib" @(default_calling_convention="system") foreign Comctl32 { LoadIconWithScaleDown :: proc(hinst: HINSTANCE, pszName: PCWSTR, cx: c_int, cy: c_int, phico: ^HICON) -> HRESULT --- + SetWindowSubclass :: proc(hwnd: HWND, pfnSubclass: SUBCLASSPROC, uIdSubclass: UINT_PTR, dwRefData: DWORD_PTR) --- } diff --git a/core/sys/windows/types.odin b/core/sys/windows/types.odin index aece4dc43..ab79c682a 100644 --- a/core/sys/windows/types.odin +++ b/core/sys/windows/types.odin @@ -796,6 +796,8 @@ TIMERPROC :: #type proc "system" (HWND, UINT, UINT_PTR, DWORD) WNDPROC :: #type proc "system" (HWND, UINT, WPARAM, LPARAM) -> LRESULT +SUBCLASSPROC :: #type proc "system" (HWND, UINT, WPARAM, LPARAM, UINT_PTR, DWORD_PTR) -> LRESULT + HOOKPROC :: #type proc "system" (code: c_int, wParam: WPARAM, lParam: LPARAM) -> LRESULT WINEVENTPROC :: #type proc "system" ( diff --git a/core/sys/windows/user32.odin b/core/sys/windows/user32.odin index da979a3e3..9ebd86201 100644 --- a/core/sys/windows/user32.odin +++ b/core/sys/windows/user32.odin @@ -32,6 +32,8 @@ foreign user32 { RegisterClassExW :: proc(^WNDCLASSEXW) -> ATOM --- UnregisterClassW :: proc(lpClassName: LPCWSTR, hInstance: HINSTANCE) -> BOOL --- + RegisterHotKey :: proc(hnwd: HWND, id: int, fsModifiers: UINT, vk: UINT) -> BOOL --- + CreateWindowExW :: proc( dwExStyle: DWORD, lpClassName: LPCWSTR, From 9a68eb401d74a57f2bc220abaa31fd13bb90c559 Mon Sep 17 00:00:00 2001 From: david_cauchi Date: Wed, 8 Jan 2025 15:06:17 +1100 Subject: [PATCH 07/14] Fix name of RI_MOUSE_LEFT_BUTTON_DOWN containing S at the end --- core/sys/windows/user32.odin | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/sys/windows/user32.odin b/core/sys/windows/user32.odin index da979a3e3..379431402 100644 --- a/core/sys/windows/user32.odin +++ b/core/sys/windows/user32.odin @@ -553,7 +553,7 @@ MOUSE_ATTRIBUTES_CHANGED :: 0x04 MOUSE_MOVE_NOCOALESCE :: 0x08 RI_MOUSE_BUTTON_1_DOWN :: 0x0001 -RI_MOUSE_LEFT_BUTTON_DOWNS :: RI_MOUSE_BUTTON_1_DOWN +RI_MOUSE_LEFT_BUTTON_DOWN :: RI_MOUSE_BUTTON_1_DOWN RI_MOUSE_BUTTON_1_UP :: 0x0002 RI_MOUSE_LEFT_BUTTON_UP :: RI_MOUSE_BUTTON_1_UP RI_MOUSE_BUTTON_2_DOWN :: 0x0004 From ab3e2340c26577567960d74c4eaa296e276a831f Mon Sep 17 00:00:00 2001 From: Lion Schitik Date: Wed, 8 Jan 2025 12:38:28 +0100 Subject: [PATCH 08/14] review --- core/sys/windows/user32.odin | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/core/sys/windows/user32.odin b/core/sys/windows/user32.odin index 9ebd86201..19b53e349 100644 --- a/core/sys/windows/user32.odin +++ b/core/sys/windows/user32.odin @@ -2,6 +2,7 @@ package sys_windows import "base:intrinsics" +import "core:c" foreign import user32 "system:User32.lib" @(default_calling_convention="system") @@ -32,7 +33,7 @@ foreign user32 { RegisterClassExW :: proc(^WNDCLASSEXW) -> ATOM --- UnregisterClassW :: proc(lpClassName: LPCWSTR, hInstance: HINSTANCE) -> BOOL --- - RegisterHotKey :: proc(hnwd: HWND, id: int, fsModifiers: UINT, vk: UINT) -> BOOL --- + RegisterHotKey :: proc(hnwd: HWND, id: c.int, fsModifiers: UINT, vk: UINT) -> BOOL --- CreateWindowExW :: proc( dwExStyle: DWORD, From 2aae4cfd461860bd10dcb922f867c98212a11449 Mon Sep 17 00:00:00 2001 From: Laytan Laats Date: Wed, 8 Jan 2025 18:46:25 +0100 Subject: [PATCH 09/14] fix #no_nil in debug info Fixes #4664 --- src/llvm_backend_debug.cpp | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/llvm_backend_debug.cpp b/src/llvm_backend_debug.cpp index 464f7065c..3951fc977 100644 --- a/src/llvm_backend_debug.cpp +++ b/src/llvm_backend_debug.cpp @@ -415,6 +415,7 @@ gb_internal LLVMMetadataRef lb_debug_union(lbModule *m, Type *type, String name, LLVMMetadataRef member_scope = lb_get_llvm_metadata(m, bt->Union.scope); unsigned element_count = cast(unsigned)bt->Union.variants.count; if (index_offset > 0) { + GB_ASSERT(index_offset == 1); element_count += 1; } @@ -437,13 +438,11 @@ gb_internal LLVMMetadataRef lb_debug_union(lbModule *m, Type *type, String name, for_array(j, bt->Union.variants) { Type *variant = bt->Union.variants[j]; - unsigned field_index = cast(unsigned)(index_offset+j); - - char name[16] = {}; - gb_snprintf(name, gb_size_of(name), "v%u", field_index); + char name[32] = {}; + gb_snprintf(name, gb_size_of(name), "v%td", j); isize name_len = gb_strlen(name); - elements[field_index] = LLVMDIBuilderCreateMemberType( + elements[index_offset+j] = LLVMDIBuilderCreateMemberType( m->debug_builder, member_scope, name, name_len, file, line, From 7185a93a8631060958565d6e3fba03b4b6eeccce Mon Sep 17 00:00:00 2001 From: Laytan Laats Date: Wed, 8 Jan 2025 20:22:59 +0100 Subject: [PATCH 10/14] actually fix #no_nil debug info Fixes #4664 --- src/llvm_backend_debug.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/llvm_backend_debug.cpp b/src/llvm_backend_debug.cpp index 3951fc977..6740cd1a2 100644 --- a/src/llvm_backend_debug.cpp +++ b/src/llvm_backend_debug.cpp @@ -438,8 +438,13 @@ gb_internal LLVMMetadataRef lb_debug_union(lbModule *m, Type *type, String name, for_array(j, bt->Union.variants) { Type *variant = bt->Union.variants[j]; + ptrdiff_t variant_index = j; + if (bt->Union.kind == UnionType_no_nil) { + variant_index += 1; + } + char name[32] = {}; - gb_snprintf(name, gb_size_of(name), "v%td", j); + gb_snprintf(name, gb_size_of(name), "v%td", variant_index); isize name_len = gb_strlen(name); elements[index_offset+j] = LLVMDIBuilderCreateMemberType( From b3c359557e7c3a1a298ac5b46af122415e43bf77 Mon Sep 17 00:00:00 2001 From: Laytan Laats Date: Wed, 8 Jan 2025 21:24:22 +0100 Subject: [PATCH 11/14] `#no_nil` third time's the charm --- src/llvm_backend_debug.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/llvm_backend_debug.cpp b/src/llvm_backend_debug.cpp index 6740cd1a2..2252c4a31 100644 --- a/src/llvm_backend_debug.cpp +++ b/src/llvm_backend_debug.cpp @@ -439,7 +439,7 @@ gb_internal LLVMMetadataRef lb_debug_union(lbModule *m, Type *type, String name, Type *variant = bt->Union.variants[j]; ptrdiff_t variant_index = j; - if (bt->Union.kind == UnionType_no_nil) { + if (bt->Union.kind != UnionType_no_nil) { variant_index += 1; } From 2620721128b2835826faa5d224bf9373a92b1998 Mon Sep 17 00:00:00 2001 From: Laytan Laats Date: Wed, 8 Jan 2025 21:45:59 +0100 Subject: [PATCH 12/14] '#no_nil' I am actually disappointed in myself --- src/llvm_backend_debug.cpp | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/src/llvm_backend_debug.cpp b/src/llvm_backend_debug.cpp index 2252c4a31..fbb25960a 100644 --- a/src/llvm_backend_debug.cpp +++ b/src/llvm_backend_debug.cpp @@ -408,8 +408,12 @@ gb_internal LLVMMetadataRef lb_debug_union(lbModule *m, Type *type, String name, lb_set_llvm_metadata(m, type, temp_forward_decl); isize index_offset = 1; + isize variant_offset = 1; if (is_type_union_maybe_pointer(bt)) { index_offset = 0; + variant_offset = 0; + } else if (bt->Union.kind == UnionType_no_nil) { + variant_offset = 0; } LLVMMetadataRef member_scope = lb_get_llvm_metadata(m, bt->Union.scope); @@ -438,13 +442,8 @@ gb_internal LLVMMetadataRef lb_debug_union(lbModule *m, Type *type, String name, for_array(j, bt->Union.variants) { Type *variant = bt->Union.variants[j]; - ptrdiff_t variant_index = j; - if (bt->Union.kind != UnionType_no_nil) { - variant_index += 1; - } - char name[32] = {}; - gb_snprintf(name, gb_size_of(name), "v%td", variant_index); + gb_snprintf(name, gb_size_of(name), "v%td", variant_offset+j); isize name_len = gb_strlen(name); elements[index_offset+j] = LLVMDIBuilderCreateMemberType( From 16e3abfe82912c1ef47008261020715d425b0dfb Mon Sep 17 00:00:00 2001 From: Laytan Laats Date: Wed, 8 Jan 2025 22:20:43 +0100 Subject: [PATCH 13/14] strings: use map_entry --- core/strings/intern.odin | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/core/strings/intern.odin b/core/strings/intern.odin index 4c270980c..0b8ed173e 100644 --- a/core/strings/intern.odin +++ b/core/strings/intern.odin @@ -89,6 +89,7 @@ intern_get_cstring :: proc(m: ^Intern, text: string) -> (str: cstring, err: runt entry := _intern_get_entry(m, text) or_return return cstring(&entry.str[0]), nil } + /* Internal function to lookup whether the text string exists in the map, returns the entry Sets and allocates the entry if it wasn't set yet @@ -104,13 +105,15 @@ Returns: - err: An allocator error if one occured, `nil` otherwise */ _intern_get_entry :: proc(m: ^Intern, text: string) -> (new_entry: ^Intern_Entry, err: runtime.Allocator_Error) #no_bounds_check { - if prev, ok := m.entries[text]; ok { - return prev, nil - } if m.allocator.procedure == nil { m.allocator = context.allocator } + key_ptr, val_ptr, inserted := map_entry(&m.entries, text) or_return + if !inserted { + return val_ptr^, nil + } + entry_size := int(offset_of(Intern_Entry, str)) + len(text) + 1 bytes := runtime.mem_alloc(entry_size, align_of(Intern_Entry), m.allocator) or_return new_entry = (^Intern_Entry)(raw_data(bytes)) @@ -120,6 +123,9 @@ _intern_get_entry :: proc(m: ^Intern, text: string) -> (new_entry: ^Intern_Entry new_entry.str[new_entry.len] = 0 key := string(new_entry.str[:new_entry.len]) - m.entries[key] = new_entry - return new_entry, nil + + key_ptr^ = key + val_ptr^ = new_entry + + return } From 1511162b0a6c18c8e45f87299fee8cca82711f99 Mon Sep 17 00:00:00 2001 From: Laytan Laats Date: Thu, 9 Jan 2025 17:29:31 +0100 Subject: [PATCH 14/14] webgpu: fix cstring as parameter not loading correctly --- core/sys/wasm/js/odin.js | 5 ++++- vendor/wgpu/wgpu.js | 24 ++++++++++++------------ 2 files changed, 16 insertions(+), 13 deletions(-) diff --git a/core/sys/wasm/js/odin.js b/core/sys/wasm/js/odin.js index 07a77952c..29227c526 100644 --- a/core/sys/wasm/js/odin.js +++ b/core/sys/wasm/js/odin.js @@ -110,7 +110,10 @@ class WasmMemoryInterface { } loadCstring(ptr) { - const start = this.loadPtr(ptr); + return this.loadCstringDirect(this.loadPtr(ptr)); + } + + loadCstringDirect(start) { if (start == 0) { return null; } diff --git a/vendor/wgpu/wgpu.js b/vendor/wgpu/wgpu.js index 9c43756d7..5e0482b69 100644 --- a/vendor/wgpu/wgpu.js +++ b/vendor/wgpu/wgpu.js @@ -1181,7 +1181,7 @@ class WebGPUInterface { */ wgpuBufferSetLabel: (bufferIdx, labelPtr) => { const buffer = this.buffers.get(bufferIdx); - buffer.buffer.label = this.mem.loadCstring(labelPtr); + buffer.buffer.label = this.mem.loadCstringDirect(labelPtr); }, /** @@ -1370,7 +1370,7 @@ class WebGPUInterface { */ wgpuCommandEncoderInsertDebugMarker: (commandEncoderIdx, markerLabelPtr) => { const commandEncoder = this.commandEncoders.get(commandEncoderIdx); - commandEncoder.insertDebugMarker(this.mem.loadCstring(markerLabelPtr)); + commandEncoder.insertDebugMarker(this.mem.loadCstringDirect(markerLabelPtr)); }, /** @@ -1387,7 +1387,7 @@ class WebGPUInterface { */ wgpuCommandEncoderPushDebugGroup: (commandEncoderIdx, groupLabelPtr) => { const commandEncoder = this.commandEncoders.get(commandEncoderIdx); - commandEncoder.pushDebugGroup(this.mem.loadCstring(groupLabelPtr)); + commandEncoder.pushDebugGroup(this.mem.loadCstringDirect(groupLabelPtr)); }, /** @@ -1459,7 +1459,7 @@ class WebGPUInterface { */ wgpuComputePassEncoderInsertDebugMarker: (computePassEncoderIdx, markerLabelPtr) => { const computePassEncoder = this.computePassEncoders.get(computePassEncoderIdx); - computePassEncoder.insertDebugMarker(this.mem.loadCstring(markerLabelPtr)); + computePassEncoder.insertDebugMarker(this.mem.loadCstringDirect(markerLabelPtr)); }, /** @@ -1476,7 +1476,7 @@ class WebGPUInterface { */ wgpuComputePassEncoderPushDebugGroup: (computePassEncoderIdx, groupLabelPtr) => { const computePassEncoder = this.computePassEncoders.get(computePassEncoderIdx); - computePassEncoder.pushDebugGroup(this.mem.loadCstring(groupLabelPtr)); + computePassEncoder.pushDebugGroup(this.mem.loadCstringDirect(groupLabelPtr)); }, /** @@ -2216,7 +2216,7 @@ class WebGPUInterface { wgpuRenderBundleEncoderInsertDebugMarker: (renderBundleEncoderIdx, markerLabelPtr) => { const renderBundleEncoder = this.renderBundleEncoders.get(renderBundleEncoderIdx); this.assert(markerLabelPtr != 0); - const markerLabel = this.mem.loadCstring(markerLabelPtr); + const markerLabel = this.mem.loadCstringDirect(markerLabelPtr); renderBundleEncoder.insertDebugMarker(markerLabel); }, @@ -2235,7 +2235,7 @@ class WebGPUInterface { wgpuRenderBundleEncoderPushDebugGroup: (renderBundleEncoderIdx, groupLabelPtr) => { const renderBundleEncoder = this.renderBundleEncoders.get(renderBundleEncoderIdx); this.assert(groupLabelPtr!= 0); - const groupLabel = this.mem.loadCstring(groupLabelPtr); + const groupLabel = this.mem.loadCstringDirect(groupLabelPtr); renderBundleEncoder.pushDebugGroup(groupLabel); }, @@ -2407,7 +2407,7 @@ class WebGPUInterface { */ wgpuRenderPassEncoderInsertDebugMarker: (renderPassEncoderIdx, markerLabelPtr) => { const renderPassEncoder = this.renderPassEncoders.get(renderPassEncoderIdx); - const markerLabel = this.mem.loadCstring(markerLabelPtr); + const markerLabel = this.mem.loadCstringDirect(markerLabelPtr); renderPassEncoder.insertDebugMarker(markerLabel); }, @@ -2425,7 +2425,7 @@ class WebGPUInterface { */ wgpuRenderPassEncoderPushDebugGroup: (renderPassEncoderIdx, groupLabelPtr) => { const renderPassEncoder = this.renderPassEncoders.get(renderPassEncoderIdx); - const groupLabel = this.mem.loadCstring(groupLabelPtr); + const groupLabel = this.mem.loadCstringDirect(groupLabelPtr); renderPassEncoder.pushDebugGroup(groupLabel); }, @@ -2881,11 +2881,11 @@ class WebGPUObjectManager { } /** - * @param {number} idx + * @param {?number} idx * @returns {T} */ get(idx) { - return this.objects[idx-1].object; + return this.objects[idx-1]?.object; } /** @param {number} idx */ @@ -2908,7 +2908,7 @@ class WebGPUObjectManager { if (withLabelSetter) { inter[`wgpu${this.name}SetLabel`] = (idx, labelPtr) => { const obj = this.get(idx); - obj.label = this.mem.loadCstring(labelPtr); + obj.label = this.mem.loadCstringDirect(labelPtr); }; } return inter;