mirror of
https://github.com/odin-lang/Odin.git
synced 2026-04-19 13:00:28 +00:00
Merge branch 'master' of https://github.com/avanspector/Odin
This commit is contained in:
42
.github/workflows/ci.yml
vendored
42
.github/workflows/ci.yml
vendored
@@ -32,9 +32,9 @@ jobs:
|
||||
gmake -C vendor/miniaudio/src
|
||||
./odin check examples/all -vet -strict-style -disallow-do -target:netbsd_amd64
|
||||
./odin check examples/all -vet -strict-style -disallow-do -target:netbsd_arm64
|
||||
./odin test tests/core/normal.odin -file -all-packages -define:ODIN_TEST_FANCY=false -define:ODIN_TEST_FAIL_ON_BAD_MEMORY=true
|
||||
./odin test tests/core/speed.odin -file -all-packages -o:speed -define:ODIN_TEST_FANCY=false -define:ODIN_TEST_FAIL_ON_BAD_MEMORY=true
|
||||
./odin test tests/vendor -all-packages -define:ODIN_TEST_FANCY=false -define:ODIN_TEST_FAIL_ON_BAD_MEMORY=true
|
||||
./odin test tests/core/normal.odin -file -all-packages -vet -strict-style -disallow-do -define:ODIN_TEST_FANCY=false -define:ODIN_TEST_FAIL_ON_BAD_MEMORY=true
|
||||
./odin test tests/core/speed.odin -file -all-packages -vet -strict-style -disallow-do -o:speed -define:ODIN_TEST_FANCY=false -define:ODIN_TEST_FAIL_ON_BAD_MEMORY=true
|
||||
./odin test tests/vendor -all-packages -vet -strict-style -disallow-do -define:ODIN_TEST_FANCY=false -define:ODIN_TEST_FAIL_ON_BAD_MEMORY=true
|
||||
(cd tests/issues; ./run.sh)
|
||||
build_freebsd:
|
||||
name: FreeBSD Build, Check, and Test
|
||||
@@ -60,9 +60,9 @@ jobs:
|
||||
gmake -C vendor/cgltf/src
|
||||
gmake -C vendor/miniaudio/src
|
||||
./odin check examples/all -vet -strict-style -disallow-do -target:freebsd_amd64
|
||||
./odin test tests/core/normal.odin -file -all-packages -define:ODIN_TEST_FANCY=false -define:ODIN_TEST_FAIL_ON_BAD_MEMORY=true
|
||||
./odin test tests/core/speed.odin -file -all-packages -o:speed -define:ODIN_TEST_FANCY=false -define:ODIN_TEST_FAIL_ON_BAD_MEMORY=true
|
||||
./odin test tests/vendor -all-packages -define:ODIN_TEST_FANCY=false -define:ODIN_TEST_FAIL_ON_BAD_MEMORY=true
|
||||
./odin test tests/core/normal.odin -file -all-packages -vet -strict-style -disallow-do -define:ODIN_TEST_FANCY=false -define:ODIN_TEST_FAIL_ON_BAD_MEMORY=true
|
||||
./odin test tests/core/speed.odin -file -all-packages -vet -strict-style -disallow-do -o:speed -define:ODIN_TEST_FANCY=false -define:ODIN_TEST_FAIL_ON_BAD_MEMORY=true
|
||||
./odin test tests/vendor -all-packages -vet -strict-style -disallow-do -define:ODIN_TEST_FANCY=false -define:ODIN_TEST_FAIL_ON_BAD_MEMORY=true
|
||||
(cd tests/issues; ./run.sh)
|
||||
ci:
|
||||
strategy:
|
||||
@@ -116,13 +116,13 @@ jobs:
|
||||
- name: Odin check examples/all
|
||||
run: ./odin check examples/all -strict-style
|
||||
- name: Normal Core library tests
|
||||
run: ./odin test tests/core/normal.odin -file -all-packages -define:ODIN_TEST_FANCY=false -define:ODIN_TEST_FAIL_ON_BAD_MEMORY=true
|
||||
run: ./odin test tests/core/normal.odin -file -all-packages -vet -strict-style -disallow-do -define:ODIN_TEST_FANCY=false -define:ODIN_TEST_FAIL_ON_BAD_MEMORY=true
|
||||
- name: Optimized Core library tests
|
||||
run: ./odin test tests/core/speed.odin -o:speed -file -all-packages -define:ODIN_TEST_FANCY=false -define:ODIN_TEST_FAIL_ON_BAD_MEMORY=true
|
||||
run: ./odin test tests/core/speed.odin -o:speed -file -all-packages -vet -strict-style -disallow-do -define:ODIN_TEST_FANCY=false -define:ODIN_TEST_FAIL_ON_BAD_MEMORY=true
|
||||
- name: Vendor library tests
|
||||
run: ./odin test tests/vendor -all-packages -define:ODIN_TEST_FANCY=false -define:ODIN_TEST_FAIL_ON_BAD_MEMORY=true
|
||||
run: ./odin test tests/vendor -all-packages -vet -strict-style -disallow-do -define:ODIN_TEST_FANCY=false -define:ODIN_TEST_FAIL_ON_BAD_MEMORY=true
|
||||
- name: Internals tests
|
||||
run: ./odin test tests/internal -all-packages -define:ODIN_TEST_FANCY=false -define:ODIN_TEST_FAIL_ON_BAD_MEMORY=true
|
||||
run: ./odin test tests/internal -all-packages -vet -strict-style -disallow-do -define:ODIN_TEST_FANCY=false -define:ODIN_TEST_FAIL_ON_BAD_MEMORY=true
|
||||
- name: GitHub Issue tests
|
||||
run: |
|
||||
cd tests/issues
|
||||
@@ -176,33 +176,33 @@ jobs:
|
||||
shell: cmd
|
||||
run: |
|
||||
call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvars64.bat
|
||||
odin run examples/demo -debug
|
||||
odin run examples/demo -debug -vet -strict-style -disallow-do
|
||||
- name: Odin check examples/all
|
||||
shell: cmd
|
||||
run: |
|
||||
call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvars64.bat
|
||||
odin check examples/all -strict-style
|
||||
odin check examples/all -vet -strict-style -disallow-do
|
||||
- name: Core library tests
|
||||
shell: cmd
|
||||
run: |
|
||||
call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvars64.bat
|
||||
odin test tests/core/normal.odin -file -all-packages -define:ODIN_TEST_FANCY=false -define:ODIN_TEST_FAIL_ON_BAD_MEMORY=true
|
||||
odin test tests/core/normal.odin -file -all-packages -vet -strict-style -disallow-do -define:ODIN_TEST_FANCY=false -define:ODIN_TEST_FAIL_ON_BAD_MEMORY=true
|
||||
- name: Optimized core library tests
|
||||
shell: cmd
|
||||
run: |
|
||||
call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvars64.bat
|
||||
odin test tests/core/speed.odin -o:speed -file -all-packages -define:ODIN_TEST_FANCY=false -define:ODIN_TEST_FAIL_ON_BAD_MEMORY=true
|
||||
odin test tests/core/speed.odin -o:speed -file -all-packages -vet -strict-style -disallow-do -define:ODIN_TEST_FANCY=false -define:ODIN_TEST_FAIL_ON_BAD_MEMORY=true
|
||||
- name: Vendor library tests
|
||||
shell: cmd
|
||||
run: |
|
||||
call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvars64.bat
|
||||
copy vendor\lua\5.4\windows\*.dll .
|
||||
odin test tests/vendor -all-packages -define:ODIN_TEST_FANCY=false -define:ODIN_TEST_FAIL_ON_BAD_MEMORY=true
|
||||
odin test tests/vendor -all-packages -vet -strict-style -disallow-do -define:ODIN_TEST_FANCY=false -define:ODIN_TEST_FAIL_ON_BAD_MEMORY=true
|
||||
- name: Odin internals tests
|
||||
shell: cmd
|
||||
run: |
|
||||
call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvars64.bat
|
||||
odin test tests/internal -all-packages -define:ODIN_TEST_FANCY=false -define:ODIN_TEST_FAIL_ON_BAD_MEMORY=true
|
||||
odin test tests/internal -all-packages -vet -strict-style -disallow-do -define:ODIN_TEST_FANCY=false -define:ODIN_TEST_FAIL_ON_BAD_MEMORY=true
|
||||
- name: Odin documentation tests
|
||||
shell: cmd
|
||||
run: |
|
||||
@@ -257,16 +257,16 @@ jobs:
|
||||
run: sudo apt-get install -y qemu-user qemu-user-static gcc-12-riscv64-linux-gnu libc6-riscv64-cross
|
||||
|
||||
- name: Odin run
|
||||
run: ./odin run examples/demo -target:linux_riscv64 -extra-linker-flags:"-fuse-ld=/usr/bin/riscv64-linux-gnu-gcc-12 -static -Wl,-static"
|
||||
run: ./odin run examples/demo -vet -strict-style -disallow-do -target:linux_riscv64 -extra-linker-flags:"-fuse-ld=/usr/bin/riscv64-linux-gnu-gcc-12 -static -Wl,-static"
|
||||
|
||||
- name: Odin run -debug
|
||||
run: ./odin run examples/demo -debug -target:linux_riscv64 -extra-linker-flags:"-fuse-ld=/usr/bin/riscv64-linux-gnu-gcc-12 -static -Wl,-static"
|
||||
run: ./odin run examples/demo -debug -vet -strict-style -disallow-do -target:linux_riscv64 -extra-linker-flags:"-fuse-ld=/usr/bin/riscv64-linux-gnu-gcc-12 -static -Wl,-static"
|
||||
|
||||
- name: Normal Core library tests
|
||||
run: ./odin test tests/core/normal.odin -file -all-packages -define:ODIN_TEST_FANCY=false -define:ODIN_TEST_FAIL_ON_BAD_MEMORY=true -target:linux_riscv64 -extra-linker-flags:"-fuse-ld=/usr/bin/riscv64-linux-gnu-gcc-12 -static -Wl,-static"
|
||||
run: ./odin test tests/core/normal.odin -file -all-packages -vet -strict-style -disallow-do -define:ODIN_TEST_FANCY=false -define:ODIN_TEST_FAIL_ON_BAD_MEMORY=true -target:linux_riscv64 -extra-linker-flags:"-fuse-ld=/usr/bin/riscv64-linux-gnu-gcc-12 -static -Wl,-static"
|
||||
|
||||
- name: Optimized Core library tests
|
||||
run: ./odin test tests/core/speed.odin -o:speed -file -all-packages -define:ODIN_TEST_FANCY=false -define:ODIN_TEST_FAIL_ON_BAD_MEMORY=true -target:linux_riscv64 -extra-linker-flags:"-fuse-ld=/usr/bin/riscv64-linux-gnu-gcc-12 -static -Wl,-static"
|
||||
run: ./odin test tests/core/speed.odin -o:speed -file -all-packages -vet -strict-style -disallow-do -define:ODIN_TEST_FANCY=false -define:ODIN_TEST_FAIL_ON_BAD_MEMORY=true -target:linux_riscv64 -extra-linker-flags:"-fuse-ld=/usr/bin/riscv64-linux-gnu-gcc-12 -static -Wl,-static"
|
||||
|
||||
- name: Internals tests
|
||||
run: ./odin test tests/internal -all-packages -define:ODIN_TEST_FANCY=false -define:ODIN_TEST_FAIL_ON_BAD_MEMORY=true -target:linux_riscv64 -extra-linker-flags:"-fuse-ld=/usr/bin/riscv64-linux-gnu-gcc-12 -static -Wl,-static"
|
||||
run: ./odin test tests/internal -all-packages -vet -strict-style -disallow-do -define:ODIN_TEST_FANCY=false -define:ODIN_TEST_FAIL_ON_BAD_MEMORY=true -target:linux_riscv64 -extra-linker-flags:"-fuse-ld=/usr/bin/riscv64-linux-gnu-gcc-12 -static -Wl,-static"
|
||||
|
||||
34
base/runtime/thread_management.odin
Normal file
34
base/runtime/thread_management.odin
Normal file
@@ -0,0 +1,34 @@
|
||||
package runtime
|
||||
|
||||
Thread_Local_Cleaner :: #type proc "odin" ()
|
||||
|
||||
@(private="file")
|
||||
thread_local_cleaners: [8]Thread_Local_Cleaner
|
||||
|
||||
// Add a procedure that will be run at the end of a thread for the purpose of
|
||||
// deallocating state marked as `thread_local`.
|
||||
//
|
||||
// Intended to be called in an `init` procedure of a package with
|
||||
// dynamically-allocated memory that is stored in `thread_local` variables.
|
||||
add_thread_local_cleaner :: proc "contextless" (p: Thread_Local_Cleaner) {
|
||||
for &v in thread_local_cleaners {
|
||||
if v == nil {
|
||||
v = p
|
||||
return
|
||||
}
|
||||
}
|
||||
panic_contextless("There are no more thread-local cleaner slots available.")
|
||||
}
|
||||
|
||||
// Run all of the thread-local cleaner procedures.
|
||||
//
|
||||
// Intended to be called by the internals of a threading API at the end of a
|
||||
// thread's lifetime.
|
||||
run_thread_local_cleaners :: proc "odin" () {
|
||||
for p in thread_local_cleaners {
|
||||
if p == nil {
|
||||
break
|
||||
}
|
||||
p()
|
||||
}
|
||||
}
|
||||
@@ -178,11 +178,11 @@ make_dynamic_array :: proc($T: typeid/[dynamic]$E, allocator := context.allocato
|
||||
}
|
||||
@(require_results)
|
||||
make_dynamic_array_len :: proc($T: typeid/[dynamic]$E, #any_int len: int, allocator := context.allocator, loc := #caller_location) -> (T, Allocator_Error) {
|
||||
return runtime.make_dynamic_array(T, len, allocator, loc)
|
||||
return runtime.make_dynamic_array_len_cap(T, len, len, allocator, loc)
|
||||
}
|
||||
@(require_results)
|
||||
make_dynamic_array_len_cap :: proc($T: typeid/[dynamic]$E, #any_int len: int, #any_int cap: int, allocator := context.allocator, loc := #caller_location) -> (array: T, err: Allocator_Error) {
|
||||
return runtime.make_dynamic_array(T, len, cap, allocator, loc)
|
||||
return runtime.make_dynamic_array_len_cap(T, len, cap, allocator, loc)
|
||||
}
|
||||
@(require_results)
|
||||
make_map :: proc($T: typeid/map[$K]$E, #any_int cap: int = 1<<runtime.MAP_MIN_LOG2_CAPACITY, allocator := context.allocator, loc := #caller_location) -> (m: T, err: Allocator_Error) {
|
||||
|
||||
@@ -49,6 +49,10 @@ arena_init_growing :: proc(arena: ^Arena, reserved: uint = DEFAULT_ARENA_GROWING
|
||||
arena.curr_block = memory_block_alloc(0, reserved, {}) or_return
|
||||
arena.total_used = 0
|
||||
arena.total_reserved = arena.curr_block.reserved
|
||||
|
||||
if arena.minimum_block_size == 0 {
|
||||
arena.minimum_block_size = reserved
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
@@ -7,6 +7,11 @@ _ :: runtime
|
||||
|
||||
DEFAULT_PAGE_SIZE := uint(4096)
|
||||
|
||||
@(init, private)
|
||||
platform_memory_init :: proc() {
|
||||
_platform_memory_init()
|
||||
}
|
||||
|
||||
Allocator_Error :: mem.Allocator_Error
|
||||
|
||||
@(require_results)
|
||||
|
||||
@@ -51,8 +51,10 @@ _protect :: proc "contextless" (data: rawptr, size: uint, flags: Protect_Flags)
|
||||
}
|
||||
|
||||
_platform_memory_init :: proc() {
|
||||
DEFAULT_PAGE_SIZE = posix.PAGE_SIZE
|
||||
|
||||
// NOTE: `posix.PAGESIZE` due to legacy reasons could be wrong so we use `sysconf`.
|
||||
size := posix.sysconf(._PAGESIZE)
|
||||
DEFAULT_PAGE_SIZE = uint(max(size, posix.PAGESIZE))
|
||||
|
||||
// is power of two
|
||||
assert(DEFAULT_PAGE_SIZE != 0 && (DEFAULT_PAGE_SIZE & (DEFAULT_PAGE_SIZE-1)) == 0)
|
||||
}
|
||||
|
||||
@@ -61,3 +61,8 @@ TEMP_ALLOCATOR_GUARD :: #force_inline proc(loc := #caller_location) -> (runtime.
|
||||
global_default_temp_allocator_index = (global_default_temp_allocator_index+1)%MAX_TEMP_ARENA_COUNT
|
||||
return tmp, loc
|
||||
}
|
||||
|
||||
@(init, private)
|
||||
init_thread_local_cleaner :: proc() {
|
||||
runtime.add_thread_local_cleaner(temp_allocator_fini)
|
||||
}
|
||||
|
||||
@@ -1,10 +1,17 @@
|
||||
//+private
|
||||
package os2
|
||||
|
||||
import "base:runtime"
|
||||
|
||||
import "core:sys/linux"
|
||||
import "core:sync"
|
||||
import "core:mem"
|
||||
|
||||
// Use the experimental custom heap allocator (over calling `malloc` etc.).
|
||||
// This is a switch because there are thread-safety problems that need to be fixed.
|
||||
// See: https://github.com/odin-lang/Odin/issues/4161
|
||||
USE_EXPERIMENTAL_ALLOCATOR :: #config(OS2_LINUX_USE_EXPERIMENTAL_ALLOCATOR, false)
|
||||
|
||||
// NOTEs
|
||||
//
|
||||
// All allocations below DIRECT_MMAP_THRESHOLD exist inside of memory "Regions." A region
|
||||
@@ -139,6 +146,8 @@ Region :: struct {
|
||||
memory: [BLOCKS_PER_REGION]Allocation_Header,
|
||||
}
|
||||
|
||||
when USE_EXPERIMENTAL_ALLOCATOR {
|
||||
|
||||
_heap_allocator_proc :: proc(allocator_data: rawptr, mode: mem.Allocator_Mode,
|
||||
size, alignment: int,
|
||||
old_memory: rawptr, old_size: int, loc := #caller_location) -> ([]byte, mem.Allocator_Error) {
|
||||
@@ -219,6 +228,10 @@ _heap_allocator_proc :: proc(allocator_data: rawptr, mode: mem.Allocator_Mode,
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
} else {
|
||||
_heap_allocator_proc :: runtime.heap_allocator_proc
|
||||
}
|
||||
|
||||
heap_alloc :: proc(size: int) -> rawptr {
|
||||
if size >= DIRECT_MMAP_THRESHOLD {
|
||||
return _direct_mmap_alloc(size)
|
||||
|
||||
@@ -166,15 +166,15 @@ Process_Info :: struct {
|
||||
|
||||
This procedure obtains an information, specified by `selection` parameter of
|
||||
a process given by `pid`.
|
||||
|
||||
Use `free_process_info` to free the memory allocated by this procedure. In
|
||||
case the function returns an error it may only have been an error for one part
|
||||
of the information and you would still need to call it to free the other parts.
|
||||
|
||||
Use `free_process_info` to free the memory allocated by this procedure. The
|
||||
`free_process_info` procedure needs to be called, even if this procedure
|
||||
returned an error, as some of the fields may have been allocated.
|
||||
|
||||
**Note**: The resulting information may or may contain the fields specified
|
||||
by the `selection` parameter. Always check whether the returned
|
||||
`Process_Info` struct has the required fields before checking the error code
|
||||
returned by this function.
|
||||
returned by this procedure.
|
||||
*/
|
||||
@(require_results)
|
||||
process_info_by_pid :: proc(pid: int, selection: Process_Info_Fields, allocator: runtime.Allocator) -> (Process_Info, Error) {
|
||||
@@ -188,14 +188,14 @@ process_info_by_pid :: proc(pid: int, selection: Process_Info_Fields, allocator:
|
||||
about a process that has been opened by the application, specified in
|
||||
the `process` parameter.
|
||||
|
||||
Use `free_process_info` to free the memory allocated by this procedure. In
|
||||
case the function returns an error it may only have been an error for one part
|
||||
of the information and you would still need to call it to free the other parts.
|
||||
Use `free_process_info` to free the memory allocated by this procedure. The
|
||||
`free_process_info` procedure needs to be called, even if this procedure
|
||||
returned an error, as some of the fields may have been allocated.
|
||||
|
||||
**Note**: The resulting information may or may contain the fields specified
|
||||
by the `selection` parameter. Always check whether the returned
|
||||
`Process_Info` struct has the required fields before checking the error code
|
||||
returned by this function.
|
||||
returned by this procedure.
|
||||
*/
|
||||
@(require_results)
|
||||
process_info_by_handle :: proc(process: Process, selection: Process_Info_Fields, allocator: runtime.Allocator) -> (Process_Info, Error) {
|
||||
@@ -208,14 +208,14 @@ process_info_by_handle :: proc(process: Process, selection: Process_Info_Fields,
|
||||
This procedure obtains the information, specified by `selection` parameter
|
||||
about the currently running process.
|
||||
|
||||
Use `free_process_info` to free the memory allocated by this procedure. In
|
||||
case the function returns an error it may only have been an error for one part
|
||||
of the information and you would still need to call it to free the other parts.
|
||||
Use `free_process_info` to free the memory allocated by this procedure. The
|
||||
`free_process_info` procedure needs to be called, even if this procedure
|
||||
returned an error, as some of the fields may have been allocated.
|
||||
|
||||
**Note**: The resulting information may or may contain the fields specified
|
||||
by the `selection` parameter. Always check whether the returned
|
||||
`Process_Info` struct has the required fields before checking the error code
|
||||
returned by this function.
|
||||
returned by this procedure.
|
||||
*/
|
||||
@(require_results)
|
||||
current_process_info :: proc(selection: Process_Info_Fields, allocator: runtime.Allocator) -> (Process_Info, Error) {
|
||||
|
||||
@@ -93,34 +93,11 @@ read_memory_as_slice :: proc(h: win32.HANDLE, addr: rawptr, dest: []$T) -> (byte
|
||||
@(private="package")
|
||||
_process_info_by_pid :: proc(pid: int, selection: Process_Info_Fields, allocator: runtime.Allocator) -> (info: Process_Info, err: Error) {
|
||||
info.pid = pid
|
||||
defer if err != nil {
|
||||
free_process_info(info, allocator)
|
||||
}
|
||||
|
||||
// Data obtained from process snapshots
|
||||
if selection >= {.PPid, .Priority} {
|
||||
entry, entry_err := _process_entry_by_pid(info.pid)
|
||||
if entry_err != nil {
|
||||
err = General_Error.Not_Exist
|
||||
return
|
||||
}
|
||||
if .PPid in selection {
|
||||
info.fields += {.PPid}
|
||||
info.ppid = int(entry.th32ParentProcessID)
|
||||
}
|
||||
if .Priority in selection {
|
||||
info.fields += {.Priority}
|
||||
info.priority = int(entry.pcPriClassBase)
|
||||
}
|
||||
}
|
||||
if .Executable_Path in selection { // snap module
|
||||
info.executable_path = _process_exe_by_pid(pid, allocator) or_return
|
||||
info.fields += {.Executable_Path}
|
||||
}
|
||||
|
||||
// Note(flysand): Open the process handle right away to prevent some race
|
||||
// conditions. Once the handle is open, the process will be kept alive by
|
||||
// the OS.
|
||||
ph := win32.INVALID_HANDLE_VALUE
|
||||
|
||||
if selection >= {.Command_Line, .Environment, .Working_Dir, .Username} { // need process handle
|
||||
if selection >= {.Command_Line, .Environment, .Working_Dir, .Username} {
|
||||
ph = win32.OpenProcess(
|
||||
win32.PROCESS_QUERY_LIMITED_INFORMATION | win32.PROCESS_VM_READ,
|
||||
false,
|
||||
@@ -134,84 +111,15 @@ _process_info_by_pid :: proc(pid: int, selection: Process_Info_Fields, allocator
|
||||
defer if ph != win32.INVALID_HANDLE_VALUE {
|
||||
win32.CloseHandle(ph)
|
||||
}
|
||||
|
||||
if selection >= {.Command_Line, .Environment, .Working_Dir} { // need peb
|
||||
process_info_size: u32
|
||||
process_info: win32.PROCESS_BASIC_INFORMATION
|
||||
status := win32.NtQueryInformationProcess(ph, .ProcessBasicInformation, &process_info, size_of(process_info), &process_info_size)
|
||||
if status != 0 {
|
||||
// TODO(flysand): There's probably a mismatch between NTSTATUS and
|
||||
// windows userland error codes, I haven't checked.
|
||||
err = Platform_Error(status)
|
||||
return
|
||||
}
|
||||
if process_info.PebBaseAddress == nil {
|
||||
// Not sure what the error is
|
||||
err = General_Error.Unsupported
|
||||
return
|
||||
}
|
||||
process_peb: win32.PEB
|
||||
|
||||
_ = read_memory_as_struct(ph, process_info.PebBaseAddress, &process_peb) or_return
|
||||
|
||||
process_params: win32.RTL_USER_PROCESS_PARAMETERS
|
||||
_ = read_memory_as_struct(ph, process_peb.ProcessParameters, &process_params) or_return
|
||||
|
||||
if selection >= {.Command_Line, .Command_Args} {
|
||||
TEMP_ALLOCATOR_GUARD()
|
||||
cmdline_w := make([]u16, process_params.CommandLine.Length, temp_allocator()) or_return
|
||||
_ = read_memory_as_slice(ph, process_params.CommandLine.Buffer, cmdline_w) or_return
|
||||
|
||||
if .Command_Line in selection {
|
||||
info.command_line = win32_utf16_to_utf8(cmdline_w, allocator) or_return
|
||||
info.fields += {.Command_Line}
|
||||
}
|
||||
if .Command_Args in selection {
|
||||
info.command_args = _parse_command_line(raw_data(cmdline_w), allocator) or_return
|
||||
info.fields += {.Command_Args}
|
||||
}
|
||||
}
|
||||
if .Environment in selection {
|
||||
TEMP_ALLOCATOR_GUARD()
|
||||
env_len := process_params.EnvironmentSize / 2
|
||||
envs_w := make([]u16, env_len, temp_allocator()) or_return
|
||||
_ = read_memory_as_slice(ph, process_params.Environment, envs_w) or_return
|
||||
|
||||
info.environment = _parse_environment_block(raw_data(envs_w), allocator) or_return
|
||||
info.fields += {.Environment}
|
||||
}
|
||||
if .Working_Dir in selection {
|
||||
TEMP_ALLOCATOR_GUARD()
|
||||
cwd_w := make([]u16, process_params.CurrentDirectoryPath.Length, temp_allocator()) or_return
|
||||
_ = read_memory_as_slice(ph, process_params.CurrentDirectoryPath.Buffer, cwd_w) or_return
|
||||
|
||||
info.working_dir = win32_utf16_to_utf8(cwd_w, allocator) or_return
|
||||
info.fields += {.Working_Dir}
|
||||
}
|
||||
}
|
||||
|
||||
if .Username in selection {
|
||||
info.username = _get_process_user(ph, allocator) or_return
|
||||
info.fields += {.Username}
|
||||
}
|
||||
err = nil
|
||||
return
|
||||
}
|
||||
|
||||
@(private="package")
|
||||
_process_info_by_handle :: proc(process: Process, selection: Process_Info_Fields, allocator: runtime.Allocator) -> (info: Process_Info, err: Error) {
|
||||
pid := process.pid
|
||||
info.pid = pid
|
||||
defer if err != nil {
|
||||
free_process_info(info, allocator)
|
||||
}
|
||||
|
||||
// Data obtained from process snapshots
|
||||
if selection >= {.PPid, .Priority} { // snap process
|
||||
snapshot_process: if selection >= {.PPid, .Priority} {
|
||||
entry, entry_err := _process_entry_by_pid(info.pid)
|
||||
if entry_err != nil {
|
||||
err = General_Error.Not_Exist
|
||||
return
|
||||
err = entry_err
|
||||
if entry_err == General_Error.Not_Exist {
|
||||
return
|
||||
} else {
|
||||
break snapshot_process
|
||||
}
|
||||
}
|
||||
if .PPid in selection {
|
||||
info.fields += {.PPid}
|
||||
@@ -222,12 +130,18 @@ _process_info_by_handle :: proc(process: Process, selection: Process_Info_Fields
|
||||
info.priority = int(entry.pcPriClassBase)
|
||||
}
|
||||
}
|
||||
if .Executable_Path in selection { // snap module
|
||||
info.executable_path = _process_exe_by_pid(pid, allocator) or_return
|
||||
snapshot_modules: if .Executable_Path in selection {
|
||||
exe_path: string
|
||||
exe_path, err = _process_exe_by_pid(pid, allocator)
|
||||
if _, ok := err.(runtime.Allocator_Error); ok {
|
||||
return
|
||||
} else if err != nil {
|
||||
break snapshot_modules
|
||||
}
|
||||
info.executable_path = exe_path
|
||||
info.fields += {.Executable_Path}
|
||||
}
|
||||
ph := win32.HANDLE(process.handle)
|
||||
if selection >= {.Command_Line, .Environment, .Working_Dir} { // need peb
|
||||
read_peb: if selection >= {.Command_Line, .Environment, .Working_Dir} {
|
||||
process_info_size: u32
|
||||
process_info: win32.PROCESS_BASIC_INFORMATION
|
||||
status := win32.NtQueryInformationProcess(ph, .ProcessBasicInformation, &process_info, size_of(process_info), &process_info_size)
|
||||
@@ -235,25 +149,26 @@ _process_info_by_handle :: proc(process: Process, selection: Process_Info_Fields
|
||||
// TODO(flysand): There's probably a mismatch between NTSTATUS and
|
||||
// windows userland error codes, I haven't checked.
|
||||
err = Platform_Error(status)
|
||||
return
|
||||
break read_peb
|
||||
}
|
||||
if process_info.PebBaseAddress == nil {
|
||||
// Not sure what the error is
|
||||
err = General_Error.Unsupported
|
||||
return
|
||||
}
|
||||
|
||||
assert(process_info.PebBaseAddress != nil)
|
||||
process_peb: win32.PEB
|
||||
_ = read_memory_as_struct(ph, process_info.PebBaseAddress, &process_peb) or_return
|
||||
|
||||
_, err = read_memory_as_struct(ph, process_info.PebBaseAddress, &process_peb)
|
||||
if err != nil {
|
||||
break read_peb
|
||||
}
|
||||
process_params: win32.RTL_USER_PROCESS_PARAMETERS
|
||||
_ = read_memory_as_struct(ph, process_peb.ProcessParameters, &process_params) or_return
|
||||
|
||||
_, err = read_memory_as_struct(ph, process_peb.ProcessParameters, &process_params)
|
||||
if err != nil {
|
||||
break read_peb
|
||||
}
|
||||
if selection >= {.Command_Line, .Command_Args} {
|
||||
TEMP_ALLOCATOR_GUARD()
|
||||
cmdline_w := make([]u16, process_params.CommandLine.Length, temp_allocator()) or_return
|
||||
_ = read_memory_as_slice(ph, process_params.CommandLine.Buffer, cmdline_w) or_return
|
||||
|
||||
_, err = read_memory_as_slice(ph, process_params.CommandLine.Buffer, cmdline_w)
|
||||
if err != nil {
|
||||
break read_peb
|
||||
}
|
||||
if .Command_Line in selection {
|
||||
info.command_line = win32_utf16_to_utf8(cmdline_w, allocator) or_return
|
||||
info.fields += {.Command_Line}
|
||||
@@ -263,28 +178,147 @@ _process_info_by_handle :: proc(process: Process, selection: Process_Info_Fields
|
||||
info.fields += {.Command_Args}
|
||||
}
|
||||
}
|
||||
|
||||
if .Environment in selection {
|
||||
TEMP_ALLOCATOR_GUARD()
|
||||
env_len := process_params.EnvironmentSize / 2
|
||||
envs_w := make([]u16, env_len, temp_allocator()) or_return
|
||||
_ = read_memory_as_slice(ph, process_params.Environment, envs_w) or_return
|
||||
|
||||
info.environment = _parse_environment_block(raw_data(envs_w), allocator) or_return
|
||||
_, err = read_memory_as_slice(ph, process_params.Environment, envs_w)
|
||||
if err != nil {
|
||||
break read_peb
|
||||
}
|
||||
info.environment = _parse_environment_block(raw_data(envs_w), allocator) or_return
|
||||
info.fields += {.Environment}
|
||||
}
|
||||
|
||||
if .Working_Dir in selection {
|
||||
TEMP_ALLOCATOR_GUARD()
|
||||
cwd_w := make([]u16, process_params.CurrentDirectoryPath.Length, temp_allocator()) or_return
|
||||
_ = read_memory_as_slice(ph, process_params.CurrentDirectoryPath.Buffer, cwd_w) or_return
|
||||
|
||||
_, err = read_memory_as_slice(ph, process_params.CurrentDirectoryPath.Buffer, cwd_w)
|
||||
if err != nil {
|
||||
break read_peb
|
||||
}
|
||||
info.working_dir = win32_utf16_to_utf8(cwd_w, allocator) or_return
|
||||
info.fields += {.Working_Dir}
|
||||
}
|
||||
}
|
||||
if .Username in selection {
|
||||
info.username = _get_process_user(ph, allocator) or_return
|
||||
read_username: if .Username in selection {
|
||||
username: string
|
||||
username, err = _get_process_user(ph, allocator)
|
||||
if _, ok := err.(runtime.Allocator_Error); ok {
|
||||
return
|
||||
} else if err != nil {
|
||||
break read_username
|
||||
}
|
||||
info.username = username
|
||||
info.fields += {.Username}
|
||||
}
|
||||
err = nil
|
||||
return
|
||||
}
|
||||
|
||||
@(private="package")
|
||||
_process_info_by_handle :: proc(process: Process, selection: Process_Info_Fields, allocator: runtime.Allocator) -> (info: Process_Info, err: Error) {
|
||||
pid := process.pid
|
||||
info.pid = pid
|
||||
// Data obtained from process snapshots
|
||||
snapshot_process: if selection >= {.PPid, .Priority} {
|
||||
entry, entry_err := _process_entry_by_pid(info.pid)
|
||||
if entry_err != nil {
|
||||
err = entry_err
|
||||
if entry_err == General_Error.Not_Exist {
|
||||
return
|
||||
} else {
|
||||
break snapshot_process
|
||||
}
|
||||
}
|
||||
if .PPid in selection {
|
||||
info.fields += {.PPid}
|
||||
info.ppid = int(entry.th32ParentProcessID)
|
||||
}
|
||||
if .Priority in selection {
|
||||
info.fields += {.Priority}
|
||||
info.priority = int(entry.pcPriClassBase)
|
||||
}
|
||||
}
|
||||
snapshot_module: if .Executable_Path in selection {
|
||||
exe_path: string
|
||||
exe_path, err = _process_exe_by_pid(pid, allocator)
|
||||
if _, ok := err.(runtime.Allocator_Error); ok {
|
||||
return
|
||||
} else if err != nil {
|
||||
break snapshot_module
|
||||
}
|
||||
info.executable_path = exe_path
|
||||
info.fields += {.Executable_Path}
|
||||
}
|
||||
ph := win32.HANDLE(process.handle)
|
||||
read_peb: if selection >= {.Command_Line, .Environment, .Working_Dir} {
|
||||
process_info_size: u32
|
||||
process_info: win32.PROCESS_BASIC_INFORMATION
|
||||
status := win32.NtQueryInformationProcess(ph, .ProcessBasicInformation, &process_info, size_of(process_info), &process_info_size)
|
||||
if status != 0 {
|
||||
// TODO(flysand): There's probably a mismatch between NTSTATUS and
|
||||
// windows userland error codes, I haven't checked.
|
||||
err = Platform_Error(status)
|
||||
return
|
||||
}
|
||||
assert(process_info.PebBaseAddress != nil)
|
||||
process_peb: win32.PEB
|
||||
_, err = read_memory_as_struct(ph, process_info.PebBaseAddress, &process_peb)
|
||||
if err != nil {
|
||||
break read_peb
|
||||
}
|
||||
process_params: win32.RTL_USER_PROCESS_PARAMETERS
|
||||
_, err = read_memory_as_struct(ph, process_peb.ProcessParameters, &process_params)
|
||||
if err != nil {
|
||||
break read_peb
|
||||
}
|
||||
if selection >= {.Command_Line, .Command_Args} {
|
||||
TEMP_ALLOCATOR_GUARD()
|
||||
cmdline_w := make([]u16, process_params.CommandLine.Length, temp_allocator()) or_return
|
||||
_, err = read_memory_as_slice(ph, process_params.CommandLine.Buffer, cmdline_w)
|
||||
if err != nil {
|
||||
break read_peb
|
||||
}
|
||||
if .Command_Line in selection {
|
||||
info.command_line = win32_utf16_to_utf8(cmdline_w, allocator) or_return
|
||||
info.fields += {.Command_Line}
|
||||
}
|
||||
if .Command_Args in selection {
|
||||
info.command_args = _parse_command_line(raw_data(cmdline_w), allocator) or_return
|
||||
info.fields += {.Command_Args}
|
||||
}
|
||||
}
|
||||
if .Environment in selection {
|
||||
TEMP_ALLOCATOR_GUARD()
|
||||
env_len := process_params.EnvironmentSize / 2
|
||||
envs_w := make([]u16, env_len, temp_allocator()) or_return
|
||||
_, err = read_memory_as_slice(ph, process_params.Environment, envs_w)
|
||||
if err != nil {
|
||||
break read_peb
|
||||
}
|
||||
info.environment = _parse_environment_block(raw_data(envs_w), allocator) or_return
|
||||
info.fields += {.Environment}
|
||||
}
|
||||
if .Working_Dir in selection {
|
||||
TEMP_ALLOCATOR_GUARD()
|
||||
cwd_w := make([]u16, process_params.CurrentDirectoryPath.Length, temp_allocator()) or_return
|
||||
_, err = read_memory_as_slice(ph, process_params.CurrentDirectoryPath.Buffer, cwd_w)
|
||||
if err != nil {
|
||||
break read_peb
|
||||
}
|
||||
info.working_dir = win32_utf16_to_utf8(cwd_w, allocator) or_return
|
||||
info.fields += {.Working_Dir}
|
||||
}
|
||||
}
|
||||
read_username: if .Username in selection {
|
||||
username: string
|
||||
username, err = _get_process_user(ph, allocator)
|
||||
if _, ok := err.(runtime.Allocator_Error); ok {
|
||||
return
|
||||
} else if err != nil {
|
||||
break read_username
|
||||
}
|
||||
info.username = username
|
||||
info.fields += {.Username}
|
||||
}
|
||||
err = nil
|
||||
@@ -294,15 +328,15 @@ _process_info_by_handle :: proc(process: Process, selection: Process_Info_Fields
|
||||
@(private="package")
|
||||
_current_process_info :: proc(selection: Process_Info_Fields, allocator: runtime.Allocator) -> (info: Process_Info, err: Error) {
|
||||
info.pid = get_pid()
|
||||
defer if err != nil {
|
||||
free_process_info(info, allocator)
|
||||
}
|
||||
|
||||
if selection >= {.PPid, .Priority} { // snap process
|
||||
snapshot_process: if selection >= {.PPid, .Priority} {
|
||||
entry, entry_err := _process_entry_by_pid(info.pid)
|
||||
if entry_err != nil {
|
||||
err = General_Error.Not_Exist
|
||||
return
|
||||
err = entry_err
|
||||
if entry_err == General_Error.Not_Exist {
|
||||
return
|
||||
} else {
|
||||
break snapshot_process
|
||||
}
|
||||
}
|
||||
if .PPid in selection {
|
||||
info.fields += {.PPid}
|
||||
@@ -313,14 +347,16 @@ _current_process_info :: proc(selection: Process_Info_Fields, allocator: runtime
|
||||
info.priority = int(entry.pcPriClassBase)
|
||||
}
|
||||
}
|
||||
if .Executable_Path in selection {
|
||||
module_filename: if .Executable_Path in selection {
|
||||
exe_filename_w: [256]u16
|
||||
path_len := win32.GetModuleFileNameW(nil, raw_data(exe_filename_w[:]), len(exe_filename_w))
|
||||
assert(path_len > 0)
|
||||
info.executable_path = win32_utf16_to_utf8(exe_filename_w[:path_len], allocator) or_return
|
||||
info.fields += {.Executable_Path}
|
||||
}
|
||||
if selection >= {.Command_Line, .Command_Args} {
|
||||
command_line: if selection >= {.Command_Line, .Command_Args} {
|
||||
command_line_w := win32.GetCommandLineW()
|
||||
assert(command_line_w != nil)
|
||||
if .Command_Line in selection {
|
||||
info.command_line = win32_wstring_to_utf8(command_line_w, allocator) or_return
|
||||
info.fields += {.Command_Line}
|
||||
@@ -330,14 +366,22 @@ _current_process_info :: proc(selection: Process_Info_Fields, allocator: runtime
|
||||
info.fields += {.Command_Args}
|
||||
}
|
||||
}
|
||||
if .Environment in selection {
|
||||
read_environment: if .Environment in selection {
|
||||
env_block := win32.GetEnvironmentStringsW()
|
||||
assert(env_block != nil)
|
||||
info.environment = _parse_environment_block(env_block, allocator) or_return
|
||||
info.fields += {.Environment}
|
||||
}
|
||||
if .Username in selection {
|
||||
read_username: if .Username in selection {
|
||||
process_handle := win32.GetCurrentProcess()
|
||||
info.username = _get_process_user(process_handle, allocator) or_return
|
||||
username: string
|
||||
username, err = _get_process_user(process_handle, allocator)
|
||||
if _, ok := err.(runtime.Allocator_Error); ok {
|
||||
return
|
||||
} else if err != nil {
|
||||
break read_username
|
||||
}
|
||||
info.username = username
|
||||
info.fields += {.Username}
|
||||
}
|
||||
if .Working_Dir in selection {
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
package CoreFoundation
|
||||
|
||||
import "base:runtime"
|
||||
|
||||
foreign import CoreFoundation "system:CoreFoundation.framework"
|
||||
|
||||
String :: distinct TypeRef // same as CFStringRef
|
||||
@@ -9,157 +7,157 @@ String :: distinct TypeRef // same as CFStringRef
|
||||
StringEncoding :: distinct u32
|
||||
|
||||
StringBuiltInEncodings :: enum StringEncoding {
|
||||
MacRoman = 0,
|
||||
MacRoman = 0,
|
||||
WindowsLatin1 = 0x0500,
|
||||
ISOLatin1 = 0x0201,
|
||||
ISOLatin1 = 0x0201,
|
||||
NextStepLatin = 0x0B01,
|
||||
ASCII = 0x0600,
|
||||
Unicode = 0x0100,
|
||||
UTF8 = 0x08000100,
|
||||
ASCII = 0x0600,
|
||||
Unicode = 0x0100,
|
||||
UTF8 = 0x08000100,
|
||||
NonLossyASCII = 0x0BFF,
|
||||
|
||||
UTF16 = 0x0100,
|
||||
UTF16 = 0x0100,
|
||||
UTF16BE = 0x10000100,
|
||||
UTF16LE = 0x14000100,
|
||||
|
||||
UTF32 = 0x0c000100,
|
||||
UTF32BE = 0x18000100,
|
||||
UTF32LE = 0x1c000100,
|
||||
UTF32 = 0x0c000100,
|
||||
UTF32BE = 0x18000100,
|
||||
UTF32LE = 0x1c000100,
|
||||
}
|
||||
|
||||
StringEncodings :: enum Index {
|
||||
MacJapanese = 1,
|
||||
MacChineseTrad = 2,
|
||||
MacKorean = 3,
|
||||
MacArabic = 4,
|
||||
MacHebrew = 5,
|
||||
MacGreek = 6,
|
||||
MacCyrillic = 7,
|
||||
MacDevanagari = 9,
|
||||
MacGurmukhi = 10,
|
||||
MacGujarati = 11,
|
||||
MacOriya = 12,
|
||||
MacBengali = 13,
|
||||
MacTamil = 14,
|
||||
MacTelugu = 15,
|
||||
MacKannada = 16,
|
||||
MacMalayalam = 17,
|
||||
MacSinhalese = 18,
|
||||
MacBurmese = 19,
|
||||
MacKhmer = 20,
|
||||
MacThai = 21,
|
||||
MacLaotian = 22,
|
||||
MacGeorgian = 23,
|
||||
MacArmenian = 24,
|
||||
MacChineseSimp = 25,
|
||||
MacTibetan = 26,
|
||||
MacMongolian = 27,
|
||||
MacEthiopic = 28,
|
||||
MacJapanese = 1,
|
||||
MacChineseTrad = 2,
|
||||
MacKorean = 3,
|
||||
MacArabic = 4,
|
||||
MacHebrew = 5,
|
||||
MacGreek = 6,
|
||||
MacCyrillic = 7,
|
||||
MacDevanagari = 9,
|
||||
MacGurmukhi = 10,
|
||||
MacGujarati = 11,
|
||||
MacOriya = 12,
|
||||
MacBengali = 13,
|
||||
MacTamil = 14,
|
||||
MacTelugu = 15,
|
||||
MacKannada = 16,
|
||||
MacMalayalam = 17,
|
||||
MacSinhalese = 18,
|
||||
MacBurmese = 19,
|
||||
MacKhmer = 20,
|
||||
MacThai = 21,
|
||||
MacLaotian = 22,
|
||||
MacGeorgian = 23,
|
||||
MacArmenian = 24,
|
||||
MacChineseSimp = 25,
|
||||
MacTibetan = 26,
|
||||
MacMongolian = 27,
|
||||
MacEthiopic = 28,
|
||||
MacCentralEurRoman = 29,
|
||||
MacVietnamese = 30,
|
||||
MacExtArabic = 31,
|
||||
MacSymbol = 33,
|
||||
MacDingbats = 34,
|
||||
MacTurkish = 35,
|
||||
MacCroatian = 36,
|
||||
MacIcelandic = 37,
|
||||
MacRomanian = 38,
|
||||
MacCeltic = 39,
|
||||
MacGaelic = 40,
|
||||
MacFarsi = 0x8C,
|
||||
MacUkrainian = 0x98,
|
||||
MacInuit = 0xEC,
|
||||
MacVT100 = 0xFC,
|
||||
MacHFS = 0xFF,
|
||||
ISOLatin2 = 0x0202,
|
||||
ISOLatin3 = 0x0203,
|
||||
ISOLatin4 = 0x0204,
|
||||
ISOLatinCyrillic = 0x0205,
|
||||
ISOLatinArabic = 0x0206,
|
||||
ISOLatinGreek = 0x0207,
|
||||
ISOLatinHebrew = 0x0208,
|
||||
ISOLatin5 = 0x0209,
|
||||
ISOLatin6 = 0x020A,
|
||||
ISOLatinThai = 0x020B,
|
||||
ISOLatin7 = 0x020D,
|
||||
ISOLatin8 = 0x020E,
|
||||
ISOLatin9 = 0x020F,
|
||||
ISOLatin10 = 0x0210,
|
||||
DOSLatinUS = 0x0400,
|
||||
DOSGreek = 0x0405,
|
||||
DOSBalticRim = 0x0406,
|
||||
DOSLatin1 = 0x0410,
|
||||
DOSGreek1 = 0x0411,
|
||||
DOSLatin2 = 0x0412,
|
||||
DOSCyrillic = 0x0413,
|
||||
DOSTurkish = 0x0414,
|
||||
DOSPortuguese = 0x0415,
|
||||
DOSIcelandic = 0x0416,
|
||||
DOSHebrew = 0x0417,
|
||||
DOSCanadianFrench = 0x0418,
|
||||
DOSArabic = 0x0419,
|
||||
DOSNordic = 0x041A,
|
||||
DOSRussian = 0x041B,
|
||||
DOSGreek2 = 0x041C,
|
||||
DOSThai = 0x041D,
|
||||
DOSJapanese = 0x0420,
|
||||
DOSChineseSimplif = 0x0421,
|
||||
DOSKorean = 0x0422,
|
||||
DOSChineseTrad = 0x0423,
|
||||
WindowsLatin2 = 0x0501,
|
||||
WindowsCyrillic = 0x0502,
|
||||
WindowsGreek = 0x0503,
|
||||
WindowsLatin5 = 0x0504,
|
||||
WindowsHebrew = 0x0505,
|
||||
WindowsArabic = 0x0506,
|
||||
WindowsBalticRim = 0x0507,
|
||||
WindowsVietnamese = 0x0508,
|
||||
WindowsKoreanJohab = 0x0510,
|
||||
ANSEL = 0x0601,
|
||||
JIS_X0201_76 = 0x0620,
|
||||
JIS_X0208_83 = 0x0621,
|
||||
JIS_X0208_90 = 0x0622,
|
||||
JIS_X0212_90 = 0x0623,
|
||||
JIS_C6226_78 = 0x0624,
|
||||
ShiftJIS_X0213 = 0x0628,
|
||||
MacVietnamese = 30,
|
||||
MacExtArabic = 31,
|
||||
MacSymbol = 33,
|
||||
MacDingbats = 34,
|
||||
MacTurkish = 35,
|
||||
MacCroatian = 36,
|
||||
MacIcelandic = 37,
|
||||
MacRomanian = 38,
|
||||
MacCeltic = 39,
|
||||
MacGaelic = 40,
|
||||
MacFarsi = 0x8C,
|
||||
MacUkrainian = 0x98,
|
||||
MacInuit = 0xEC,
|
||||
MacVT100 = 0xFC,
|
||||
MacHFS = 0xFF,
|
||||
ISOLatin2 = 0x0202,
|
||||
ISOLatin3 = 0x0203,
|
||||
ISOLatin4 = 0x0204,
|
||||
ISOLatinCyrillic = 0x0205,
|
||||
ISOLatinArabic = 0x0206,
|
||||
ISOLatinGreek = 0x0207,
|
||||
ISOLatinHebrew = 0x0208,
|
||||
ISOLatin5 = 0x0209,
|
||||
ISOLatin6 = 0x020A,
|
||||
ISOLatinThai = 0x020B,
|
||||
ISOLatin7 = 0x020D,
|
||||
ISOLatin8 = 0x020E,
|
||||
ISOLatin9 = 0x020F,
|
||||
ISOLatin10 = 0x0210,
|
||||
DOSLatinUS = 0x0400,
|
||||
DOSGreek = 0x0405,
|
||||
DOSBalticRim = 0x0406,
|
||||
DOSLatin1 = 0x0410,
|
||||
DOSGreek1 = 0x0411,
|
||||
DOSLatin2 = 0x0412,
|
||||
DOSCyrillic = 0x0413,
|
||||
DOSTurkish = 0x0414,
|
||||
DOSPortuguese = 0x0415,
|
||||
DOSIcelandic = 0x0416,
|
||||
DOSHebrew = 0x0417,
|
||||
DOSCanadianFrench = 0x0418,
|
||||
DOSArabic = 0x0419,
|
||||
DOSNordic = 0x041A,
|
||||
DOSRussian = 0x041B,
|
||||
DOSGreek2 = 0x041C,
|
||||
DOSThai = 0x041D,
|
||||
DOSJapanese = 0x0420,
|
||||
DOSChineseSimplif = 0x0421,
|
||||
DOSKorean = 0x0422,
|
||||
DOSChineseTrad = 0x0423,
|
||||
WindowsLatin2 = 0x0501,
|
||||
WindowsCyrillic = 0x0502,
|
||||
WindowsGreek = 0x0503,
|
||||
WindowsLatin5 = 0x0504,
|
||||
WindowsHebrew = 0x0505,
|
||||
WindowsArabic = 0x0506,
|
||||
WindowsBalticRim = 0x0507,
|
||||
WindowsVietnamese = 0x0508,
|
||||
WindowsKoreanJohab = 0x0510,
|
||||
ANSEL = 0x0601,
|
||||
JIS_X0201_76 = 0x0620,
|
||||
JIS_X0208_83 = 0x0621,
|
||||
JIS_X0208_90 = 0x0622,
|
||||
JIS_X0212_90 = 0x0623,
|
||||
JIS_C6226_78 = 0x0624,
|
||||
ShiftJIS_X0213 = 0x0628,
|
||||
ShiftJIS_X0213_MenKuTen = 0x0629,
|
||||
GB_2312_80 = 0x0630,
|
||||
GBK_95 = 0x0631,
|
||||
GB_18030_2000 = 0x0632,
|
||||
KSC_5601_87 = 0x0640,
|
||||
KSC_5601_92_Johab = 0x0641,
|
||||
CNS_11643_92_P1 = 0x0651,
|
||||
CNS_11643_92_P2 = 0x0652,
|
||||
CNS_11643_92_P3 = 0x0653,
|
||||
ISO_2022_JP = 0x0820,
|
||||
ISO_2022_JP_2 = 0x0821,
|
||||
ISO_2022_JP_1 = 0x0822,
|
||||
ISO_2022_JP_3 = 0x0823,
|
||||
ISO_2022_CN = 0x0830,
|
||||
ISO_2022_CN_EXT = 0x0831,
|
||||
ISO_2022_KR = 0x0840,
|
||||
EUC_JP = 0x0920,
|
||||
EUC_CN = 0x0930,
|
||||
EUC_TW = 0x0931,
|
||||
EUC_KR = 0x0940,
|
||||
ShiftJIS = 0x0A01,
|
||||
KOI8_R = 0x0A02,
|
||||
Big5 = 0x0A03,
|
||||
MacRomanLatin1 = 0x0A04,
|
||||
HZ_GB_2312 = 0x0A05,
|
||||
Big5_HKSCS_1999 = 0x0A06,
|
||||
VISCII = 0x0A07,
|
||||
KOI8_U = 0x0A08,
|
||||
Big5_E = 0x0A09,
|
||||
NextStepJapanese = 0x0B02,
|
||||
EBCDIC_US = 0x0C01,
|
||||
EBCDIC_CP037 = 0x0C02,
|
||||
UTF7 = 0x04000100,
|
||||
UTF7_IMAP = 0x0A10,
|
||||
ShiftJIS_X0213_00 = 0x0628, // Deprecated. Use `ShiftJIS_X0213` instead.
|
||||
GB_2312_80 = 0x0630,
|
||||
GBK_95 = 0x0631,
|
||||
GB_18030_2000 = 0x0632,
|
||||
KSC_5601_87 = 0x0640,
|
||||
KSC_5601_92_Johab = 0x0641,
|
||||
CNS_11643_92_P1 = 0x0651,
|
||||
CNS_11643_92_P2 = 0x0652,
|
||||
CNS_11643_92_P3 = 0x0653,
|
||||
ISO_2022_JP = 0x0820,
|
||||
ISO_2022_JP_2 = 0x0821,
|
||||
ISO_2022_JP_1 = 0x0822,
|
||||
ISO_2022_JP_3 = 0x0823,
|
||||
ISO_2022_CN = 0x0830,
|
||||
ISO_2022_CN_EXT = 0x0831,
|
||||
ISO_2022_KR = 0x0840,
|
||||
EUC_JP = 0x0920,
|
||||
EUC_CN = 0x0930,
|
||||
EUC_TW = 0x0931,
|
||||
EUC_KR = 0x0940,
|
||||
ShiftJIS = 0x0A01,
|
||||
KOI8_R = 0x0A02,
|
||||
Big5 = 0x0A03,
|
||||
MacRomanLatin1 = 0x0A04,
|
||||
HZ_GB_2312 = 0x0A05,
|
||||
Big5_HKSCS_1999 = 0x0A06,
|
||||
VISCII = 0x0A07,
|
||||
KOI8_U = 0x0A08,
|
||||
Big5_E = 0x0A09,
|
||||
NextStepJapanese = 0x0B02,
|
||||
EBCDIC_US = 0x0C01,
|
||||
EBCDIC_CP037 = 0x0C02,
|
||||
UTF7 = 0x04000100,
|
||||
UTF7_IMAP = 0x0A10,
|
||||
ShiftJIS_X0213_00 = 0x0628, // Deprecated. Use `ShiftJIS_X0213` instead.
|
||||
}
|
||||
|
||||
@(link_prefix = "CF", default_calling_convention = "c")
|
||||
@(link_prefix="CF", default_calling_convention="c")
|
||||
foreign CoreFoundation {
|
||||
// Copies the character contents of a string to a local C string buffer after converting the characters to a given encoding.
|
||||
StringGetCString :: proc(theString: String, buffer: [^]byte, bufferSize: Index, encoding: StringEncoding) -> b8 ---
|
||||
@@ -181,23 +179,16 @@ foreign CoreFoundation {
|
||||
|
||||
STR :: StringMakeConstantString
|
||||
|
||||
StringCopyToOdinString :: proc(
|
||||
theString: String,
|
||||
allocator := context.allocator,
|
||||
) -> (
|
||||
str: string,
|
||||
ok: bool,
|
||||
) #optional_ok {
|
||||
StringCopyToOdinString :: proc(theString: String, allocator := context.allocator) -> (str: string, ok: bool) #optional_ok {
|
||||
length := StringGetLength(theString)
|
||||
max := StringGetMaximumSizeForEncoding(length, StringEncoding(StringBuiltInEncodings.UTF8))
|
||||
|
||||
buf, err := make([]byte, max, allocator)
|
||||
if err != nil { return }
|
||||
|
||||
raw_str := runtime.Raw_String {
|
||||
data = raw_data(buf),
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
StringGetBytes(theString, {0, length}, StringEncoding(StringBuiltInEncodings.UTF8), 0, false, raw_data(buf), max, (^Index)(&raw_str.len))
|
||||
|
||||
return transmute(string)raw_str, true
|
||||
n: Index
|
||||
StringGetBytes(theString, {0, length}, StringEncoding(StringBuiltInEncodings.UTF8), 0, false, raw_data(buf), Index(len(buf)), &n)
|
||||
return string(buf[:n]), true
|
||||
}
|
||||
|
||||
@@ -27,6 +27,8 @@ foreign pthread {
|
||||
|
||||
pthread_equal :: proc(a, b: pthread_t) -> b32 ---
|
||||
|
||||
pthread_detach :: proc(t: pthread_t) -> c.int ---
|
||||
|
||||
sched_get_priority_min :: proc(policy: c.int) -> c.int ---
|
||||
sched_get_priority_max :: proc(policy: c.int) -> c.int ---
|
||||
|
||||
|
||||
@@ -400,6 +400,9 @@ foreign kernel32 {
|
||||
GlobalAlloc :: proc(flags: UINT, bytes: SIZE_T) -> LPVOID ---
|
||||
GlobalReAlloc :: proc(mem: LPVOID, bytes: SIZE_T, flags: UINT) -> LPVOID ---
|
||||
GlobalFree :: proc(mem: LPVOID) -> LPVOID ---
|
||||
|
||||
GlobalLock :: proc(hMem: HGLOBAL) -> LPVOID ---
|
||||
GlobalUnlock :: proc(hMem: HGLOBAL) -> BOOL ---
|
||||
|
||||
ReadDirectoryChangesW :: proc(
|
||||
hDirectory: HANDLE,
|
||||
|
||||
@@ -66,7 +66,7 @@ foreign user32 {
|
||||
RemovePropW :: proc(hWnd: HWND, lpString: LPCWSTR) -> HANDLE ---
|
||||
EnumPropsW :: proc(hWnd: HWND, lpEnumFunc: PROPENUMPROCW) -> INT ---
|
||||
EnumPropsExW :: proc(hWnd: HWND, lpEnumFunc: PROPENUMPROCW, lParam: LPARAM) -> INT ---
|
||||
GetMessageW :: proc(lpMsg: ^MSG, hWnd: HWND, wMsgFilterMin: UINT, wMsgFilterMax: UINT) -> BOOL ---
|
||||
GetMessageW :: proc(lpMsg: ^MSG, hWnd: HWND, wMsgFilterMin: UINT, wMsgFilterMax: UINT) -> INT ---
|
||||
|
||||
TranslateMessage :: proc(lpMsg: ^MSG) -> BOOL ---
|
||||
DispatchMessageW :: proc(lpMsg: ^MSG) -> LRESULT ---
|
||||
@@ -142,7 +142,7 @@ foreign user32 {
|
||||
AppendMenuW :: proc(hMenu: HMENU, uFlags: UINT, uIDNewItem: UINT_PTR, lpNewItem: LPCWSTR) -> BOOL ---
|
||||
GetMenu :: proc(hWnd: HWND) -> HMENU ---
|
||||
SetMenu :: proc(hWnd: HWND, hMenu: HMENU) -> BOOL ---
|
||||
TrackPopupMenu :: proc(hMenu: HMENU, uFlags: UINT, x, y: INT, nReserved: INT, hWnd: HWND, prcRect: ^RECT) -> BOOL ---
|
||||
TrackPopupMenu :: proc(hMenu: HMENU, uFlags: UINT, x, y: INT, nReserved: INT, hWnd: HWND, prcRect: ^RECT) -> INT ---
|
||||
RegisterWindowMessageW :: proc(lpString: LPCWSTR) -> UINT ---
|
||||
|
||||
CreateAcceleratorTableW :: proc(paccel: LPACCEL, cAccel: INT) -> HACCEL ---
|
||||
@@ -305,6 +305,13 @@ foreign user32 {
|
||||
|
||||
GetProcessWindowStation :: proc() -> HWINSTA ---
|
||||
GetUserObjectInformationW :: proc(hObj: HANDLE, nIndex: GetUserObjectInformationFlags, pvInfo: PVOID, nLength: DWORD, lpnLengthNeeded: LPDWORD) -> BOOL ---
|
||||
|
||||
OpenClipboard :: proc(hWndNewOwner: HWND) -> BOOL ---
|
||||
CloseClipboard :: proc() -> BOOL ---
|
||||
GetClipboardData :: proc(uFormat: UINT) -> HANDLE ---
|
||||
SetClipboardData :: proc(uFormat: UINT, hMem: HANDLE) -> HANDLE ---
|
||||
IsClipboardFormatAvailable :: proc(format: UINT) -> BOOL ---
|
||||
EmptyClipboard :: proc() -> BOOL ---
|
||||
}
|
||||
|
||||
CreateWindowW :: #force_inline proc "system" (
|
||||
@@ -746,3 +753,31 @@ WinEventFlag :: enum DWORD {
|
||||
SKIPOWNPROCESS = 1,
|
||||
INCONTEXT = 2,
|
||||
}
|
||||
|
||||
// Standard Clipboard Formats
|
||||
CF_TEXT :: 1
|
||||
CF_BITMAP :: 2
|
||||
CF_METAFILEPICT :: 3
|
||||
CF_SYLK :: 4
|
||||
CF_DIF :: 5
|
||||
CF_TIFF :: 6
|
||||
CF_OEMTEXT :: 7
|
||||
CF_DIB :: 8
|
||||
CF_PALETTE :: 9
|
||||
CF_PENDATA :: 10
|
||||
CF_RIFF :: 11
|
||||
CF_WAVE :: 12
|
||||
CF_UNICODETEXT :: 13
|
||||
CF_ENHMETAFILE :: 14
|
||||
CF_HDROP :: 15
|
||||
CF_LOCALE :: 16
|
||||
CF_DIBV5 :: 17
|
||||
CF_DSPBITMAP :: 0x0082
|
||||
CF_DSPENHMETAFILE :: 0x008E
|
||||
CF_DSPMETAFILEPICT :: 0x0083
|
||||
CF_DSPTEXT :: 0x0081
|
||||
CF_GDIOBJFIRST :: 0x0300
|
||||
CF_GDIOBJLAST :: 0x03FF
|
||||
CF_OWNERDISPLAY :: 0x0080
|
||||
CF_PRIVATEFIRST :: 0x0200
|
||||
CF_PRIVATELAST :: 0x02FF
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
// +private
|
||||
package thread
|
||||
|
||||
import "base:runtime"
|
||||
import "core:sync"
|
||||
import "core:sys/unix"
|
||||
import "core:time"
|
||||
@@ -55,7 +56,10 @@ _create :: proc(procedure: Thread_Proc, priority: Thread_Priority) -> ^Thread {
|
||||
// Here on Unix, we start the OS thread in a running state, and so we manually have it wait on a condition
|
||||
// variable above. We must perform that waiting BEFORE we select the context!
|
||||
context = _select_context_for_thread(init_context)
|
||||
defer _maybe_destroy_default_temp_allocator(init_context)
|
||||
defer {
|
||||
_maybe_destroy_default_temp_allocator(init_context)
|
||||
runtime.run_thread_local_cleaners()
|
||||
}
|
||||
|
||||
t.procedure(t)
|
||||
}
|
||||
@@ -65,6 +69,9 @@ _create :: proc(procedure: Thread_Proc, priority: Thread_Priority) -> ^Thread {
|
||||
sync.unlock(&t.mutex)
|
||||
|
||||
if .Self_Cleanup in sync.atomic_load(&t.flags) {
|
||||
res := unix.pthread_detach(t.unix_thread)
|
||||
assert_contextless(res == 0)
|
||||
|
||||
t.unix_thread = {}
|
||||
// NOTE(ftphikari): It doesn't matter which context 'free' received, right?
|
||||
context = {}
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
package thread
|
||||
|
||||
import "base:intrinsics"
|
||||
import "base:runtime"
|
||||
import "core:sync"
|
||||
import win32 "core:sys/windows"
|
||||
|
||||
@@ -39,7 +40,10 @@ _create :: proc(procedure: Thread_Proc, priority: Thread_Priority) -> ^Thread {
|
||||
// Here on Windows, the thread is created in a suspended state, and so we can select the context anywhere before the call
|
||||
// to t.procedure().
|
||||
context = _select_context_for_thread(init_context)
|
||||
defer _maybe_destroy_default_temp_allocator(init_context)
|
||||
defer {
|
||||
_maybe_destroy_default_temp_allocator(init_context)
|
||||
runtime.run_thread_local_cleaners()
|
||||
}
|
||||
|
||||
t.procedure(t)
|
||||
}
|
||||
|
||||
@@ -263,7 +263,7 @@ gb_internal lbValue lb_emit_transmute(lbProcedure *p, lbValue value, Type *t) {
|
||||
if (is_type_simd_vector(src) && is_type_simd_vector(dst)) {
|
||||
res.value = LLVMBuildBitCast(p->builder, value.value, lb_type(p->module, t), "");
|
||||
return res;
|
||||
} else if (is_type_array_like(src) && is_type_simd_vector(dst)) {
|
||||
} else if (is_type_array_like(src) && (is_type_simd_vector(dst) || is_type_integer_128bit(dst))) {
|
||||
unsigned align = cast(unsigned)gb_max(type_align_of(src), type_align_of(dst));
|
||||
lbValue ptr = lb_address_from_load_or_generate_local(p, value);
|
||||
if (lb_try_update_alignment(ptr, align)) {
|
||||
|
||||
@@ -69,18 +69,18 @@ test_libc_pow_binding :: proc(t: ^testing.T, $LIBC_COMPLEX:typeid, $F:typeid, po
|
||||
complex_power := LIBC_COMPLEX(complex(F(n), F(0.)))
|
||||
result := pow(complex_base, complex_power)
|
||||
switch n%%4 {
|
||||
case 0:
|
||||
expected_real = value
|
||||
expected_imag = 0.
|
||||
case 1:
|
||||
expected_real = 0.
|
||||
expected_imag = value
|
||||
case 2:
|
||||
expected_real = -value
|
||||
expected_imag = 0.
|
||||
case 3:
|
||||
expected_real = 0.
|
||||
expected_imag = -value
|
||||
case 0:
|
||||
expected_real = value
|
||||
expected_imag = 0.
|
||||
case 1:
|
||||
expected_real = 0.
|
||||
expected_imag = value
|
||||
case 2:
|
||||
expected_real = -value
|
||||
expected_imag = 0.
|
||||
case 3:
|
||||
expected_real = 0.
|
||||
expected_imag = -value
|
||||
}
|
||||
testing.expectf(t, isclose(t, expected_real, F(real(result)), rtol, atol), "ftype:%T, n:%v reldiff(%v, re(%v)) is greater than specified rtol:%e", F{}, n, expected_real, result, rtol)
|
||||
testing.expectf(t, isclose(t, expected_imag, F(imag(result)), rtol, atol), "ftype:%T, n:%v reldiff(%v, im(%v)) is greater than specified rtol:%e", F{}, n, expected_imag, result, rtol)
|
||||
|
||||
@@ -187,7 +187,7 @@ validate_rbtree :: proc(t: ^testing.T, tree: ^$T/rb.Tree($Key, $Value)) {
|
||||
}
|
||||
|
||||
verify_rbtree_propery_1 :: proc(t: ^testing.T, n: ^$N/rb.Node($Key, $Value)) {
|
||||
testing.expect(t, rb.node_color(n) == .Black || rb.node_color(n) == .Red, "Property #1: Each node is either red or black.")
|
||||
testing.expect(t, rb.node_color(n) == .Black || rb.node_color(n) == .Red, "Property #1: Each node is either red or black.")
|
||||
if n == nil {
|
||||
return
|
||||
}
|
||||
|
||||
@@ -429,7 +429,7 @@ map_with_integer_keys :: proc(t: ^testing.T) {
|
||||
defer delete_map(my_map2)
|
||||
|
||||
unmarshal_err := json.unmarshal(marshaled_data, &my_map2)
|
||||
defer for key, item in my_map2 {
|
||||
defer for _, item in my_map2 {
|
||||
runtime.delete_string(item)
|
||||
}
|
||||
testing.expectf(t, unmarshal_err == nil, "Expected `json.unmarshal` to return nil, got %v", unmarshal_err)
|
||||
|
||||
@@ -241,7 +241,7 @@ doc_to_string :: proc(doc: ^xml.Document) -> (result: string) {
|
||||
written += fmt.wprintf(writer, "[DOCTYPE] %v\n", doc.doctype.ident)
|
||||
|
||||
if len(doc.doctype.rest) > 0 {
|
||||
fmt.wprintf(writer, "\t%v\n", doc.doctype.rest)
|
||||
fmt.wprintf(writer, "\t%v\n", doc.doctype.rest)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -250,10 +250,10 @@ doc_to_string :: proc(doc: ^xml.Document) -> (result: string) {
|
||||
}
|
||||
|
||||
if doc.element_count > 0 {
|
||||
fmt.wprintln(writer, " --- ")
|
||||
print_element(writer, doc, 0)
|
||||
fmt.wprintln(writer, " --- ")
|
||||
}
|
||||
fmt.wprintln(writer, " --- ")
|
||||
print_element(writer, doc, 0)
|
||||
fmt.wprintln(writer, " --- ")
|
||||
}
|
||||
|
||||
return written, .None
|
||||
}
|
||||
|
||||
55
tests/core/sys/windows/test_clipboard.odin
Normal file
55
tests/core/sys/windows/test_clipboard.odin
Normal file
@@ -0,0 +1,55 @@
|
||||
//+build windows
|
||||
package test_core_sys_windows
|
||||
|
||||
import "core:testing"
|
||||
import win32 "core:sys/windows"
|
||||
import "base:runtime"
|
||||
import "core:strings"
|
||||
import "core:mem"
|
||||
|
||||
read_from_clipboard :: proc(wnd_handle: win32.HWND, allocator: runtime.Allocator) -> (result: string, ok: win32.BOOL) {
|
||||
win32.IsClipboardFormatAvailable(win32.CF_TEXT) or_return
|
||||
|
||||
win32.OpenClipboard(wnd_handle) or_return
|
||||
defer win32.CloseClipboard()
|
||||
|
||||
clipboard_data := win32.GetClipboardData(win32.CF_TEXT)
|
||||
if clipboard_data != nil {
|
||||
if cstr := cstring(win32.GlobalLock(win32.HGLOBAL(clipboard_data))); cstr != nil {
|
||||
result = strings.clone_from_cstring(cstr, allocator)
|
||||
ok = true
|
||||
}
|
||||
win32.GlobalUnlock(win32.HGLOBAL(clipboard_data))
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
write_to_clipboard :: proc(wnd_handle: win32.HWND, text: string) -> win32.BOOL {
|
||||
win32.OpenClipboard(wnd_handle) or_return
|
||||
defer win32.CloseClipboard()
|
||||
win32.EmptyClipboard()
|
||||
|
||||
h_mem := win32.HGLOBAL(win32.GlobalAlloc(win32.GMEM_MOVEABLE, len(text) + 1))
|
||||
if h_mem == nil {return false}
|
||||
|
||||
cstr_dst := cast([^]u8)win32.GlobalLock(h_mem)
|
||||
defer win32.GlobalUnlock(h_mem)
|
||||
if cstr_dst == nil {return false}
|
||||
|
||||
mem.copy(rawptr(cstr_dst), raw_data(text), len(text))
|
||||
cstr_dst[len(text)] = 0
|
||||
|
||||
win32.SetClipboardData(win32.CF_TEXT, win32.HANDLE(h_mem))
|
||||
return true
|
||||
}
|
||||
|
||||
|
||||
@(test)
|
||||
verify_win32_clipboard :: proc(t: ^testing.T) {
|
||||
ok1 := write_to_clipboard(nil, "Hello everynyan! OH MY GAH")
|
||||
testing.expect_value(t, ok1, true)
|
||||
|
||||
clipboard_content, ok2 := read_from_clipboard(nil, context.temp_allocator)
|
||||
testing.expect_value(t, ok2, true)
|
||||
testing.expect_value(t, clipboard_content, "Hello everynyan! OH MY GAH")
|
||||
}
|
||||
@@ -16,8 +16,7 @@ run_test_cases :: proc(t: ^testing.T, test_cases: []Test_Case, loc := #caller_lo
|
||||
result, _, _ := utf8.grapheme_count(c.str)
|
||||
if !testing.expectf(t, result == c.expected_clusters,
|
||||
"(#% 4i) graphemes: %i != %i, %q %s", i, result, c.expected_clusters, c.str, c.str,
|
||||
loc = loc)
|
||||
{
|
||||
loc = loc) {
|
||||
failed += 1
|
||||
}
|
||||
}
|
||||
|
||||
4
vendor/wgpu/README.md
vendored
4
vendor/wgpu/README.md
vendored
@@ -11,8 +11,8 @@ Have a look at the `example/` directory for the rendering of a basic triangle.
|
||||
## Getting the wgpu-native libraries
|
||||
|
||||
For native support (not the browser), some libraries are required. Fortunately this is
|
||||
extremely easy, just download them from the [releases on GitHub](https://github.com/gfx-rs/wgpu-native/releases/tag/v0.19.4.1),
|
||||
the bindings are for v0.19.4.1 at the moment.
|
||||
extremely easy, just download them from the [releases on GitHub](https://github.com/gfx-rs/wgpu-native/releases/tag/v22.1.0.1),
|
||||
the bindings are for v22.1.0.1 at the moment.
|
||||
|
||||
These are expected in the `lib` folder under the same name as they are released (just unzipped).
|
||||
By default it will look for a static release version (`wgpu-OS-ARCH-release.a|lib`),
|
||||
|
||||
4
vendor/wgpu/examples/glfw/main.odin
vendored
4
vendor/wgpu/examples/glfw/main.odin
vendored
@@ -158,15 +158,17 @@ frame :: proc "c" (dt: f32) {
|
||||
view = frame,
|
||||
loadOp = .Clear,
|
||||
storeOp = .Store,
|
||||
depthSlice = wgpu.DEPTH_SLICE_UNDEFINED,
|
||||
clearValue = { 0, 1, 0, 1 },
|
||||
},
|
||||
},
|
||||
)
|
||||
defer wgpu.RenderPassEncoderRelease(render_pass_encoder)
|
||||
|
||||
wgpu.RenderPassEncoderSetPipeline(render_pass_encoder, state.pipeline)
|
||||
wgpu.RenderPassEncoderDraw(render_pass_encoder, vertexCount=3, instanceCount=1, firstVertex=0, firstInstance=0)
|
||||
|
||||
wgpu.RenderPassEncoderEnd(render_pass_encoder)
|
||||
wgpu.RenderPassEncoderRelease(render_pass_encoder)
|
||||
|
||||
command_buffer := wgpu.CommandEncoderFinish(command_encoder, nil)
|
||||
defer wgpu.CommandBufferRelease(command_buffer)
|
||||
|
||||
4
vendor/wgpu/examples/sdl2/main.odin
vendored
4
vendor/wgpu/examples/sdl2/main.odin
vendored
@@ -158,15 +158,17 @@ frame :: proc "c" (dt: f32) {
|
||||
view = frame,
|
||||
loadOp = .Clear,
|
||||
storeOp = .Store,
|
||||
depthSlice = wgpu.DEPTH_SLICE_UNDEFINED,
|
||||
clearValue = { 0, 1, 0, 1 },
|
||||
},
|
||||
},
|
||||
)
|
||||
defer wgpu.RenderPassEncoderRelease(render_pass_encoder)
|
||||
|
||||
wgpu.RenderPassEncoderSetPipeline(render_pass_encoder, state.pipeline)
|
||||
wgpu.RenderPassEncoderDraw(render_pass_encoder, vertexCount=3, instanceCount=1, firstVertex=0, firstInstance=0)
|
||||
|
||||
wgpu.RenderPassEncoderEnd(render_pass_encoder)
|
||||
wgpu.RenderPassEncoderRelease(render_pass_encoder)
|
||||
|
||||
command_buffer := wgpu.CommandEncoderFinish(command_encoder, nil)
|
||||
defer wgpu.CommandBufferRelease(command_buffer)
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
187
vendor/wgpu/wgpu.js
vendored
187
vendor/wgpu/wgpu.js
vendored
@@ -44,6 +44,7 @@ class WebGPUInterface {
|
||||
BlendFactor: ["zero", "one", "src", "one-minus-src", "src-alpha", "one-minus-src-alpha", "dst", "one-minus-dst", "dst-alpha", "one-minus-dst-alpha", "src-alpha-saturated", "constant", "one-minus-constant", ],
|
||||
PresentMode: ["fifo", "fifo-relaxed", "immediate", "mailbox", ],
|
||||
TextureAspect: ["all", "stencil-only", "depth-only"],
|
||||
DeviceLostReason: [undefined, "unknown", "destroyed"],
|
||||
};
|
||||
|
||||
/** @type {WebGPUObjectManager<{}>} */
|
||||
@@ -382,13 +383,19 @@ class WebGPUInterface {
|
||||
*/
|
||||
RenderPassColorAttachment(start) {
|
||||
const viewIdx = this.mem.loadPtr(start + 4);
|
||||
const resolveTargetIdx = this.mem.loadPtr(start + 8);
|
||||
const resolveTargetIdx = this.mem.loadPtr(start + 12);
|
||||
|
||||
let depthSlice = this.mem.loadU32(start + 8);
|
||||
if (depthSlice == 0xFFFFFFFF) { // DEPTH_SLICE_UNDEFINED.
|
||||
depthSlice = undefined;
|
||||
}
|
||||
|
||||
return {
|
||||
view: viewIdx > 0 ? this.textureViews.get(viewIdx) : undefined,
|
||||
resolveTarget: resolveTargetIdx > 0 ? this.textureViews.get(resolveTargetIdx) : undefined,
|
||||
loadOp: this.enumeration("LoadOp", start + 12),
|
||||
storeOp: this.enumeration("StoreOp", start + 16),
|
||||
depthSlice: depthSlice,
|
||||
loadOp: this.enumeration("LoadOp", start + 16),
|
||||
storeOp: this.enumeration("StoreOp", start + 20),
|
||||
clearValue: this.Color(start + 24),
|
||||
};
|
||||
}
|
||||
@@ -950,14 +957,25 @@ class WebGPUInterface {
|
||||
|
||||
/**
|
||||
* @param {number} adapterIdx
|
||||
* @param {number} propertiesPtr
|
||||
* @param {number} infoPtr
|
||||
*/
|
||||
wgpuAdapterGetProperties: (adapterIdx, propertiesPtr) => {
|
||||
this.assert(propertiesPtr != 0);
|
||||
// Unknown adapter.
|
||||
this.mem.storeI32(propertiesPtr + 28, 3);
|
||||
wgpuAdapterGetInfo: (adapterIdx, infoPtr) => {
|
||||
this.assert(infoPtr != 0);
|
||||
|
||||
// WebGPU backend.
|
||||
this.mem.storeI32(propertiesPtr + 32, 2);
|
||||
this.mem.storeI32(infoPtr + 20, 2);
|
||||
// Unknown adapter.
|
||||
this.mem.storeI32(infoPtr + 24, 3);
|
||||
|
||||
// NOTE: I don't think getting the other fields in this struct is possible.
|
||||
// `adapter.requestAdapterInfo` is deprecated.
|
||||
},
|
||||
|
||||
/**
|
||||
* @param {number} infoPtr
|
||||
*/
|
||||
wgpuAdapterInfoFreeMembers: (infoPtr) => {
|
||||
// NOTE: nothing to free.
|
||||
},
|
||||
|
||||
/**
|
||||
@@ -970,50 +988,6 @@ class WebGPUInterface {
|
||||
return adapter.features.has(this.enums.FeatureName[featureInt]);
|
||||
},
|
||||
|
||||
/**
|
||||
* @param {number} adapterIdx
|
||||
* @param {number} callbackPtr
|
||||
* @param {0|number} userdata
|
||||
*/
|
||||
wgpuAdapterRequestAdapterInfo: async (adapterIdx, callbackPtr, userdata) => {
|
||||
const adapter = this.adapters.get(adapterIdx);
|
||||
const callback = this.mem.exports.__indirect_function_table.get(callbackPtr);
|
||||
|
||||
const info = await adapter.requestAdapterInfo();
|
||||
|
||||
const addr = this.mem.exports.wgpu_alloc(16);
|
||||
|
||||
const vendorLength = new TextEncoder().encode(info.vendor).length;
|
||||
const vendorAddr = this.mem.exports.wgpu_alloc(vendorLength);
|
||||
this.mem.storeString(vendorAddr, info.vendor);
|
||||
this.mem.storeI32(addr + 0, vendorAddr);
|
||||
|
||||
const architectureLength = new TextEncoder().encode(info.architecture).length;
|
||||
const architectureAddr = this.mem.exports.wgpu_alloc(architectureLength);
|
||||
this.mem.storeString(architectureAddr, info.architecture);
|
||||
this.mem.storeI32(addr + 4, architectureAddr);
|
||||
|
||||
|
||||
const deviceLength = new TextEncoder().encode(info.device).length;
|
||||
const deviceAddr = this.mem.exports.wgpu_alloc(deviceLength);
|
||||
this.mem.storeString(deviceAddr, info.device);
|
||||
this.mem.storeI32(addr + 8, deviceAddr);
|
||||
|
||||
|
||||
const descriptionLength = new TextEncoder().encode(info.description).length;
|
||||
const descriptionAddr = this.mem.exports.wgpu_alloc(descriptionLength);
|
||||
this.mem.storeString(descriptionAddr, info.description);
|
||||
this.mem.storeI32(addr + 12, descriptionAddr);
|
||||
|
||||
callback(addr, userdata);
|
||||
|
||||
this.mem.exports.wgpu_free(descriptionAddr);
|
||||
this.mem.exports.wgpu_free(deviceAddr);
|
||||
this.mem.exports.wgpu_free(architectureAddr);
|
||||
this.mem.exports.wgpu_free(vendorAddr);
|
||||
this.mem.exports.wgpu_free(addr);
|
||||
},
|
||||
|
||||
/**
|
||||
* @param {number} adapterIdx
|
||||
* @param {0|number} descriptorPtr
|
||||
@@ -1040,14 +1014,69 @@ class WebGPUInterface {
|
||||
};
|
||||
}
|
||||
|
||||
let device;
|
||||
let deviceIdx;
|
||||
try {
|
||||
const device = await adapter.requestDevice(descriptor);
|
||||
device = await adapter.requestDevice(descriptor);
|
||||
deviceIdx = this.devices.create(device);
|
||||
// NOTE: don't callback here, any errors that happen later will then be caught by the catch here.
|
||||
} catch (e) {
|
||||
console.warn(e);
|
||||
callback(1, null, null, userdata);
|
||||
const messageLength = new TextEncoder().encode(e.message).length;
|
||||
const messageAddr = this.mem.exports.wgpu_alloc(messageLength + 1);
|
||||
this.mem.storeString(messageAddr, e.message);
|
||||
|
||||
callback(1, null, messageAddr, userdata);
|
||||
|
||||
this.mem.exports.wgpu_free(messageAddr);
|
||||
}
|
||||
|
||||
let callbacksPtr = descriptorPtr + 24 + this.mem.intSize;
|
||||
|
||||
const deviceLostCallbackPtr = this.mem.loadPtr(callbacksPtr);
|
||||
if (deviceLostCallbackPtr != 0) {
|
||||
const deviceLostUserData = this.mem.loadPtr(callbacksPtr) + 4;
|
||||
const deviceLostCallback = this.mem.exports.__indirect_function_table.get(deviceLostCallbackPtr);
|
||||
|
||||
device.lost.then((info) => {
|
||||
const reason = this.enums.DeviceLostReason.indexOf(info.reason);
|
||||
|
||||
const messageLength = new TextEncoder().encode(info.message).length;
|
||||
const messageAddr = this.mem.exports.wgpu_alloc(messageLength + 1);
|
||||
this.mem.storeString(messageAddr, info.message);
|
||||
|
||||
deviceLostCallback(reason, messageAddr, deviceLostUserData);
|
||||
|
||||
this.mem.exports.wgpu_free(messageAddr);
|
||||
});
|
||||
}
|
||||
callbacksPtr += 8;
|
||||
|
||||
// Skip over `nextInChain`.
|
||||
callbacksPtr += 4;
|
||||
|
||||
const uncapturedErrorCallbackPtr = this.mem.loadPtr(callbacksPtr);
|
||||
if (uncapturedErrorCallbackPtr != 0) {
|
||||
const uncapturedErrorUserData = this.mem.loadPtr(callbacksPtr + 4);
|
||||
const uncapturedErrorCallback = this.mem.exports.__indirect_function_table.get(uncapturedErrorCallbackPtr);
|
||||
|
||||
device.onuncapturederror = (ev) => {
|
||||
let status = 4; // Unknown
|
||||
if (ev.error instanceof GPUValidationError) {
|
||||
status = 1; // Validation
|
||||
} else if (ev.error instanceof GPUOutOfMemoryError) {
|
||||
status = 2; // OutOfMemory
|
||||
} else if (ev.error instanceof GPUInternalError) {
|
||||
status = 3; // Internal
|
||||
}
|
||||
|
||||
const messageLength = new TextEncoder().encode(ev.error.message).length;
|
||||
const messageAddr = this.mem.exports.wgpu_alloc(messageLength + 1);
|
||||
this.mem.storeString(messageAddr, ev.error.message);
|
||||
|
||||
uncapturedErrorCallback(status, messageAddr, uncapturedErrorUserData);
|
||||
|
||||
this.mem.exports.wgpu_free(messageAddr);
|
||||
};
|
||||
}
|
||||
|
||||
callback(0, deviceIdx, null, userdata);
|
||||
@@ -1918,29 +1947,6 @@ class WebGPUInterface {
|
||||
device.pushErrorScope(this.enums.ErrorFilter[filterInt]);
|
||||
},
|
||||
|
||||
/**
|
||||
* @param {number} deviceIdx
|
||||
* @param {number} callbackPtr
|
||||
* @param {number} userdata
|
||||
*/
|
||||
wgpuDeviceSetUncapturedErrorCallback: (deviceIdx, callbackPtr, userdata) => {
|
||||
const device = this.devices.get(deviceIdx);
|
||||
const callback = this.mem.exports.__indirect_function_table.get(callbackPtr);
|
||||
|
||||
device.onuncapturederror = (ev) => {
|
||||
console.warn(ev.error);
|
||||
let status = 4;
|
||||
if (error instanceof GPUValidationError) {
|
||||
status = 1;
|
||||
} else if (error instanceof GPUOutOfMemoryError) {
|
||||
status = 2;
|
||||
} else if (error instanceof GPUInternalError) {
|
||||
status = 3;
|
||||
}
|
||||
callback(status, null, userdata);
|
||||
};
|
||||
},
|
||||
|
||||
...this.devices.interface(true),
|
||||
|
||||
/* ---------------------- Instance ---------------------- */
|
||||
@@ -2646,23 +2652,23 @@ class WebGPUInterface {
|
||||
const formatStr = navigator.gpu.getPreferredCanvasFormat();
|
||||
const format = this.enums.TextureFormat.indexOf(formatStr);
|
||||
|
||||
this.mem.storeUint(capabilitiesPtr + this.mem.intSize, 1);
|
||||
this.mem.storeUint(capabilitiesPtr + 8, 1);
|
||||
const formatAddr = this.mem.exports.wgpu_alloc(4);
|
||||
this.mem.storeI32(formatAddr, format);
|
||||
this.mem.storeI32(capabilitiesPtr + this.mem.intSize*2, formatAddr);
|
||||
this.mem.storeI32(capabilitiesPtr + 8 + this.mem.intSize, formatAddr);
|
||||
|
||||
// NOTE: present modes don't seem to actually do anything in JS, we can just give back a default FIFO though.
|
||||
this.mem.storeUint(capabilitiesPtr + this.mem.intSize*3, 1);
|
||||
this.mem.storeUint(capabilitiesPtr + 8 + this.mem.intSize*2, 1);
|
||||
const presentModesAddr = this.mem.exports.wgpu_alloc(4);
|
||||
this.mem.storeI32(presentModesAddr, 0);
|
||||
this.mem.storeI32(capabilitiesPtr + this.mem.intSize*4, presentModesAddr);
|
||||
this.mem.storeI32(capabilitiesPtr + 8 + this.mem.intSize*3, presentModesAddr);
|
||||
|
||||
// Browser seems to support opaque (1) and premultiplied (2).
|
||||
this.mem.storeUint(capabilitiesPtr + this.mem.intSize*5, 2);
|
||||
this.mem.storeUint(capabilitiesPtr + 8 + this.mem.intSize*4, 2);
|
||||
const alphaModesAddr = this.mem.exports.wgpu_alloc(8);
|
||||
this.mem.storeI32(alphaModesAddr + 0, 1); // Opaque.
|
||||
this.mem.storeI32(alphaModesAddr + 4, 2); // premultiplied.
|
||||
this.mem.storeI32(capabilitiesPtr + this.mem.intSize*6, alphaModesAddr);
|
||||
this.mem.storeI32(capabilitiesPtr + 8 + this.mem.intSize*5, alphaModesAddr);
|
||||
},
|
||||
|
||||
/**
|
||||
@@ -2680,17 +2686,6 @@ class WebGPUInterface {
|
||||
// TODO: determine suboptimal and/or status.
|
||||
},
|
||||
|
||||
/**
|
||||
* @param {number} surfaceIdx
|
||||
* @param {number} texturePtr
|
||||
* @returns {number}
|
||||
*/
|
||||
wgpuSurfaceGetPreferredFormat: (surfaceIdx, adapterIdx) => {
|
||||
const formatStr = navigator.gpu.getPreferredCanvasFormat();
|
||||
const format = this.enums.TextureFormat.indexOf(formatStr);
|
||||
return format;
|
||||
},
|
||||
|
||||
/**
|
||||
* @param {number} surfaceIdx
|
||||
*/
|
||||
|
||||
164
vendor/wgpu/wgpu.odin
vendored
164
vendor/wgpu/wgpu.odin
vendored
@@ -13,7 +13,7 @@ when ODIN_OS == .Windows {
|
||||
@(private) LIB :: "lib/wgpu-windows-" + ARCH + "-" + TYPE + "/wgpu_native" + EXT
|
||||
|
||||
when !#exists(LIB) {
|
||||
#panic("Could not find the compiled WGPU Native library at '" + #directory + LIB + "', these can be downloaded from https://github.com/gfx-rs/wgpu-native/releases/tag/v0.19.4.1, make sure to read the README at '" + #directory + "vendor/wgpu/README.md'")
|
||||
#panic("Could not find the compiled WGPU Native library at '" + #directory + LIB + "', these can be downloaded from https://github.com/gfx-rs/wgpu-native/releases/tag/v22.1.0.1, make sure to read the README at '" + #directory + "vendor/wgpu/README.md'")
|
||||
}
|
||||
|
||||
foreign import libwgpu {
|
||||
@@ -34,7 +34,7 @@ when ODIN_OS == .Windows {
|
||||
@(private) LIB :: "lib/wgpu-macos-" + ARCH + "-" + TYPE + "/libwgpu_native" + EXT
|
||||
|
||||
when !#exists(LIB) {
|
||||
#panic("Could not find the compiled WGPU Native library at '" + #directory + LIB + "', these can be downloaded from https://github.com/gfx-rs/wgpu-native/releases/tag/v0.19.4.1, make sure to read the README at '" + #directory + "vendor/wgpu/README.md'")
|
||||
#panic("Could not find the compiled WGPU Native library at '" + #directory + LIB + "', these can be downloaded from https://github.com/gfx-rs/wgpu-native/releases/tag/v22.1.0.1, make sure to read the README at '" + #directory + "vendor/wgpu/README.md'")
|
||||
}
|
||||
|
||||
foreign import libwgpu {
|
||||
@@ -49,7 +49,7 @@ when ODIN_OS == .Windows {
|
||||
@(private) LIB :: "lib/wgpu-linux-" + ARCH + "-" + TYPE + "/libwgpu_native" + EXT
|
||||
|
||||
when !#exists(LIB) {
|
||||
#panic("Could not find the compiled WGPU Native library at '" + #directory + LIB + "', these can be downloaded from https://github.com/gfx-rs/wgpu-native/releases/tag/v0.19.4.1, make sure to read the README at '" + #directory + "vendor/wgpu/README.md'")
|
||||
#panic("Could not find the compiled WGPU Native library at '" + #directory + LIB + "', these can be downloaded from https://github.com/gfx-rs/wgpu-native/releases/tag/v22.1.0.1, make sure to read the README at '" + #directory + "vendor/wgpu/README.md'")
|
||||
}
|
||||
|
||||
foreign import libwgpu {
|
||||
@@ -220,7 +220,8 @@ CullMode :: enum i32 {
|
||||
|
||||
DeviceLostReason :: enum i32 {
|
||||
Undefined = 0x00000000,
|
||||
Destroyed = 0x00000001,
|
||||
Unknown = 0x00000001,
|
||||
Destroyed = 0x00000002,
|
||||
}
|
||||
|
||||
ErrorFilter :: enum i32 {
|
||||
@@ -264,6 +265,30 @@ FeatureName :: enum i32 {
|
||||
PipelineStatisticsQuery,
|
||||
StorageResourceBindingArray,
|
||||
PartiallyBoundBindingArray,
|
||||
TextureFormat16bitNorm,
|
||||
TextureCompressionAstcHdr,
|
||||
// TODO: requires wgpu.h api change
|
||||
// TimestampQueryInsidePasses,
|
||||
MappablePrimaryBuffers = 0x0003000E,
|
||||
BufferBindingArray,
|
||||
UniformBufferAndStorageTextureArrayNonUniformIndexing,
|
||||
// TODO: requires wgpu.h api change
|
||||
// AddressModeClampToZero,
|
||||
// AddressModeClampToBorder,
|
||||
// PolygonModeLine,
|
||||
// PolygonModePoint,
|
||||
// ConservativeRasterization,
|
||||
// ClearTexture,
|
||||
// SprivShaderPassThrough,
|
||||
// MultiView,
|
||||
VertexAttribute64bit = 0x00030019,
|
||||
TextureFormatNv12,
|
||||
RayTracingAccelarationStructure,
|
||||
RayQuery,
|
||||
ShaderF64,
|
||||
ShaderI16,
|
||||
ShaderPrimitiveIndex,
|
||||
ShaderEarlyDepthTest,
|
||||
}
|
||||
|
||||
FilterMode :: enum i32 {
|
||||
@@ -520,6 +545,18 @@ TextureFormat :: enum i32 {
|
||||
ASTC12x10UnormSrgb = 0x0000005D,
|
||||
ASTC12x12Unorm = 0x0000005E,
|
||||
ASTC12x12UnormSrgb = 0x0000005F,
|
||||
|
||||
// Native.
|
||||
|
||||
// From FeatureName.TextureFormat16bitNorm
|
||||
R16Unorm = 0x00030001,
|
||||
R16Snorm,
|
||||
Rg16Unorm,
|
||||
Rg16Snorm,
|
||||
Rgba16Unorm,
|
||||
Rgba16Snorm,
|
||||
// From FeatureName.TextureFormatNv12
|
||||
NV12,
|
||||
}
|
||||
|
||||
TextureSampleType :: enum i32 {
|
||||
@@ -581,13 +618,13 @@ VertexStepMode :: enum i32 {
|
||||
VertexBufferNotUsed = 0x00000002,
|
||||
}
|
||||
|
||||
// WGSLFeatureName :: enum i32 {
|
||||
// Undefined = 0x00000000,
|
||||
// ReadonlyAndReadwriteStorageTextures = 0x00000001,
|
||||
// Packed4x8IntegerDotProduct = 0x00000002,
|
||||
// UnrestrictedPointerParameters = 0x00000003,
|
||||
// PointerCompositeAccess = 0x00000004,
|
||||
// }
|
||||
WGSLFeatureName :: enum i32 {
|
||||
Undefined = 0x00000000,
|
||||
ReadonlyAndReadwriteStorageTextures = 0x00000001,
|
||||
Packed4x8IntegerDotProduct = 0x00000002,
|
||||
UnrestrictedPointerParameters = 0x00000003,
|
||||
PointerCompositeAccess = 0x00000004,
|
||||
}
|
||||
|
||||
BufferUsage :: enum i32 {
|
||||
MapRead = 0x00000000,
|
||||
@@ -634,22 +671,18 @@ TextureUsage :: enum i32 {
|
||||
}
|
||||
TextureUsageFlags :: bit_set[TextureUsage; Flags]
|
||||
|
||||
|
||||
BufferMapAsyncCallback :: #type proc "c" (status: BufferMapAsyncStatus, /* NULLABLE */ userdata: rawptr)
|
||||
ShaderModuleGetCompilationInfoCallback :: #type proc "c" (status: CompilationInfoRequestStatus, compilationInfo: ^CompilationInfo, /* NULLABLE */ userdata: rawptr)
|
||||
DeviceCreateComputePipelineAsyncCallback :: #type proc "c" (status: CreatePipelineAsyncStatus, pipeline: ComputePipeline, message: cstring, /* NULLABLE */ userdata: rawptr)
|
||||
DeviceCreateRenderPipelineAsyncCallback :: #type proc "c" (status: CreatePipelineAsyncStatus, pipeline: RenderPipeline, message: cstring, /* NULLABLE */ userdata: rawptr)
|
||||
Proc :: distinct rawptr
|
||||
|
||||
DeviceLostCallback :: #type proc "c" (reason: DeviceLostReason, message: cstring, userdata: rawptr)
|
||||
ErrorCallback :: #type proc "c" (type: ErrorType, message: cstring, userdata: rawptr)
|
||||
|
||||
Proc :: distinct rawptr
|
||||
|
||||
QueueOnSubmittedWorkDoneCallback :: #type proc "c" (status: QueueWorkDoneStatus, /* NULLABLE */ userdata: rawptr)
|
||||
InstanceRequestAdapterCallback :: #type proc "c" (status: RequestAdapterStatus, adapter: Adapter, message: cstring, /* NULLABLE */ userdata: rawptr)
|
||||
AdapterRequestDeviceCallback :: #type proc "c" (status: RequestDeviceStatus, device: Device, message: cstring, /* NULLABLE */ userdata: rawptr)
|
||||
|
||||
// AdapterRequestAdapterInfoCallback :: #type proc "c" (adapterInfo: AdapterInfo, /* NULLABLE */ userdata: rawptr)
|
||||
BufferMapAsyncCallback :: #type proc "c" (status: BufferMapAsyncStatus, /* NULLABLE */ userdata: rawptr)
|
||||
DeviceCreateComputePipelineAsyncCallback :: #type proc "c" (status: CreatePipelineAsyncStatus, pipeline: ComputePipeline, message: cstring, /* NULLABLE */ userdata: rawptr)
|
||||
DeviceCreateRenderPipelineAsyncCallback :: #type proc "c" (status: CreatePipelineAsyncStatus, pipeline: RenderPipeline, message: cstring, /* NULLABLE */ userdata: rawptr)
|
||||
InstanceRequestAdapterCallback :: #type proc "c" (status: RequestAdapterStatus, adapter: Adapter, message: cstring, /* NULLABLE */ userdata: rawptr)
|
||||
QueueOnSubmittedWorkDoneCallback :: #type proc "c" (status: QueueWorkDoneStatus, /* NULLABLE */ userdata: rawptr)
|
||||
ShaderModuleGetCompilationInfoCallback :: #type proc "c" (status: CompilationInfoRequestStatus, compilationInfo: ^CompilationInfo, /* NULLABLE */ userdata: rawptr)
|
||||
|
||||
ChainedStruct :: struct {
|
||||
next: ^ChainedStruct,
|
||||
@@ -661,28 +694,23 @@ ChainedStructOut :: struct {
|
||||
sType: SType,
|
||||
}
|
||||
|
||||
// AdapterInfo :: struct {
|
||||
// next: ^ChainedStructOut,
|
||||
// vendor: cstring,
|
||||
// architecture: cstring,
|
||||
// device: cstring,
|
||||
// description: cstring,
|
||||
// backendType: BackendType,
|
||||
// adapterType: AdapterType,
|
||||
// vendorID: u32,
|
||||
// deviceID: u32,
|
||||
// }
|
||||
|
||||
AdapterProperties :: struct {
|
||||
AdapterInfo :: struct {
|
||||
nextInChain: ^ChainedStructOut,
|
||||
vendorID: u32,
|
||||
vendorName: cstring,
|
||||
vendor: cstring,
|
||||
architecture: cstring,
|
||||
deviceID: u32,
|
||||
name: cstring,
|
||||
driverDescription: cstring,
|
||||
adapterType: AdapterType,
|
||||
device: cstring,
|
||||
description: cstring,
|
||||
backendType: BackendType,
|
||||
adapterType: AdapterType,
|
||||
vendorID: u32,
|
||||
deviceID: u32,
|
||||
}
|
||||
when ODIN_OS == .JS {
|
||||
#assert(int(BackendType.WebGPU) == 2)
|
||||
#assert(offset_of(AdapterInfo, backendType) == 20)
|
||||
|
||||
#assert(int(AdapterType.Unknown) == 3)
|
||||
#assert(offset_of(AdapterInfo, adapterType) == 24)
|
||||
}
|
||||
|
||||
BindGroupEntry :: struct {
|
||||
@@ -943,6 +971,7 @@ StorageTextureBindingLayout :: struct {
|
||||
|
||||
SurfaceCapabilities :: struct {
|
||||
nextInChain: ^ChainedStructOut,
|
||||
usages: TextureUsageFlags,
|
||||
formatCount: uint,
|
||||
formats: /* const */ [^]TextureFormat `fmt:"v,formatCount"`,
|
||||
presentModeCount: uint,
|
||||
@@ -950,6 +979,16 @@ SurfaceCapabilities :: struct {
|
||||
alphaModeCount: uint,
|
||||
alphaModes: /* const */ [^]CompositeAlphaMode `fmt:"v,alphaModeCount"`,
|
||||
}
|
||||
when ODIN_OS == .JS {
|
||||
#assert(offset_of(SurfaceCapabilities, formatCount) == 8)
|
||||
#assert(offset_of(SurfaceCapabilities, formats) == 8 + 1*size_of(int))
|
||||
|
||||
#assert(offset_of(SurfaceCapabilities, presentModeCount) == 8 + 2*size_of(int))
|
||||
#assert(offset_of(SurfaceCapabilities, presentModes) == 8 + 3*size_of(int))
|
||||
|
||||
#assert(offset_of(SurfaceCapabilities, alphaModeCount) == 8 + 4*size_of(int))
|
||||
#assert(offset_of(SurfaceCapabilities, alphaModes) == 8 + 5*size_of(int))
|
||||
}
|
||||
|
||||
SurfaceConfiguration :: struct {
|
||||
nextInChain: ^ChainedStruct,
|
||||
@@ -1040,6 +1079,12 @@ TextureViewDescriptor :: struct {
|
||||
aspect: TextureAspect,
|
||||
}
|
||||
|
||||
UncapturedErrorCallbackInfo :: struct {
|
||||
nextInChain: ^ChainedStruct,
|
||||
callback: ErrorCallback,
|
||||
userdata: rawptr,
|
||||
}
|
||||
|
||||
VertexAttribute :: struct {
|
||||
format: VertexFormat,
|
||||
offset: u64,
|
||||
@@ -1120,12 +1165,21 @@ ProgrammableStageDescriptor :: struct {
|
||||
RenderPassColorAttachment :: struct {
|
||||
nextInChain: ^ChainedStruct,
|
||||
/* NULLABLE */ view: TextureView,
|
||||
// depthSlice: u32,
|
||||
depthSlice: u32,
|
||||
/* NULLABLE */ resolveTarget: TextureView,
|
||||
loadOp: LoadOp,
|
||||
storeOp: StoreOp,
|
||||
clearValue: Color,
|
||||
}
|
||||
when ODIN_OS == .JS {
|
||||
#assert(size_of(RenderPassColorAttachment) == 56)
|
||||
#assert(offset_of(RenderPassColorAttachment, view) == 4)
|
||||
#assert(offset_of(RenderPassColorAttachment, depthSlice) == 8)
|
||||
#assert(offset_of(RenderPassColorAttachment, resolveTarget) == 12)
|
||||
#assert(offset_of(RenderPassColorAttachment, loadOp) == 16)
|
||||
#assert(offset_of(RenderPassColorAttachment, storeOp) == 20)
|
||||
#assert(offset_of(RenderPassColorAttachment, clearValue) == 24)
|
||||
}
|
||||
|
||||
RequiredLimits :: struct {
|
||||
nextInChain: ^ChainedStruct,
|
||||
@@ -1194,6 +1248,10 @@ DeviceDescriptor :: struct {
|
||||
defaultQueue: QueueDescriptor,
|
||||
deviceLostCallback: DeviceLostCallback,
|
||||
deviceLostUserdata: rawptr,
|
||||
uncapturedErrorCallbackInfo: UncapturedErrorCallbackInfo,
|
||||
}
|
||||
when ODIN_OS == .JS {
|
||||
#assert(offset_of(DeviceDescriptor, deviceLostCallback) == 24 + size_of(int))
|
||||
}
|
||||
|
||||
RenderPassDescriptor :: struct {
|
||||
@@ -1245,16 +1303,18 @@ foreign libwgpu {
|
||||
// Methods of Adapter
|
||||
@(link_name="wgpuAdapterEnumerateFeatures")
|
||||
RawAdapterEnumerateFeatures :: proc(adapter: Adapter, features: [^]FeatureName) -> uint ---
|
||||
@(link_name="wgpuAdapterGetInfo")
|
||||
RawAdapterGetInfo :: proc(adapter: Adapter, info: ^AdapterInfo) ---
|
||||
@(link_name="wgpuAdapterGetLimits")
|
||||
RawAdapterGetLimits :: proc(adapter: Adapter, limits: ^SupportedLimits) -> b32 ---
|
||||
@(link_name="wgpuAdapterGetProperties")
|
||||
RawAdapterGetProperties :: proc(adapter: Adapter, properties: ^AdapterProperties) ---
|
||||
AdapterHasFeature :: proc(adapter: Adapter, feature: FeatureName) -> b32 ---
|
||||
// AdapterRequestAdapterInfo :: proc(adapter: Adapter, callback: AdapterRequestAdapterInfoCallback, /* NULLABLE */ userdata: rawptr) ---
|
||||
AdapterRequestDevice :: proc(adapter: Adapter, /* NULLABLE */ descriptor: /* const */ ^DeviceDescriptor, callback: AdapterRequestDeviceCallback, /* NULLABLE */ userdata: rawptr = nil) ---
|
||||
AdapterReference :: proc(adapter: Adapter) ---
|
||||
AdapterRelease :: proc(adapter: Adapter) ---
|
||||
|
||||
// Procs of AdapterInfo
|
||||
AdapterInfoFreeMembers :: proc(adapterInfo: AdapterInfo) ---
|
||||
|
||||
// Methods of BindGroup
|
||||
BindGroupSetLabel :: proc(bindGroup: BindGroup, label: cstring) ---
|
||||
BindGroupReference :: proc(bindGroup: BindGroup) ---
|
||||
@@ -1348,13 +1408,12 @@ foreign libwgpu {
|
||||
DevicePopErrorScope :: proc(device: Device, callback: ErrorCallback, userdata: rawptr) ---
|
||||
DevicePushErrorScope :: proc(device: Device, filter: ErrorFilter) ---
|
||||
DeviceSetLabel :: proc(device: Device, label: cstring) ---
|
||||
DeviceSetUncapturedErrorCallback :: proc(device: Device, callback: ErrorCallback, userdata: rawptr) ---
|
||||
DeviceReference :: proc(device: Device) ---
|
||||
DeviceRelease :: proc(device: Device) ---
|
||||
|
||||
// Methods of Instance
|
||||
InstanceCreateSurface :: proc(instance: Instance, descriptor: /* const */ ^SurfaceDescriptor) -> Surface ---
|
||||
// InstanceHasWGSLLanguageFeature :: proc(instance: Instance, feature: WGSLFeatureName) -> b32 ---
|
||||
InstanceHasWGSLLanguageFeature :: proc(instance: Instance, feature: WGSLFeatureName) -> b32 ---
|
||||
InstanceProcessEvents :: proc(instance: Instance) ---
|
||||
InstanceRequestAdapter :: proc(instance: Instance, /* NULLABLE */ options: /* const */ ^RequestAdapterOptions, callback: InstanceRequestAdapterCallback, /* NULLABLE */ userdata: rawptr = nil) ---
|
||||
InstanceReference :: proc(instance: Instance) ---
|
||||
@@ -1455,9 +1514,8 @@ foreign libwgpu {
|
||||
RawSurfaceGetCapabilities :: proc(surface: Surface, adapter: Adapter, capabilities: ^SurfaceCapabilities) ---
|
||||
@(link_name="wgpuSurfaceGetCurrentTexture")
|
||||
RawSurfaceGetCurrentTexture :: proc(surface: Surface, surfaceTexture: ^SurfaceTexture) ---
|
||||
SurfaceGetPreferredFormat :: proc(surface: Surface, adapter: Adapter) -> TextureFormat ---
|
||||
SurfacePresent :: proc(surface: Surface) ---
|
||||
// SurfaceSetLabel :: proc(surface: Surface, label: cstring) ---
|
||||
SurfaceSetLabel :: proc(surface: Surface, label: cstring) ---
|
||||
SurfaceUnconfigure :: proc(surface: Surface) ---
|
||||
SurfaceReference :: proc(surface: Surface) ---
|
||||
SurfaceRelease :: proc(surface: Surface) ---
|
||||
@@ -1500,8 +1558,8 @@ AdapterGetLimits :: proc(adapter: Adapter) -> (limits: SupportedLimits, ok: bool
|
||||
return
|
||||
}
|
||||
|
||||
AdapterGetProperties :: proc(adapter: Adapter) -> (properties: AdapterProperties) {
|
||||
RawAdapterGetProperties(adapter, &properties)
|
||||
AdapterGetInfo :: proc(adapter: Adapter) -> (info: AdapterInfo) {
|
||||
RawAdapterGetInfo(adapter, &info)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -1634,8 +1692,8 @@ SurfaceGetCurrentTexture :: proc(surface: Surface) -> (surface_texture: SurfaceT
|
||||
|
||||
// WGPU Native bindings
|
||||
|
||||
BINDINGS_VERSION :: [4]u8{0, 19, 4, 1}
|
||||
BINDINGS_VERSION_STRING :: "0.19.4.1"
|
||||
BINDINGS_VERSION :: [4]u8{22, 1, 0, 1}
|
||||
BINDINGS_VERSION_STRING :: "22.1.0.1"
|
||||
|
||||
when ODIN_OS != .JS {
|
||||
@(private="file", init)
|
||||
|
||||
Reference in New Issue
Block a user