1. FFI question for Gregg
- Posted by ChrisB (moderator) Mar 05, 2023
- 1707 views
Hi Gregg
Andy's SDL2 wrapper worked in the first version but unfortunately I seem to be getting an out of memory error. Not sure if there was something I was missing. Here's a bare minimum program that demos the issue.
--minimal setup to demo memory issue with ffi --uses SDL, but will just get relevant structure created include std/ffi.e include std/machine.e include std/math.e public constant SDL_RELEASED = 0 public constant SDL_PRESSED = 1 public enum type SDL_EventType SDL_FIRSTEVENT = 0, -- /**< Unused (do not remove) */ SDL_QUIT = 0x100, --/**< User-requested quit */ --/* These application events have special meaning on iOS, see README-ios.md for details */ SDL_APP_TERMINATING, -- /**< The application is being terminated by the OS -- Called on iOS in applicationWillTerminate() -- Called on Android in onDestroy() -- */ SDL_APP_LOWMEMORY, -- /**< The application is low on memory, free memory if possible. -- Called on iOS in applicationDidReceiveMemoryWarning() -- Called on Android in onLowMemory() -- */ SDL_APP_WILLENTERBACKGROUND,-- /**< The application is about to enter the background -- Called on iOS in applicationWillResignActive() -- Called on Android in onPause() --*/ SDL_APP_DIDENTERBACKGROUND, --/**< The application did enter the background and may not get CPU for some time -- Called on iOS in applicationDidEnterBackground() -- Called on Android in onPause() --*/ SDL_APP_WILLENTERFOREGROUND, --/**< The application is about to enter the foreground -- Called on iOS in applicationWillEnterForeground() -- Called on Android in onResume() --*/ SDL_APP_DIDENTERFOREGROUND, --/**< The application is now interactive -- Called on iOS in applicationDidBecomeActive() -- Called on Android in onResume() -- */ SDL_LOCALECHANGED, SDL_DISPLAYEVENT = 0x150, SDL_WINDOWEVENT = 0x200, SDL_SYSWMEVENT, SDL_KEYDOWN = 0x300, SDL_KEYUP, SDL_TEXTEDITING, SDL_TEXTINPUT, SDL_KEYMAPCHANGED, SDL_TEXTEDITING_EXT, SDL_MOUSEMOTION = 0x400, SDL_MOUSEBUTTONDOWN, SDL_MOUSEBUTTONUP, SDL_MOUSEWHEEL, SDL_JOYAXISMOTION = 0x600, SDL_JOYBALLMOTION, SDL_JOYHATMOTION, SDL_JOYBUTTONDOWN, SDL_JOYBUTTONUP, SDL_JOYDEVICEADDED, SDL_JOYDEVICEREMOVED, SDL_JOYBATTERYUPDATED, SDL_CONTROLLERAXISMOTION = 0x650, SDL_CONTROLLERBUTTONDOWN, SDL_CONTROLLERBUTTONUP, SDL_CONTROLLERDEVICEADDED, SDL_CONTROLLERDEVICEREMOVED, SDL_CONTROLLERDEVICEREMAPPED, SDL_CONTROLLERTOUCHPADDOWN, SDL_CONTROLLERTOUCHPADMOTION, SDL_CONTROLLERTOUCHPADUP, SDL_CONTROLLERSENSORUPDATE, SDL_FINGERDOWN = 0x700, SDL_FINGERUP, SDL_FINGERMOTION, SDL_DOLLARGESTURE = 0x800, SDL_DOLLARRECORD, SDL_MULTIGESTURE, SDL_CLIPBOARDUPDATE = 0x900, SDL_DROPFILE = 0x1000, SDL_DROPTEXT, SDL_DROPBEGIN, SDL_DROPCOMPLETE, SDL_AUDIODEVICEADDED = 0x1100, SDL_AUDIODEVICEREMOVED, SDL_SENSORUPDATE = 0x1200, SDL_RENDER_TARGETS_RESET = 0x2000, SDL_RENDER_DEVICE_RESET, SDL_POLLSENTINEL = 0x7F00, --/** Events ::SDL_USEREVENT through ::SDL_LASTEVENT are for your use, --* and should be allocated with SDL_RegisterEvents() --*/ SDL_USEREVENT = 0x8000, --/** -- * This last event is only for bounding internal arrays -- */ SDL_LASTEVENT = 0xFFFF end type public constant SDL_CommonEvent = define_c_struct({ C_UINT32, --type C_UINT32 --timestamp }) public constant SDL_DisplayEvent = define_c_struct({ C_UINT32, --type C_UINT32, --timestamp C_UINT32, --display C_UINT8, --event --C_UINT8, --padding1 --C_UINT8, --padding2 --C_UINT8, --padding3 C_INT32 --data1 }) public constant SDL_WindowEvent = define_c_struct({ C_UINT32, --type C_UINT32, --timestamp C_UINT32, --windowID C_UINT8, --event --C_UINT8, --padding1 --C_UINT8, --padding2 --C_UINT8, --padding3 C_INT32, --data1 C_INT32 --data2 }) public constant SDL_KeyboardEvent = define_c_struct({ C_UINT32, --type [1] C_UINT32, --timestamp [2] C_UINT32, --windowID [3] C_UINT8, --state [4] C_UINT8 --repeat [5] --C_UINT8, --padding2 [6] --C_UINT8, --padding3 [7] --SDL_Keysym --key that was pressed or released [8] }) public constant SDL_TEXTEDITINGEVENT_TEXT_SIZE = 32 public constant SDL_TextEditingEvent = define_c_struct({ C_UINT32, --type C_UINT32, --timestamp C_UINT32, --windowID C_CHAR, --text C_INT32, --start C_INT32 --length }) public constant SDL_TextEditingExtEvent = define_c_struct({ C_UINT32, --type C_UINT32, --timestamp C_UINT32, --windowID C_STRING, --text C_INT32, --start C_INT32 --length }) public constant SDL_TEXTINPUTEVENT_TEXT_SIZE = 32 public constant SDL_TextInputEvent = define_c_struct({ C_UINT32, --type C_UINT32, --timestamp C_UINT32, --windowID C_CHAR --text }) public constant SDL_MouseMotionEvent = define_c_struct({ C_UINT32, --type C_UINT32, --timestamp C_UINT32, --windowID C_UINT32, --which C_INT32, --x C_INT32, --y C_INT32, --xrel C_INT32 --yrel }) public constant SDL_MouseButtonEvent = define_c_struct({ C_UINT32, --type C_UINT32, --timestamp C_UINT32, --windowID C_UINT32, --which C_UINT8, --button C_UINT8, --state C_UINT8, --clicks C_UINT8, --padding1 C_INT32, --x C_INT32 --y }) public constant SDL_MouseWheelEvent = define_c_struct({ C_UINT32, --type C_UINT32, --timestamp C_UINT32, --windowID C_UINT32, --which C_INT32, --x C_INT32, --y C_UINT32, --direction C_FLOAT, --precisex C_FLOAT, --precisey C_INT32, --mouseX C_INT32 --mouseY }) public constant SDL_JoyAxisEvent = define_c_struct({ C_UINT32, --type C_UINT32, --timestamp C_LONG, --joystick id which C_UINT8, --axis C_UINT8, --padding1 C_UINT8, --padding2 C_UINT8, --padding3 C_INT16, --value C_UINT16 --padding4 }) public constant SDL_JoyBallEvent = define_c_struct({ C_UINT32, --type C_UINT32, --timestamp C_LONG, --joystick id which C_UINT8, --ball C_UINT8, --padding1 C_UINT8, --padding2 C_UINT8, --padding3 C_INT16, --xrel C_INT16 --yrel }) public constant SDL_JoyHatEvent = define_c_struct({ C_UINT32, --type C_UINT32, --timestamp C_LONG, --joystick id which C_UINT8, --hat C_UINT8, --value C_UINT8, --padding1 C_UINT8 --padding2 }) public constant SDL_JoyButtonEvent = define_c_struct({ C_UINT32, --type C_UINT32, --timestamp C_LONG, --joystick id which C_UINT8, --button C_UINT8, --state C_UINT8, --padding1 C_UINT8 --padding2 }) public constant SDL_JoyDeviceEvent = define_c_struct({ C_UINT32, --type C_UINT32, --timestamp C_INT32 --which }) public constant SDL_JoyBatteryEvent = define_c_struct({ C_UINT32, --type C_UINT32, --timestamp C_LONG, --joystick which C_INT --joystick powerlevel }) public constant SDL_ControllerAxisEvent = define_c_struct({ C_UINT32, --type C_UINT32, --timestamp C_LONG, --joystickid which C_UINT8, --axis --C_UINT8, --padding1 --C_UINT8, --padding2 --C_UINT8, --padding3 C_INT16, --value C_UINT16 --padding4 }) public constant SDL_ControllerButtonEvent = define_c_struct({ C_UINT32, --type C_UINT32, --timestamp C_LONG, --joystickid which C_UINT8, --button C_UINT8, --state C_UINT8, --padding1 C_UINT8 --padding2 }) public constant SDL_ControllerDeviceEvent = define_c_struct({ C_UINT32, --type C_UINT32, --timestamp C_INT32 --which }) public constant SDL_ControllerTouchpadEvent = define_c_struct({ C_UINT32, --type C_UINT32, --timestamp C_LONG, --joystickid which C_INT32, --touchpad C_INT32, --finger C_FLOAT, --x C_FLOAT, --y C_FLOAT --pressure }) public constant SDL_ControllerSensorEvent = define_c_struct({ C_UINT32, --type C_UINT32, --timestamp C_LONG, --joystickid which C_INT32, --sensor {C_FLOAT,3}, --data (array of 3) C_UINT64 --timestamp of sensor reading in microseconds, if hardware supports info }) public constant SDL_AudioDeviceEvent = define_c_struct({ C_UINT32, --type C_UINT32, --timestamp C_UINT32, --which C_UINT8, --icapture C_UINT8, --padding1 C_UINT8, --padding2 C_UINT8 --padding3 }) public constant SDL_TouchFingerEvent = define_c_struct({ C_UINT32, --type C_UINT32, --timestamp C_LONG, --touchID C_LONG, --fingerID C_FLOAT, --x C_FLOAT, --y C_FLOAT, --dx C_FLOAT, --dy C_FLOAT, --pressure C_UINT32 --windowID }) public constant SDL_MultiGestureEvent = define_c_struct({ C_UINT32, --type C_UINT32, --timestamp C_LONG, --touchID C_FLOAT, --dTheta C_FLOAT, --dDist C_FLOAT, --x C_FLOAT, --y C_UINT16, --numFingers C_UINT16 --padding }) public constant SDL_DollarGestureEvent = define_c_struct({ C_UINT32, --type C_UINT32, --timestamp C_LONG, --touchID C_LONG, --gestureID C_UINT32, --numFingers C_FLOAT, --error C_FLOAT, --x C_FLOAT --y }) public constant SDL_DropEvent = define_c_struct({ C_UINT32, --type C_UINT32, --timestamp C_POINTER, --file C_UINT32 --windowID }) public constant SDL_SensorEvent = define_c_struct({ C_UINT32, --type C_UINT32, --timestamp C_INT32, --which {C_FLOAT,6}, --data C_UINT64 --timestamp of sensor reading in microseconds }) public constant SDL_QuitEvent = define_c_struct({ C_UINT32, --type C_UINT32 --timestamp }) public constant SDL_OSEvent = define_c_struct({ C_UINT32, --type C_UINT32 --timestamp }) public constant SDL_UserEvent = define_c_struct({ C_UINT32, --type C_UINT32, --timestamp C_UINT32, --windowID C_INT32, --code C_POINTER, --data1 C_POINTER --data2 }) public constant SDL_SysWMEvent = define_c_struct({ C_UINT32, --type C_UINT32, --timestamp C_POINTER --msg }) --=================================================================== public constant SDL_Event = define_c_struct({ C_UINT32, --type [1] SDL_CommonEvent, --[2] SDL_DisplayEvent, --[3] SDL_WindowEvent, --[4] SDL_KeyboardEvent, --[5] SDL_TextEditingEvent, --[6] SDL_TextEditingExtEvent, --[7] SDL_TextInputEvent, --[8] SDL_MouseMotionEvent, --[9] SDL_MouseButtonEvent, --[10] SDL_MouseWheelEvent, --[11] SDL_JoyAxisEvent, --[12] SDL_JoyBallEvent, --[13] SDL_JoyHatEvent, --[14] SDL_JoyButtonEvent, --[15] SDL_JoyDeviceEvent, --[16] SDL_JoyBatteryEvent, --[17] SDL_ControllerAxisEvent, --[18] SDL_ControllerButtonEvent, --[19] SDL_ControllerDeviceEvent, --[20] SDL_ControllerTouchpadEvent, --[21] SDL_ControllerSensorEvent, --[22] SDL_AudioDeviceEvent, --[23] SDL_SensorEvent, --[24] SDL_QuitEvent, --[25] SDL_UserEvent, --[26] SDL_SysWMEvent, --[27] SDL_TouchFingerEvent, --[28] SDL_MultiGestureEvent, --[29] SDL_DollarGestureEvent, --[30] SDL_DropEvent --[31] }) atom event_ptr = allocate_struct(SDL_Event) atom event_type
produces the error
1795457776 couldn't alloc 1795457776 bytes C:\EuProgramming\Euphoria4_1\libffi-euphoria\include\std\ffi.e:780 in function a llocate_struct() Your program has run out of memory. One moment please...
I made some small mods to you ffi.e
public function allocate_mem(atom block_size) return machine_func( M_ALLOC, block_size ) end function public procedure free(atom mem) return machine_func( M_FREE, mem ) end procedure /*,ade the followin small changes 34 - public added to constant declaration 262 - public function allocate_string( sequence s, integer cleanup = 0 ) --abd made public atom mem = machine_func( M_ALLOC, length(s) + 1 ) if mem then poke( mem, s ) poke( mem+length(s), 0 ) end if if cleanup then end if return mem end function -- added cleanup for compatabilty with eu --added pubic functions allocate_mem and free */
but I can't see how these would be an issue.
Anyway, ideas?
Cheers
Chris
2. Re: FFI question for Gregg
- Posted by Icy_Viking Mar 05, 2023
- 1720 views
I got the same error when I tried renaming the variables myself. So I went back to the old version of FFI. Its probably an easy fix. Might have to do with the 32 and 64-bit versions of the DLLs. Or something to do with how 32-bit and 64-bit memory is handled.
3. Re: FFI question for Gregg
- Posted by ghaberek (admin) Mar 05, 2023
- 1685 views
Andy's SDL2 wrapper worked in the first version but unfortunately I seem to be getting an out of memory error. Not sure if there was something I was missing. Here's a bare minimum program that demos the issue.
(snip)
produces the error
1795457776 couldn't alloc 1795457776 bytes C:\EuProgramming\Euphoria4_1\libffi-euphoria\include\std\ffi.e:780 in function a llocate_struct() Your program has run out of memory. One moment please...
Good catch! That was definitely a bug. When creating a copy of the C_POINTER type for C_STRING it incorrectly overwrote the copied data with default values and this caused it to try and allocate a pointer's value worth of bytes. (Oops.) I've corrected in now. See commit #cfbf236.
Very important! Make sure you are now using define_c_union() for union types. This ensures the members "collapse" correctly so they all start at zero offset. Then use the nested types in the union to "typecast" the union when you peek/poke the members (see my example below). If you use define_c_struct() each of the members will be aligned sequentially in memory which is not what you want. You can see this if you print the sizeof() result. On my system (64-bit Ubuntu) using define_c_union() the sizeof(SDL_Event) is 24 bytes but using define_c_struct() the sizeof(SDL_Event) is 800 bytes!
-- declare the union public constant SDL_Event = define_c_union({ C_UINT32, --type [1] -- (lots of types here) }) -- allocate the memory atom event = allocate_struct( SDL_Event ) -- (event loop or something here) -- "typecast" the union to SDL_CommonEvent to get common members atom eventtype = peek_member( event, SDL_CommonEvent, 1 ) atom timestamp = peek_member( event, SDL_CommonEvent, 2 ) if eventtype = SDL_DISPLAYEVENT then -- "typecast" the union to SDL_DisplayEvent to read its members atom displayid = peek_member( event, SDL_DisplayEvent, 3 ) atom dispevent = peek_member( event, SDL_DisplayEvent, 4 ) elsif eventtype = SDL_WINDOWEVENT then -- "typecast" the union to SDL_WindowEvent to read its members atom windowid = peek_member( event, SDL_WindowEvent, 3 ) atom winevent = peek_member( event, SDL_WindowEvent, 4 ) elsif eventtype = SDL_KEYDOWN or eventtype = SDL_KEYUP then -- "typecast" the union to SDL_KeyboardEvent to read its members atom windowid = peek_member( event, SDL_KeyboardEvent, 3 ) atom keystate = peek_member( event, SDL_KeyboardEvent, 4 ) atom keyrepeat = peek_member( event, SDL_KeyboardEvent, 5 ) else -- etc. end if free( event )
I made some small mods to you ffi.e
(snip)
but I can't see how these would be an issue.
Don't bother modifying any of the boilerplate code inside of std/ffi.e. It's only there because I need to be keep std/ffi.e free of include statements to ensure my code doesn't inherit any side-effects from (or cause any side-effects to) the standard library. Once this goes into Euphoria all of that will go away and I will be using the standard library routines again. You should just use std/machine.e, std/types.e, etc.
-Greg
4. Re: FFI question for Gregg
- Posted by Icy_Viking Mar 05, 2023
- 1662 views
Thanks for the help, Greg. I've updated my SDL 2 wrapper with the new define_c_struct and define_c_union types. I did test and the example programs were working.
5. Re: FFI question for Gregg
- Posted by ChrisB (moderator) Mar 06, 2023
- 1653 views
Thanks.
Cheers
Chris
6. Re: FFI question for Gregg
- Posted by ChrisB (moderator) Mar 06, 2023
- 1647 views
Hi Gregg
FFI's definition of allocate_string takes one parameter, and the std's definition takes two,
ffi - allocate_string(sequence string) std - allocate_string(sequence string, boolean clean)
Chris
7. Re: FFI question for Gregg
- Posted by ghaberek (admin) Mar 06, 2023
- 1619 views
FFI's definition of allocate_string takes one parameter, and the std's definition takes two,
ffi - allocate_string(sequence string) std - allocate_string(sequence string, boolean clean)
Sure, but the distinction is irrelevant. The code in std/ffi.e that allocates strings always calls free() on them later. If I had a cleanup parameter it would never get used. It's not meant to be a complete replacement for the standard library function; it's just enough to avoid repeating myself. The places where that is used will end up in the backend which uses its own C methods for allocating strings.
-Greg
8. Re: FFI question for Gregg
- Posted by ChrisB (moderator) Mar 06, 2023
- 1613 views
Hi
The distinction arises when it's called, and there are two parameters, an error is thrown complaining about too many parameters. I realise that the same thing happens (as far as allocate_string), hence why I put 'if clean then end if' in there. The functionality is still the same, in that the second parameter if used is just discarded.
Thanks for all this work by the way.
Cheers
Chris
9. Re: FFI question for Gregg
- Posted by ghaberek (admin) Mar 06, 2023
- 1590 views
The distinction arises when it's called, and there are two parameters, an error is thrown complaining about too many parameters. I realise that the same thing happens (as far as allocate_string), hence why I put 'if clean then end if' in there. The functionality is still the same, in that the second parameter if used is just discarded.
My point is that you shouldn't even be seeing it and you shouldn't care that it's there. When you include std/ffi.e its version of allocate_string() is not public so you'll never see it. Just leave it alone and use std/machine.e if you need allocate_string().
-Greg
10. Re: FFI question for Gregg
- Posted by ChrisB (moderator) Mar 08, 2023
- 1353 views
Ah, ok.
Cheers
Chris