#zig-sdl3: A Zig Wrapper For SDL3
1 messages · Page 2 of 1
@mellow sedge https://github.com/Gota7/zig-sdl3/pull/100
There seems to be no way to create a pull request for 'adding a branch'. This pull request is not supposed to be merged, instead a branch should be created from this pull request.
will look at later, thnx
Where is the flake lock? Forgot to commit it maybe?
Also do the tests run the examples or something? Because I'm still sus about how your getting that flake to work atm lol
Yeah, I forgot to commit it with the flake.nix and then I didn't want to have a whole commit just for the lock.
I will commit it once I get on my PC.
And, no, tests do not run the examples. But example run almost fine to me.
For some reason SDL isn't able to initialize if I run from any nix shell.
Did you try to use the flake by the way?
You can just ammend a commit, just as long as others aren't using the brach it's usually fine imo
No I can try out your branch after work today, won't be too long
Sure.
What do you mean by this though?
Yep that seems better
What's the rec needed for there?
(Not saying it isn't needed I'm not sure myself)
Without rec it's an error error: undefined variable 'buildInputs'.
Oh yeah makes sense
I just kind of copied it from my friends flake. https://github.com/xor-bits/hiillos/blob/master/flake.nix
?
Any example I run is error.SdlError.
Though wait, it's no longer about the nix shell. Apparently it does not work from my normal shell, but works if I run it from VSCode?
That's cursed.
It isn't cursed
What your seeing is that you haven't got the right build deps
Why would it work in VSCode though 🤔
The reason it is working from VSCode is because VSCode uses a FHS environment or whatever iirc
It isn't isolated
Look at my flake I linked above and see the deps in my ld path and see which are needed, I haven't trimmed them down I took mine from another project of mine I had made it for earlier and just kept them all in
I am not in the nix shell, not sure if this is related.
Your flake actually needs to declare all the build dependencies which it is linking against
Yeah, I know about it.
Oh, right, I also need to fix the template. Thank you for reminding.
@hard sparrow , yep, thank you, now it works properly. https://github.com/Gota7/zig-sdl3/pull/100/commits/20c047fc52affd5135f5577fd42f2e81ad000aa5
You should probably refer to the GitHub commit or something, not my Discord message ahahaha
You shouldn't really need to refer to a Discord message, it might not exist forever you know
Someone looking might not have a Discord account either
True...
Out of curiosity gota you know how you added some nice logging to the template example, howcome you don't just have that nice logging be the default so people don't have to copy paste it in their projects? They also might not know they can do that, iirc not all the examples have the extra logging
It's the default, no?
Because I didn't do anything. xD
Oh, sorry, I misread. Didn't notice the 'gota'.
No that's all good aha I just wanted to clarify what I was talking about
Make extra functionality to wrap SDL logs with zig's log system as well as error messages.
this is actually planned lol
where I'll probably put in an extras lib a built-in log function that can be easily used, as well as another log function that would forward to zig logs
I really don't want to force my defaults on anyone though and would rather just forward SDL and have any extras be opt-in/explicitly used (which is why the functions will be in an extras subsystem and you'd have to still call sdl3.log.setLogOutputFunction() and sdl3.errors.error_callback yourself
Yeah that'd be good
I see what you mean
I think the extra logging info tho is really useful
Uhm, can this library compile to android?
I mean that feature has not been added yet so it doesn't really compile to anything yet
yeah, I figured it out the hard way already
I currently have 13 event structs left to wrap, after that it shouldn't take me long to wrap all of the SDL events properly
once events are done I'll work on some of the issues for 1.0.0 and 1.1.0 because I'd rather work on literally anything else than the hints subsystem
What's so bad about hints?
https://wiki.libsdl.org/SDL3/CategoryHints there are so many, each with different acceptable values (SDL punts them as strings but I want to use types propertly), and ofc writing the docs for each hint as well
I legit don't know if I can do this without doing some form of at least partial automation because of just the tediousness and size
Tbf hints are probably less useful than whatever else you decide to work on
true lol
I could help you tomorrow if you want (it's 12 pm for me rn)
I mean sure do as many as the hints as you like lol
I can try helping but I don't have a github account.
They're free
Also 2 event datatypes left, events will definitely be done tonight or sometime tomorrow but most likely tomorrow
I'd say the lack of events are the only real thing making using zig-sdl3 impractical so I'm happy about that
What do you think you'll add next after your events and cleanup? Audio mixer or something?
(Just curious)
Idk if mixer for sdl3 is released yet
I was going to document image and probably look into shadercross outside of random issues
There is a release on GitHub at the least
oh neat
shadercross more of a priority though tbh bc most people care about GPU I think lol
Yeah very fair
I probably would've favoured it if it was ported to Zig build system and wrapped tbh
Might have a few big deps to port along with it?
Yeah that part might be hard with the big deps
Someone has ported it already but they didn't port all the deps themselves, and I think someone mentioned that mach dxcompiler is out of date or something
https://github.com/Beyley/SDL_shadercross_zig
the SDL project loves having lots of big deps
Ooo nice that there is work on this already
once zig 15 is released, it might be neat to wrap SDL's IO and async IO for zig using the new IO interface
Reminder. I think it hangs for a bit too long already.
merged and added as dev
man this events thing is taking longer than expected
so close yet so far
is it tedious manual work so everything is typed properly?
that really sucks
yeah, the main insult is that I have 4 places I need to go through each event pretty much
1 for defining all the event types
1 for mapping event types to the proper struct
1 for converting the SDL event to the zig event for every event
and 1 for converting every zig event to SDL event for every event
I got 2 of the 4 places done at least
Nice!
ITS DONE
events is finally done
only hints remains
being able to see the suggestions for the tagged union is so satisfying
I'm happy recommending zig-sdl3 to people now
events was the main thing you really couldn't do and that's not great given most of SDL is event driven
the API may change a bit while I smooth some things out but other than that and potential bugs (and ofc unfinished extensions) it's basically done
a lot of the stuff remaining other than extension libs is polish
Honestly I'm just tempted to punt hints like sdl does. Don't have inline docs or type hints properly and just link you to the wiki
I think that's what I'll do bc I really don't want to do this. Someone else can if they want but unless I hear strong reasons why wrapping hints properly with inline docs is necessary I'll punt it like sdl does
I want this to come out faster and digging into hints rather than something people cares about seems like a waste of time
For a subsystem that gets called 3~4 times per program, I think it's fair
Events now on zig-master. No changes were needed, fortunately.
Didn't even need to rebase, just cherry-picked it.
I also always use Zig master, so I appreciate your effort!
Also congrats @broken bluff on finishing everything (except hints).
If you used zig-master branch, does it work well for you? Just want to make sure.
I haven't had a chance to try it yet. I'll let you know when I do.
Since I'm punting hints, all the subsystems will be done tonight!
0.1.0 is coming out this weekend :>
@shut tree for the zig-master branch could you delete the docs job and update the test job to use the correct zig version?
Done. Had to bump setup-zig to v2. (https://github.com/mlugg/setup-zig/issues/44), but now it should pass.
epic, thnx
yippee!
honestly sometimes SDL feels like it was designed by aliens or something
Yeahhh the pro of making a wrapper api is you get to reinterpret some of the more... interesting design choices
I don't get it either they are using a tagged union anyways USE THE TAGGED UNION
fr
And properties can go to hell
i mean i guess properties are because "oh we need to add new fields without breaking ABI"
i hate dynamic linking.
Ah yeah true
but even so they picked such a convoluted way to do it
Yeah I'd rather they use pointers for all properties or something
And have an array of fixed size and an unused property for the future is just blank in the slot
Actually this doesn't do much
Hm
what i would do is like
have the properties field be a pointer to a plain array of key/value pairs
or something like that
the point is it would be something you can declare inline using Designated Initializers
(this is one reason i like sokol better api-wise. floooh actually knows that designated initializers exist and the api is designed around that fact)
(and really if you're targeting anything older than c99 you're doing something wrong)
I think that's a good approach
@broken bluff https://github.com/Gota7/zig-sdl3/pull/101
looks good to me, you can merge it now if you want
(otherwise I'll merge when I get the chance)
so I just put the part of the hearder with all the defines in a text file and than ran this script I made on it, good enough :p
with open('hints.txt', 'r') as ins:
with open('hints_out.txt', 'w') as outs:
tags = []
for line in ins:
if line.startswith('#define'):
parts = line.split(' ')
tag = parts[1].replace('SDL_HINT_', '').lower()
outs.write(f'{tag},\n')
tags.append((tag, parts[1]))
outs.write('\n/// Convert to an SDL value.\n')
outs.write('pub fn toSdl(self: Type) [*c]const u8 {\n')
outs.write('\treturn switch (self) {\n')
for tag in tags:
outs.write(f'\t\t.{tag[0]} => c.{tag[1]},\n')
outs.write('\t};\n')
outs.write('}\n')
just double checking all the other functions before I mark hints as done
THERE WE GO, LAST SUBSYSTEM DONE
now I'm documenting the image subsystem
Will get on zig-master as soon as I can.
Yeah ik I need to fix the templat and I have a fix for it just haven't been able to push
so close...
originally the frame rate capper wasn't planned for this but I already started work on it since it makes sense to use for examples so the CPU isn't constantly burning lol
unfortunately I'm not good at writing frame rate capper code it seems, mostly functional just have some things to iron out about it
I've been having so much trouble getting the custom allocator to work
these are my callbacks for SDL, and they look correct so I'm not sure what's wrong?
/// Custom allocator to use for `setMemoryFunctionsByAllocator()`.
var custom_allocator: std.mem.Allocator = undefined;
const Allocation = struct {
size: usize,
};
fn allocationSize(request_size: usize) usize {
var size: usize = request_size;
if (size < 1)
size = 1;
while (size % @min(@sizeOf(@cImport(@cInclude("stddef.h")).max_align_t), @sizeOf(?*anyopaque) * 2) != 0) // TODO: Optimize this?
size += 1;
return size;
}
fn makeAllocation(total_size: usize, comptime memset: bool) ?*anyopaque {
const total_buf = custom_allocator.alloc(u8, allocationSize(total_size) + @sizeOf(Allocation)) catch return null;
if (memset)
@memset(total_buf, 0);
const allocation: *Allocation = @ptrCast(@alignCast(total_buf.ptr));
allocation.size = total_buf.len;
const data_ptr: *anyopaque = @ptrFromInt(@intFromPtr(total_buf.ptr) + @sizeOf(Allocation));
// std.debug.print("MAKE PTR: {p}, {d}\n", .{ data_ptr, allocation.size });
return data_ptr;
}
fn allocCalloc(num_members: usize, size: usize) callconv(.c) ?*anyopaque {
return makeAllocation(num_members * size, true);
}
fn allocFree(mem: ?*anyopaque) callconv(.c) void {
const raw_ptr = mem orelse return;
const allocation: *Allocation = @ptrFromInt(@intFromPtr(mem) - @sizeOf(Allocation));
// std.debug.print("CLEAR PTR: {p}, {d}\n", .{ raw_ptr, allocation.size });
custom_allocator.free(@as([*]u8, @ptrCast(raw_ptr))[0..allocation.size]);
}
fn allocMalloc(size: usize) callconv(.c) ?*anyopaque {
return makeAllocation(size, false);
}
fn allocRealloc(mem: ?*anyopaque, size: usize) callconv(.c) ?*anyopaque {
const raw_ptr = mem orelse return allocMalloc(size);
// const allocation: *Allocation = @alignCast(@fieldParentPtr("buf", @as(*void, @ptrCast(raw_ptr))));
allocFree(raw_ptr);
return allocMalloc(size);
// const total_buf = custom_allocator.realloc(@as([*]u8, @ptrCast(raw_ptr))[0..allocation.size], allocationSize(size) + @sizeOf(Allocation)) catch return null;
// allocation = @ptrCast(@alignCast(total_buf.ptr));
// allocation.size = total_buf.len;
// return &allocation.buf;
}
what's especially funny is that if I try and use the C allocator I get this:
❯ zig build run -Dexample=custom_allocator -Dc_sdl_sanitize_c=full
MAKE PTR: anyopaque@2317a2a8, 24
MAKE PTR: anyopaque@2317a2c8, 72
MAKE PTR: anyopaque@2317a318, 104
MAKE PTR: anyopaque@2317a388, 56
MAKE PTR: anyopaque@2317a3c8, 56
MAKE PTR: anyopaque@2317a408, 40
MAKE PTR: anyopaque@2317a438, 1032
MAKE PTR: anyopaque@2317a848, 24
MAKE PTR: anyopaque@2317a868, 200
CLEAR PTR: anyopaque@2317a318, 104
free(): invalid pointer
run
└─ run custom_allocator failure
error: the following command terminated unexpectedly:
/home/gota/Documents/Zig/SDL3/zig-out/bin/custom_allocator
Build Summary: 28/30 steps succeeded; 1 failed
run transitive failure
└─ run custom_allocator failure
error: the following build command failed with exit code 1:
/home/gota/Documents/Zig/SDL3/.zig-cache/o/af9a13d54bdb3f5077ec3a908244d46a/build /home/gota/Apps/zig-x86_64-linux-0.14.1/zig /home/gota/Apps/zig-x86_64-linux-0.14.1/lib /home/gota/Documents/Zig/SDL3 /home/gota/Documents/Zig/SDL3/.zig-cache /home/gota/.cache/zig --seed 0x3729cd45 -Zb69b279c5beeb924 run -Dexample=custom_allocator -Dc_sdl_sanitize_c=full
we can see very clearly that the address being freed has been allocated perfectly fine
so who knows really
you're freeing raw_ptr but that's offset ahead by the allocation size
holy shot was that really it
ok I'm closer, now I get this:
❯ zig build run -Dexample=custom_allocator -Dc_sdl_sanitize_c=full
Illegal instruction at address 0x160f73e
/home/gota/.cache/zig/p/sdl-0.2.5+3.2.18-7uIn9FwZfwHKOwSubcg5_CiW4fXag5IIsiV_jnLdkpDM/src/video/SDL_video.c:1007:58: 0x160f73e in SDL_GetDisplayIndex (/home/gota/.cache/zig/p/sdl-0.2.5+3.2.18-7uIn9FwZfwHKOwSubcg5_CiW4fXag5IIsiV_jnLdkpDM/src/video/SDL_video.c)
if (displayID == _this->displays[display_index]->id) {
^
/home/gota/.cache/zig/p/sdl-0.2.5+3.2.18-7uIn9FwZfwHKOwSubcg5_CiW4fXag5IIsiV_jnLdkpDM/src/video/SDL_video.c:976:21: 0x160fc82 in SDL_GetVideoDisplay (/home/gota/.cache/zig/p/sdl-0.2.5+3.2.18-7uIn9FwZfwHKOwSubcg5_CiW4fXag5IIsiV_jnLdkpDM/src/video/SDL_video.c)
display_index = SDL_GetDisplayIndex(displayID);
^
/home/gota/.cache/zig/p/sdl-0.2.5+3.2.18-7uIn9FwZfwHKOwSubcg5_CiW4fXag5IIsiV_jnLdkpDM/src/video/SDL_video.c:1031:33: 0x160e692 in SDL_GetDisplayProperties_REAL (/home/gota/.cache/zig/p/sdl-0.2.5+3.2.18-7uIn9FwZfwHKOwSubcg5_CiW4fXag5IIsiV_jnLdkpDM/src/video/SDL_video.c)
SDL_VideoDisplay *display = SDL_GetVideoDisplay(displayID);
^
/home/gota/.cache/zig/p/sdl-0.2.5+3.2.18-7uIn9FwZfwHKOwSubcg5_CiW4fXag5IIsiV_jnLdkpDM/src/video/SDL_video.c:882:13: 0x160dfc2 in SDL_AddVideoDisplay (/home/gota/.cache/zig/p/sdl-0.2.5+3.2.18-7uIn9FwZfwHKOwSubcg5_CiW4fXag5IIsiV_jnLdkpDM/src/video/SDL_video.c)
props = SDL_GetDisplayProperties(id);
^
/home/gota/.cache/zig/p/sdl-0.2.5+3.2.18-7uIn9FwZfwHKOwSubcg5_CiW4fXag5IIsiV_jnLdkpDM/src/video/x11/SDL_x11modes.c:507:9: 0x1a6616f in X11_AddXRandRDisplay (/home/gota/.cache/zig/p/sdl-0.2.5+3.2.18-7uIn9FwZfwHKOwSubcg5_CiW4fXag5IIsiV_jnLdkpDM/src/video/x11/SDL_x11modes.c)
if (SDL_AddVideoDisplay(&display, send_event) == 0) {
^
/home/gota/.cache/zig/p/sdl-0.2.5+3.2.18-7uIn9FwZfwHKOwSubcg5_CiW4fXag5IIsiV_jnLdkpDM/src/video/x11/SDL_x11modes.c:768:22: 0x1a60f75 in X11_InitModes_XRandR (/home/gota/.cache/zig/p/sdl-0.2.5+3.2.18-7uIn9FwZfwHKOwSubcg5_CiW4fXag5IIsiV_jnLdkpDM/src/video/x11/SDL_x11modes.c)
if (!X11_AddXRandRDisplay(_this, dpy, screen, res->outputs[output], res, false)) {
^
/home/gota/.cache/zig/p/sdl-0.2.5+3.2.18-7uIn9FwZfwHKOwSubcg5_CiW4fXag5IIsiV_jnLdkpDM/src/video/x11/SDL_x11modes.c:881:13: 0x1a6067f in X11_InitModes (/home/gota/.cache/zig/p/sdl-0.2.5+3.2.18-7uIn9FwZfwHKOwSubcg5_CiW4fXag5IIsiV_jnLdkpDM/src/video/x11/SDL_x11modes.c)
X11_InitModes_XRandR(_this)) {
^
/home/gota/.cache/zig/p/sdl-0.2.5+3.2.18-7uIn9FwZfwHKOwSubcg5_CiW4fXag5IIsiV_jnLdkpDM/src/video/x11/SDL_x11video.c:406:10: 0x19fdd87 in X11_VideoInit (/home/gota/.cache/zig/p/sdl-0.2.5+3.2.18-7uIn9FwZfwHKOwSubcg5_CiW4fXag5IIsiV_jnLdkpDM/src/video/x11/SDL_x11video.c)
if (!X11_InitModes(_this)) {
^
/home/gota/.cache/zig/p/sdl-0.2.5+3.2.18-7uIn9FwZfwHKOwSubcg5_CiW4fXag5IIsiV_jnLdkpDM/src/video/SDL_video.c:700:10: 0x160a1a3 in SDL_VideoInit (/home/gota/.cache/zig/p/sdl-0.2.5+3.2.18-7uIn9FwZfwHKOwSubcg5_CiW4fXag5IIsiV_jnLdkpDM/src/video/SDL_video.c)
if (!_this->VideoInit(_this)) {
^
/home/gota/.cache/zig/p/sdl-0.2.5+3.2.18-7uIn9FwZfwHKOwSubcg5_CiW4fXag5IIsiV_jnLdkpDM/src/SDL.c:357:18: 0x15e4cc6 in SDL_InitSubSystem_REAL (/home/gota/.cache/zig/p/sdl-0.2.5+3.2.18-7uIn9FwZfwHKOwSubcg5_CiW4fXag5IIsiV_jnLdkpDM/src/SDL.c)
if (!SDL_VideoInit(NULL)) {
^
/home/gota/.cache/zig/p/sdl-0.2.5+3.2.18-7uIn9FwZfwHKOwSubcg5_CiW4fXag5IIsiV_jnLdkpDM/src/SDL.c:534:12: 0x15e5a02 in SDL_Init_REAL (/home/gota/.cache/zig/p/sdl-0.2.5+3.2.18-7uIn9FwZfwHKOwSubcg5_CiW4fXag5IIsiV_jnLdkpDM/src/SDL.c)
return SDL_InitSubSystem(flags);
```
thnx though that was a really good catch idk how I missed that lol
it looks like I got the FPS capper working at least :>
has 2 modes, one for setting to a given FPS and one for just acting unlimited
the delay function in unlimited mode will essentially just give the dt, basically you have 3 options:
- Unlimited FPS (There really is never a good reason to do this except for "benchmarks" and that's a stretch)
- Unlimited FPS, but the renderer or GPU is vsync limited so this works well for getting
dtand observed FPS - Limited FPS (Good for having the user set the FPS, basically mandatory if vsync is not available)
I find it really strange that SDL by default has no good way of managing FPS? Getting the dt is one of the most important parts of any game loop
and unless you are explicitly going out of your way to enable vsync, or have an application that is event-driven rather than frame-driven, then by default you're running at unlimited FPS and maxing out your CPU which is definitely not great for beginners, even the official SDL3 examples just ignore this problem! The default SDL3 examples just have you burn CPU and battery!
https://examples.libsdl.org/SDL3/renderer/08-rotating-textures/ for example, this example here does per-frame updates but they don't even try to set vsync and how they spin the texture relative to the frame time is definitely more of a hack than what anyone would practically do when making an FPS-driven app or game
I think this is bad practice personally and I'll be using the FPS limiter extra for the renderer examples when I get to them, as you want a beginner to be doing the right thing by default. No one new to SDL is going to practically know about CPU time, and what if they never even heard of the concept of dt welp have fun explaining to them how to get it themselves and delay properly
I'll also update the template to have an FPS debug counter or something on the top right
(and yes vsync is disabled by default)
I wrote something in the SDL server about my concerns with the examples and frame limiting, I suppose I'll wait to hear back
The app callbacks aren't permanently running though
Its logic depends on the platform; on ios and android it uses the OS's own callbacks to decide when it's time to make a frame
so the battery usage is as good as possible
This is the logic for platforms that don't provide frame callbacks
this is my first time learning about
https://wiki.libsdl.org/SDL3/SDL_HINT_MAIN_CALLBACK_RATE
you would think they would use this in the examples though
also on my PC callbacks by default do run as fast as possible on the CPU
not great they removed functionality like that then out of nowhere 😬
SDL guys giving me shit saying I'm inventing a problem 
It'd probably better raise the issue on the actual github
Basically there are three possible solutions:
- callbacks shouldn't run as fast as possible by default
- vsync should be on by default
- examples should require vsync
it's up to the devs to decide which solution is appropriate (or if they don't care about laptops)
Did you share your code and explain CPU maxing out on your machine? That is a real problem
so far the responses have been along the lines of this lib isn't to cater to beginners, who's shipping a game that doesn't know about FPS caps
and that I'm overexaggerating the effects of just burning CPU lol as if handheld gaming isn't a big trend where idk you kinda want battery life???
I'll probably make an issue on the repo yeah
FPS counter and frame cap added to the template
I mostly just follow this article and implement this https://scribe.rip/@tglaiel/how-to-make-your-game-run-at-60fps-24c61210fe75
this is a nice article
I also remember this https://github.com/libsdl-org/SDL/issues/10160
this is a neat thread
I didn't know there were so many different methods of frame rate...
I've just be using variable all my life
(except for fixed-framerate on retro consoles)
yeah I'd ask the devs directly
not people who think they are elite programmers because they use SDL
also, I'm fairly certain most of everything outside desktop OSes has a callbacks impl that is synchronized with the display
it's also possible that laptop OSes are assumed to force vsync anyway?
Either way yeah, raising a descriptive issue with the actual problem and what might be acceptable solutions and letting the devs share their thoughts is the way to go about it
How are you supposed to save images with the sdl3 image wrapper?
I thought it'd just be this:
const image_stream = try sdl3.io_stream.Stream.initFromFile(full_path, .read_binary);
const image_surface = try sdl3.image.loadIo(image_stream, true);
try sdl3.image.savePng(image_surface, OUTPUT_PATH);
But it gives me an thread 259477 panic: applying zero offset to null pointer
thread 4567 panic: applying zero offset to null pointer
miniz.h:2619:39: 0x7f5ebf8fd6a5 in tdefl_compress_normal (IMG_png.c)
const mz_uint8 *pSrc_end = pSrc + num_bytes_to_process;
^
miniz.h:2782:10: 0x7f5ebf8fb751 in tdefl_compress (IMG_png.c)
if (!tdefl_compress_normal(d))
^
miniz.h:2802:41: 0x7f5ebf8fa8bb in tdefl_compress_buffer (IMG_png.c)
MZ_ASSERT(d->m_pPut_buf_func); return tdefl_compress(d, pIn_buf, &in_buf_size, NULL, NULL, flush);
^
miniz.h:2926:7: 0x7f5ebf8f752c in tdefl_write_image_to_png_file_in_memory_ex (IMG_png.c)
if (tdefl_compress_buffer(pComp, NULL, 0, TDEFL_FINISH) != TDEFL_STATUS_DONE) { MZ_FREE(pComp); MZ_FREE(out_buf.m_pBuf); return NULL; }
^
miniz.h:2967:10: 0x7f5ebf8f6e07 in tdefl_write_image_to_png_file_in_memory (IMG_png.c)
return tdefl_write_image_to_png_file_in_memory_ex(pImage, w, h, num_chans, bpl, pLen_out, 6, MZ_FALSE);
^
IMG_png.c:759:15: 0x7f5ebf8f665b in IMG_SavePNG_IO_miniz (IMG_png.c)
png = tdefl_write_image_to_png_file_in_memory(surface->pixels, surface->w, surface->h, SDL_BYTESPERPIXEL(surface->format), surface->pitch, &size);
^
IMG_png.c:808:18: 0x7f5ebf8f5ede in IMG_SavePNG_IO (IMG_png.c)
result = IMG_SavePNG_IO_miniz(surface, dst);
^
IMG_png.c:785:16: 0x7f5ebf8f5e4c in IMG_SavePNG (src/IMG_png.c)
return IMG_SavePNG_IO(surface, dst, 1);
^
image.zig:1221:30: 0x10e6c4e in savePng (pppp)
const ret = c.IMG_SavePNG(
^
atlas_pack.zig:79:31: 0x10e76b5 in main (pppp)
try sdl3.image.savePng(image_surface, OUTPUT_PATH);
^
you're hitting an UBSan trap because it's adding 0 to a null pointer. in this code snippet is probably fine in practice but it's technically UB and therefore a bug in the miniz.h header
UBSan is enabled by default for Debug and ReleaseSafe builds, with how the zig-sdl3 build.zig is set up you can only disable it by building it in ReleaseFast/Small (i.e. pass .optimize = .ReleaseFast instead of optimize in your b.dependency("sdl3") call in your own build.zig)
a good contribution to zig-sdl3 would be to make it pass forward the c_sdl_sanitize_c option to the compile step that creates SDL_image
so that you can disable ubsan in debug builds
Wait but this is a bug right?
Don't you want it on?
it's a "bug" because the C spec says that null + 0 is undefined and that a compiler is free to handle that however it wants, but in practice every compiler in the world is going to handle it the same way
ubsan is very pedantic and doesn't differentiate between dangerous, always-bad UB and silly things like this
Wait so your saying the SDL_image code is fine but the problem is that zig-sdl3 doesn't turn off the sanitizing?
yes
So SDL_image shouldn't be changed to avoid UB?
I see that's really counter intuitive for me lol, I haven't written C code before so not sure about how UB works
If I did turn ubsan off wouldn't I miss other actual problems?
fixing it in SDL_image would be good too. I've run into similar ubsan traps in the main SDL in the past and I usually contribute an upstream fix that rewrites the code to avoid invoking UB
if you turn it off it won't catch other actual problems, but SDL_image is a mature enough library that it's probably not a problem
that you're even running into this is just because most C projects use bad compiler defaults and don't build with important warning/sanitization enabled
zig cc tries to improve upon status quo with more sane defaults, at the cost of annoyances like this if the code wasn't written taking warnings/UB into consideration
Is there a way to have them be warnings instead of errors?
Even if I contributed a fix it'd still take a while before the next release comes out and zig-sdl3 updates I assume
not from your own code, no. I haven't tested but it might be possible to log failures but not trap by passing -fsanitize=recover as a C flag when setting up SDL_image in zig-sdl3
but either way the most pragmatic fix for you right now is building zig-sdl3 in ReleaseFast, even in debug builds
Yeah I see okay
I'll try do that then soon
Thank you
I'm not sure I know how to rewrite this better, would it be worth me creating a GitHub issue or just posting in the Discord you reckon before I switch modes to ignore the problem?
I'd say ignore it. creating an issue in the SDL_image repo wouldn't hurt but if you're not familiar with compiling C it's probably difficult to reduce it down to a minimal repro for the maintainers without requiring them to use zig specifically. usually these are best handled by contributing a PR directly
I see that makes sense
I set it to release fast:
const atlas_mod = b.createModule(.{
.root_source_file = b.path("src/atlas_pack.zig"),
.target = target,
.optimize = .ReleaseFast,
});
But I still get the same error
wrong place, you pass it to the b.dependency call for zig-sdl3
Ohh makes sense mb
Yeah no longer get the error anymore thanks!
2 issues left until 0.1.0
Woo!
1 more
it's just the custom allocator example but it's not working at all and keeps crashing and I really can't figure this out :<
I might push that to 0.1.0
IT HAPPEND!
My next priority is getting shadercross and some hlsl examples working
Also some render examples would be good
please ignore the mach engine. i mistook the game-dev in mach channel for this i ment to send it here.
wow that was fast
are the sdl3 side libs not too hard to integrate then?
Integrating is the easiest part.
You need to also write the wrapper in this case.
For example, SDL_ttf.h is 3000 lines of code and it's really painful to write a wrapper for it.
You wrapped net right?
Nice that's cool
Out of curiosity have you automated transferring docs over or something or do you do that manually?
I write a Python script to generate the initial thing and then just tweaked that.
Though I still don't understand how I get files smaller than the original header.
Decided to also do SDL_ttf since I would probably need it too.
Anyone know off any examples loading a 3d object?
Like from gltf or obj or something
@shut tree you're insane lol thnx I'll review when I can
At this rate we might just skip 1.0.0 and go straight to 1.1.0 lol
@hard sparrow do you know anything about this [Gota7/zig-sdl3] Issue opened: #106 nix-os SdlError: No available video device (maybe add system integration?)
Ok that didn't work
There we go
https://github.com/Gota7/zig-sdl3/issues/106#issuecomment-3127725082 Should probably add flake to the master branch.
Yeah probably
(You can make a pull request if you like, otherwise I'll do it when I get home)
Sorry I missed your message but yeah looks like you got it
No worries
I saw that you wanted to add an android template/example, but the original castholm/SDL repo doesn't support android, so this might be useful to you (I also added iOS support if you need it):
https://github.com/mozbeel/SDL-zig
Thnx, I'll look into it
Glad to help!
@broken bluff , did changes some time ago addressing your review. :) https://github.com/Gota7/zig-sdl3/pull/105
Also, I realized we need to install examples/data so ttf example can actually run. It was in my local zig-out all this time. You can do it now or I'll do it myself tomorrow, it's 11 PM for me here already.
passed back MR
Thank you so much for creating it. you did so much better than I could. I guess i'll use this repo for my projects from now on.
Did you try to do that too?
yeah 😅 but didnt actively develop due to lack of time.
Alright, glad I could help!
I think you didn't know me. I am stark8421
Thank you for your Android template, It really did safe me alot of time
(and alot of pain)
I haven't been this glad in very long time. Glad it was useful.
Do anyone have any ideas on how to use shaders with sdl renderer? or is it impossible as of now?
I think there will eventually be a release which let's you specifically use fragment shaders with the Render API (not vertex)
That's what I've heard
ohh ok thanks for info.
I wrote this in game-dev but yea it's a thing already (SDL_CreateGPURenderState)
I think for the extension libs, it'd be nice to have a bring your own lib for them too
bc for my own development purposes I'd like to be able to load .kra files as textures
which would require my own fork of SDL_image
so a way to specify the SDL_image to use rather than the one in the zon would be useful
(I do basically all my artwork with Krita)
That's actually such a good idea
it really does makes dev time faster
I added zip reading functionality in my old engine just for it
Are there any zig examples or tutorials for working with gpu?
I'm going through a regular sdl tutorial, but really new to zig so having something to reference would be nice
The shaders are written with Zig though so I looked at the shaders from the regular tutorials and SDL3 code from here
I was wondering why you do all this pointer magic rather than just using memcpy?
const transfer_buffer_mapped = @as(
*@TypeOf(vertex_data),
@alignCast(@ptrCast(try ctx.device.mapTransferBuffer(transfer_buffer, false))),
);
transfer_buffer_mapped.* = vertex_data;
@as(*@TypeOf(index_data), @ptrFromInt(@intFromPtr(transfer_buffer_mapped) + vertex_data_size)).* = index_data;
https://github.com/Gota7/zig-sdl3-gpu-examples/blob/master/src/examples/textured_quad.zig#L189-L201
I tried to do something similar yesterday as you did and it worked when I hard coded the vertex and index buffers but as soon as I had them at runtime I started getting alignment errors (probably because the alignment of the vertices and indices are different ig, which doesn't seem to be a problem with memcpy with sliceAsBytes?)
What it looks like the other way:
const vertex_index_transfer_buffer_mapped = try device.mapTransferBuffer(vertex_index_transfer_buffer, false);
@memcpy(vertex_index_transfer_buffer_mapped, std.mem.sliceAsBytes(vertex_data));
@memcpy(vertex_index_transfer_buffer_mapped + vertex_data_size, std.mem.sliceAsBytes(index_data));
@broken bluff
yeah that's cleaner I forgot std.mem.sliceAsBytes exists tbh
you can make an MR for it if you like
Haha all good yeah it's a lot nicer because the as and ptr methods get really really long and confusing imo
Yeah sure will do later today or something
Just wondering if you started on sdl-shadercross yet or nah gota?
Nothing substantial, someone else is free to do it. I'm taking a short break from sdl stuff in general
Fair enough man!
Did you by any chance get it to build? If not that's all good, just wondering
If you got it built I can take a look and try work on bindings or something maybe, just not sure how to port the build to Zig myself
Nah I didn't get it built, I was copying some from someone else's port linked somewhere above in this thread
I just searched and found one by swan-www and one by Beyley, which one were you able to build with?
I didn't build any yet didn't get that far
Just started porting one into the repo but only a small amount
Oh you mean you hadn't actually started getting it running icic
How hard do you think it'd be for me to add one of those in?
Assuming the existing one works not to bad to copy it into the zig sdl3 build.zig
I'll give it a go then!
My aim is to just get it built and usable via the CLI
I heavily suggest to anyone who doesn't want to ship on Xbox to just disable DirectXShaderCompiler in SDL_shadercross. Then it becomes trivial to build. Just use the Vulkan backend on Windows
Okay thanks
Still will need to find a way to compile spirv cross iteslf though as SDL_shadercross depends on it
You mean SPIRV-Cross? I think you can just use this https://github.com/hexops/spirv-cross
It's still hard to build AFAIK but nowhere near the monstruosity that is DirectXShaderCompiler
Sweet thanks yeah typo
And for the record, if you don't plan to ship on Mac/iOS, you also don't need SDL_shadercross at all
Pure SPIR-V works perfectly on Windows and Linux (and I think Android) thanks to Vulkan
You'd just need SPIR-V reflect if you want it to check all the bindings for you. But I'm pretty sure that one is extremely trivial to build
Now if you want to use HLSL and not GLSL, I think you need something like shaderc or glslc to compile it. But it doesn't have to be DirectXShaderCompiler
SDL_shadercross is just a thin wrapper over DirectXShaderCompiler and SPIRV-Cross. It uses the former to compile HLSL to SPIR-V and then the latter to cross compile it to all the other GPU API formats
If you don't need the other formats, there is no use for SDL_shadercross. You can just compile your shader to SPIRV, use SPIRV-reflect (or just hardcode the bindings when creating the shader) and pass it to SDL GPU
Wait so your saying I don't even need SDL_shadercross to compile SPIR-V?
What's the easiest way to compile it from HLSL? HLSL is what I see all the examples written in online so I thought that'd be the best one to use
You don't need D3D12 unless shipping to Xbox because Vulkan works perfectly fine on Windows, and you don't need Metal if you don't want to ship to Mac/iOS.
If you only want Windows and Linux support, you can just compile your SPIR-V and use it normally and it will work
Nope, though it does enable all the fancy super modern HLSL features, because it uses DirectXShaderCompiler
There's tons of HLSL-to-SPIR-V compilers, you can just pick the one you like more. I can't really tell you which one is better because I do just use GLSL and glslangValidator
I see
So if I did just want to write GLSL then I should just use SDL_shadercross that's the easiest way to go about with that or is something like glslang easier to get working/compiled with Zig?
If you want to just write GLSL, just use glslang from the Vulkan SDK
Again SDL_shadercross is not needed at all unless you want to ship on consoles or Mac/iOS
Okay so I'm defs skipping it then
Same
Thank you so much I think you probably have saved me like a lot of time and effort haha
No problem!
I mostly want shadercross for integrating with the zig build system tbh
Would rather not translate at runtime
Yeah I wasn't gonna do that 🤣
Apparently DXC or whatever is a fork of LLVM or Clang or something lol
Ah yeah with Microsoft bs
Are there any samples showing how send uniform data?
I'm not sure but I can show you the code
At the start when you initialise a shader you tell it how many uniforms you want bound:
const vert_shader = try device.createShader(.{
...
.num_uniform_buffers = 1,
...
});
Then in your render pass before your draw call upload the data:
command_buffer.pushVertexUniformData(0, std.mem.sliceAsBytes(&model_matrix));
Much simpler than buffers or textures 
The docs say this: In practical terms this means you must ensure that vec3 and vec4 fields are 16-byte aligned.
The sdl tutorial I followed also uses a struct to hold a float value.
So how would you e.g. send two different floats?
You either combine them into a single uniform or you have multiple uniforms
I believe there are a limited number of binds you can make so it is ideal to combine (but I could be wrong)?
You can load a vector or matrix or whatever onto a uniform there is no problems with doing that btw
Does it need to be padded to be a multiple of 16 bytes?
If you are sending in the uniform everything as f32's then I do not see any reason why you need to be manually thinking about padding
For example I have three matrices which I bind to a single uniform:
const Transforms = struct {
model: zm.Mat,
view: zm.Mat,
projection: zm.Mat,
};
[[vk::binding(0, 1)]]
cbuffer Transforms {
float4x4 model;
float4x4 view;
float4x4 projection;
}
I don't do anything fancy to upload them either:
command_buffer.pushVertexUniformData(0, std.mem.asBytes(&transforms));
I'm just curious about the line that says std140 requires fields be 16-byte aligned
Afaik if you have your data in a struct, it will ensure the correct alignment is used when you are exposing bytes
ah ok
If you have two separate variables which do not have the same alignment and are not in a struct (i.e. probably because they are not comptime known size) and you want to combine them together, then you'd need to manually calculate the padding or whatever to fix the alignment
But that sounds hard and I haven't had to do that yet
But I don't think that's even relevant to uniforms in particular, you'd have the same issue with a buffer or texture or anything I'm pretty sure
What's the difference betweenasBytes and sliceAsBytes?
You can only use sliceAsBytes if you have a slice
If you have a struct then you use asBytes, although I'm guessing it could work for more than structs (haven't tried)?
Sorry maybe I should have asked in game-dev, this isn't really zigsdl3 specific anymore
It isn't really game dev specific either
I suppose not
Possibly you're not setting something up or not calling something you should be
do you have code that can be run to test?
Is there a reason why the swapchain texture struct is declared inline?
pub fn waitAndAcquireSwapchainTexture(
self: CommandBuffer,
window: video.Window,
) !struct { texture: ?Texture, width: u32, height: u32 }
@broken bluff
I mean it's just easier to do that for functions that return multiple things essentially
Could make a struct for everything but is there a reason to?
Fair enough
I thought I'd need to pass it around but turns out I was wrong
In worst case you could use the type info to get that struct, not the cleanest but it works
Yeah that's what I was gonna do
My only thing was it would've had ! error type
How are you supposed to handle errors with this wrapper?
Ok so trying to set uniform data like this doesn't seem valid when accessing b in the shader:
const UniformBuffer = packed struct {
a: f32,
b: @Vector(16, f32),
};
But adding padding so that b starts at 16 bytes seems to work.
const UniformBuffer = packed struct {
a: f32,
_padding: @Vector(3, f32),
b: @Vector(16, f32),
};
Don't use vector or packed struct instead of extern here, they both have very weird alignment/impl stuffs that will definitely bite you
you have an error callback you can set in the errors namespace as the example shows. Other than that, you can only really catch SdlError and use errors.get() as SDL uses strings for errors...
So it should be extern struct instead?
I'll be honest I don't really understand either of these keywords.
Why extern is needed you can normally just declare as pub
Unless you need to call it from C code?
packed really means bitpacked and puts all your fields in bits with no alignment into an integer while extern forces the struct to use the C abi
Vector is a SIMD primitive and has basically no implementation guarantees
if you're using non-zig shaders usually it's C abi I think
Wdym? I use just regular SPIR-V without any issues having a uniform in a normal struct although all the types are the same and size too so maybe that could be why?
So if not vector, []f32, or individual f32 fields instead?
Also the examples use packed and Vector for the vertex data. Is that also a problem?
Use [N]f32
I think it's fine in the shaders because they are then SPIR-V vectors but idk
@broken bluff , sorry for being inactive, I am back. First I'll get stuff on master then I'll try to finish the PR.
So can anyone clarify something on how uniform data works?
Basically I set up some uniforms for the fragment shader and pushed it using pushFragmentUniformData.
Then later also added the same uniform data to the vertex shader, but didn't add a corresponding pushVertexUniformData
And yet it still worked.
Np, I'll re review after work
When you copy a matrix [4][4]f32 with Zig onto GPU is it row or column major?
column major
Now that I'm back from vacation I'll look at that big MR again and start working on some 1.0.0 stuff
Saw https://poniesandlight.co.uk/reflect/debug_print_text/ in #game-dev a few months ago, decided to see if I could get it to work with SDL3 and HLSL+shadercross as a project to test this wrap and try SDL3. Worked beautifully, vert buffer is a bit chunky but not having to pre-render letters is nice.
Is v0.1.0 only compatible with 0.14.0, or also 0.14.1?
for the gpu stuff, everything else works fine
There shouldnt be a difference since 0.14.1 is bugfix
Hmm, is there anything obviously wrong in here?
https://zigbin.io/795197
I just grabbed the template from the main sdl3-zig repo and then swapped out some of the window and renderer creation stuff from one of the gpu examples, I was hoping to just get a window up and running.
Do zig shaders work with SDL shadercross?
Think you need zig nightly (0.15) for that
Must say this binding is very cool, but sadly I cant use it since theres an error in zig https://github.com/ziglang/zig/issues/24686
but eventualy it will work 😄
i just cleared all my zig caches and double checked. the current zig master branch fetches correctly. you might just have to update your zig version. i am now on 0.15.0-dev.1564+2761cc8be
i was trying to figure out zig shaders. how ever https://github.com/ziglang/zig/issues/24852 is blocking me :/ does anyone have a workaround for that one?
I don't think so. I think at this stage it's way better to just use GLSL shaders...
sorry i broke it recently. you can try this PR but regardless i don't recommend relying on spirv backend for now.
aww rip, okay
Also me: is out of town for the weekend lol
hf
I have a strange issue with RenderDoc and the sdl3 gpu API. When running through renderdoc the device creation fails. I get no vulkan validation errors or anything. When running the exe manually I have no issues at all. I use the callback template and create a device with debug enabled and spirv. Anyone else ran into this? Good to mention I'm on ubuntu.
never ran into that before
I suppose it's time to upgrade the master branch to zig 15 now, luckily that shouldn't take too long thnx to the helpful @ oh they are gone
Are you running in the right working directory?
Yes, I'll try later again today. I did see some open issues at renderdoc in regards of using Wayland, I might try using x11 instead.
I have the same issue
Also there is this issue on android platform. the gpu api with the wrapper, app crashes all the time in when sent to background. but it doesn't happen with raw c api that often why is that?
Hmm not sure, you would need to check the wrapper code, but I don't think it does anything else but calling the c api. I got renderdoc working using x11. So it seems wayland is not yet fully supported when using vulkan, see the following open issue on renderdoc: https://github.com/baldurk/renderdoc/issues/853
update to 0.15.1 coming this weekend
had basically 0 zig time this weekend lol so assuming I get my college stuff done tonight I have a lot of stuff I want to work on for zig-sdl3
ok so just merging the zig-master branch into the master branch has a bunch of merge conflicts and I'm not sure what to do
are there any git masters here that would know the best course of action for getting zig-sdl3 to 0.15.1 while taking advantage of the changes done in the zig-master branch
once this is updated to use 0.15.1 and I fix some bugs I'll release a 0.1.1
maybe cherry-picking
yeah I can do that
nice i will switch from the zig-master branch to 0.1.1 then :D
switched to 0.1.1 all gucci. thanks @broken bluff
Ye np
working on wrapping shadercross rn
once I finish wrapping it, I'll get started on porting GPU examples
each example will be a standalone file and executable
though the build script will build all of them and optionally run a target example
each shader will have an HLSL, GLSL, and zig equivalent
in addition to that, there will probably be another GPU example folder and build script exclusively for zig shaders using some tricks I learned for compile time reflection to verify CPU<->Vertex Shader<->Fragment Shader code and binding compatiblity
but the "normal GPU examples folder" would have zig shaders that just do exactly what the GLSL and HLSL ones do with not much else
I wrapped shadercross, now just need to get it built lol
So much looking forward to it 😃
alright, I think I got shadercross linked? I got the clear screen example working on the shadercross branch
Woo!
and yeah each example is stand-alone copy-paste using callbacks
huh apparently I need to compile shadercross with DXC in order to get HLSL to SPIRV? Interesting
Hi, just pulled the latest SDL3 Zig wrapper and got unlucky with a broken (as of 12 hours ago) hello-world.zig sample. I just sent a PR to fix it.
https://github.com/Gota7/zig-sdl3/pull/127
Fix the polling sample usage in hello-world.zig and the README.md to correctly break out of the infinite loop when closing the window.
It's my first time using Github to make a PR so hopefully I did it correctly. It seems right.
dang how did I miss this thanks
welp, shadercross reflecting for getting the SPIRV metadata is not appreciating the zig compiled SPIRV binary :p
spirv-tools suck ass on a whole. sorry
I wonder if I do an optimization pass on the SPIRV would fix it
as I need to do that anyways
very annoying that spirv-tools just gives up the second something is wrong though, just parse the thing
ah well
might not be a bad idea to steal https://github.com/ziglang/zig/blob/master/src/link/SpirV/BinaryModule.zig btw
see https://github.com/ziglang/zig/blob/master/src/link/SpirV/lower_invocation_globals.zig for usage example
so make my own implementation of the shadercross get SPIRV metadata?
I suppose that would be the only alternate option other than hardcoding some values if spirv-opt doesn't magically fix it
old spirv-opt
because your tool doesn't expect zig to exist
w h y
what kind of future proofing is that
yeah ik I need to update my version but still like what
k h r o n o s
how is this a problem that can be encountered, isn't the purpose of SPIRV to be language agnostic???
i suppose they expect you to put 0 (Unknown) in that case
just give me a warning don't error and abort everything :p
guess it's time how to figure out how to update these tools then
unfortunately I'm on debian 12
rip
ok if I update to trixie I'll get a 2025 version
I do want to upgrade my debian install but not sure if I have enough time atm to back everything up properly
I decided to upgrade to debian 13 anyways
luckily, debian is so good and reliable that it just worked without issues. I had a weird bug where the KDE apps list wouldn't show any of my apps but there was a single command I had to run and then it was fine
so yeah now spirv-opt seems to be doing its thing but unfortunately I still get that alignment error from reflection...
at least I know this is just a shadercross thing at runtime
bc compiling GLSL to SPV results in the same thing :p
setup is always the hard part, once I have the basic triangle example working for GLSL, HLSL, and zig with shadercross behaving properly, then the rest of the examples should be fairly straightforward
the zig shaders in this are also standalone files unlike my other examples where they are a bunch of comptime stuff, I want these GPU examples to be as standalone as possible
I updated the version of spirv-cross but still no luck hm
OH OK ITS AN UBSAN THING
it ✨ just works ✨ in ReleaseFast
I'll force SPIRV-cross to be ReleaseFast for now
wanted to be smart and switch between ReleaseSmall and ReleaseFast but it's not comptime-able? So idk
so far, all the shader formats are working on linux except for HLSL
added warning for spirv-opt not being found
I rely on spirv-opt for zig shaders to be optimized properly, but it is not technically necessary
also added a nice panic message for when glslang is missing
this is so cool!
I am super excited to try out the examples as soon as you are in the "triangle working" state 🙂
The triangle works for Linux at least for zig and glsl shaders. I haven't tested it with Mac or windows yet. I don't anticipate any more changes to the gpu examples build script though, remaining changes should just be in the sdl3 build script
There is a shadercross branch on my zig-sdl3 repo with everything so far
Sweet, I will give it a test on Mac OS then 😃
Thanks, I'm curious on how well it works for you. My Mac using friend said MSL 2.2 doesn't support 64-bit ints so the zig shaders didn't work, however the glsl ones worked perfectly after installing glslang
I'll see what happens if I disable the int64 spirv extension later
It now works as long as you don't perform any >32bit arithmetics
Epic
Perfect then
Checklist for shadercross branch to be done:
- HLSL support
- Verify all 3 shader formats work on linux, windows, and mac
- Finish all the GPU examples
- Make a dedicated example project showing watching for an HLSL file change and recompiling the shader at runtime for a shader-toy like program
- Zig shader GPU project using compile time reflection to generate CPU vertex buffer types and ensure vertex and fragment shader compatibility
I might give it a shot later today 🙂
Thnx :>
windows really just said no lol
I'll try GLSL and see if that works at least
though I'm pretty sure this is a known issue with Windows
At least my Mac friend zig and glsl shaders worked for him
why is stuff always broken on windows... so annoying to have to struggle getting shit working just because I'm not a linux nerd
Found the issue
Windows is just harder to develop for tbh
Having used both for a while I vastly prefer the unix like command utilities and filesystem
I agree, when it comes to the amount of bullshit that MS puts into the OS and API and such
This is why I'm doing fun stuff in zig as an antidote for all the bullshit from my day job lol
When using the windows 10 vm to try and compile I clicked the system environment variables start menu entry too fast and I had to right click and hit open in order for anything to happen
I couldn't left click anymore even closing and reopening the start menu, but just for that entry
How does that even happen
There is a pr to fix the windows issue but it looks dead :<
alright GLSL borked too
ughh
oh ok it's not GLSL
it's just every GPU example crashing on WIndows for no discernable reason
NO idea what is going on
maybe it's something to do with shadercross?
the regular SDL3 examples are working perfectly fine
or maybe it's my VM
or maybe something with GPU in general
I have no idea no error messages just the program exiting unsuccessfully, and not sure how to debug this
if there are any zig Windows experts that can figure out what the issue is please let me know, it'll help greatly in getting this out faster
I cannot say I'm an "expert", but I am using Zig on Windows and can see what output I get
Is this on the shadercross branch?
Yep
So it works for you @empty oyster? Might just be a vm thing then
Thanks for testing :>
@broken bluff basic triangle works perfectly on my Mac 🙂
Only one feedback, the error message is not very clear when glslang is not installed
🥳
Eyyy nice. Do zig shaders work too? I also tried doing a custom panic message for glslang I'm not sure what else I can do unfortunately
also this looks like you're trying to compile zig shaders and using an outdated version of my shadercross branch?
Mhh, I just cloned and pulled 10 minutes before running the command 🧐
oh huh
I thought I disabled 64-bit ints for zig shaders
I'm not sure why zig shaders are not working on runtime...
Yep, worked right away
It was technically on Windows 11 but I doubt that matters
Probably not, good to know that :>
This also means while I can't compile zig shaders on windows they'd probably run if precompiled from a different os
Basic triangle and basic vertex buffer examples done
where can i take a look? :) i found the PR :)
this looks a lot cleaner than the old gpu examples :D
looking forward to a uniform buffer example ;) (for my zig-sdl3 and zig shader exploration project)
Thnx :> I've been trying to make everything look cleaner and self-contained. Hopefully I have time to complete all the examples soon
I have some strange issue with surface creation before and after claimWindow call. running it before claimWindow seems to work, after not. Anyone else run into this? I did see a possible related issue: https://github.com/Gota7/zig-sdl3/issues/123 added some samples there.
I am trying to load images with SDL_Image and upload the to the GPU using SDL_GPU. But if I call IMG_Load between claiming the window to the device and creating the texture, the entire program cras...
I would assume claimWindow and image.loadFile should be totally unrelated as loadFile is not a gpu operation as far as I know.
yeah, I have no idea what the problem is
ok the vertex buffer example I made on my laptop just crashes on my PC
what
cull mode works fine though
huh
it looks like the renderer in VULKAN_submit is just null
@broken bluff I've investigated into my issue some more and it results in to almost the same error as you have above:
The interesting thing is that this time I rewrote it in c using the zig build system. I've added the c code to the open issue: https://github.com/Gota7/zig-sdl3/issues/123
Building SDL from source, and building the SDL_gpu_examples from source than I don't have this issue.
oh huh
wonder what's going on with the build system
undefined behavior somewhere maybe?
OK I THINK IT WAS FIXED UPSTREAM
I updated SDL3 and it seemed to work
making a PR now
mostly waiting for CI to pass
ok @novel cloud try now
using the latest master of zig-sdl3
Nice! this seems to work indeed
still strange issue though. curious to see what the underlying issue was.
Anyways thnx for checking and for the awesome library!
np :>
probably not this, but possible
OH THIS WAS IT
I have no proof this was it, but I'm fairly sure this is the problem
Yeah that looks like a winner
7/32 GPU examples done
8/32 GPU examples done
I just did the textured quad one :>
next example will be to animate the texture quad with a matrix, let's see how that goes lol
9/32 GPU examples done
textured animated quads working
zig shader too
const std = @import("std");
extern var uniforms: extern struct {
transform: Mat4,
} addrspace(.uniform);
extern var position_in: @Vector(3, f32) addrspace(.input);
extern var tex_coord_in: @Vector(2, f32) addrspace(.input);
extern var tex_coord_out: @Vector(2, f32) addrspace(.output);
const Mat4 = extern struct {
c0: @Vector(4, f32),
c1: @Vector(4, f32),
c2: @Vector(4, f32),
c3: @Vector(4, f32),
pub fn mulVec(a: Mat4, b: @Vector(4, f32)) @Vector(4, f32) {
const ar0 = a.row(0);
const ar1 = a.row(1);
const ar2 = a.row(2);
const ar3 = a.row(3);
return .{ @reduce(.Add, ar0 * b), @reduce(.Add, ar1 * b), @reduce(.Add, ar2 * b), @reduce(.Add, ar3 * b) };
}
pub fn row(mat: Mat4, ind: comptime_int) @Vector(4, f32) {
return switch (ind) {
0 => .{ mat.c0[0], mat.c1[0], mat.c2[0], mat.c3[0] },
1 => .{ mat.c0[1], mat.c1[1], mat.c2[1], mat.c3[1] },
2 => .{ mat.c0[2], mat.c1[2], mat.c2[2], mat.c3[2] },
3 => .{ mat.c0[3], mat.c1[3], mat.c2[3], mat.c3[3] },
else => @compileError("Invalid row number"),
};
}
};
export fn main() callconv(.spirv_vertex) void {
std.gpu.binding(&uniforms, 1, 0);
std.gpu.location(&position_in, 0);
std.gpu.location(&tex_coord_in, 1);
std.gpu.location(&tex_coord_out, 0);
std.gpu.position_out.* = uniforms.transform.mulVec(.{ position_in[0], position_in[1], position_in[2], 1 });
tex_coord_out = tex_coord_in;
}
this is what the shader looks like for those that are curious
Sweet😍
Looking forward to having a good matrix vector lib in zig that also efficiently supports GPU!
Maybe we could cook sth up once zig shaders get a little more stable and ironed out ☺️
that would be nice
I am working on a generic math lib, but it uses packed structs which is not possible for extern vars in GPU to use
10/32 examples done
about to do the basic compute example next, I'm excited for this one
This would be also super relevant for the stuff that I am
interested in moving forward ☺️
so far I got the GLSL program working
just working out some of the last bugs in the zig inline assembly
I'm currently getting this which is very unhelpful lol
oh
turns out I need to use a u32 vec not i32 vec
Is it already pushed on you branch? I would love to play around with it during the next week 😃
not yet
it will be once the zig part is done which should hopefully be sometime today
const std = @import("std");
fn store2d(
comptime set: u32,
comptime bind: u32,
uv: @Vector(2, u32),
pixel: @Vector(4, f32),
) void {
asm volatile (
\\%float = OpTypeFloat 32
\\%v4float = OpTypeVector %float 4
\\%img_type = OpTypeImage %float 2D 0 0 0 2 Rgba32f
\\%img_ptr = OpTypePointer UniformConstant %img_type
\\%img = OpVariable %img_ptr UniformConstant
\\ OpDecorate %img DescriptorSet $set
\\ OpDecorate %img Binding $bind
\\%loaded_image = OpLoad %img_type %img
\\ OpImageWrite %loaded_image %uv %pixel
:
: [uv] "" (uv),
[pixel] "" (pixel),
[set] "c" (set),
[bind] "c" (bind),
);
}
export fn main() callconv(.spirv_kernel) void {
std.gpu.executionMode(main, .{ .local_size = .{ .x = 8, .y = 8, .z = 1 } });
store2d(1, 0, .{ std.gpu.global_invocation_id[0], std.gpu.global_invocation_id[1] }, .{ 1, 1, 0, 1 });
}
@novel monolith this is my zig shader for a compute kernel, though I get this error:
Sweet 😃
am I setting the execution mode wrong?
(unfortunately my program crashes entirely if I just do not set the execution mode so it is probably important?)
hey sorry about that i removed execution mode from assembler with no replacement
there's an open PR to use callconv tho which is the intended way
ah ok
that's unfortunate, I guess compute with zig shaders is not possible in the meantime then?
yes unfortunately
:<
the new changes look good, but I must ask why remove valid SPIR-V assembly instructions? I know using the language is the correct way in most scenarios, but I can write x86 assembly code that does the same thing zig code does if I wanted to
ok an interesting idea I have, I have no way of doing what I want in zig to get the inline assembly working. But what if I link code that does the inline assembly I need?
that instruction had so many flaws and iirc it needed some extra work to keep it working after the refactor but i agree removing it with no replacement was perhaps not a good idea
spirv linker doesn't support this yet
ah
yeah in that case I have no ideas outside of binary hacking, and I really don't think appending an instruction to a compiled binary is really practical lol
It's awesome to see the progress on all this!
For this example shader, is the @Vector syntax required when compiling to SPIRV (or any benefit in general)? It's mostly just syntax, but having the @reduce makes it harder to read. Would a [4]f32 (or a type with an add function) compile to the same SPIRV output?
probably?
Probably to which?
I just prefer using vectors more, and in practice you would probably be using a math library and wouldn't be seeing underlying operations like @reduce anyways
as in [4]f32 would probably compile the same
Yeah, agreed. I haven't read up on the SPIRV backend at all so wasn't sure if maybe you had to use the Vector built-in to get the equivalent of vec4 in glsl, for example
also in general vector operations would be more optimal (assuming the spirv-opt tool doesn't promote to vectors already)
I would think they'd be the same, but this is out of my wheelhouse. GPUs are SIMD machines so I'd hope it'd be able to deduce that [4]f32 is just a vec4
hopefully, would be interesting to compare at some point
11/32 GPU examples done, the compute one is up
unfortunately zig shaders for compute will have to be added in the future and for now I just have all compute shaders for zig use the GLSL versions which is kinda gross as now you need glslang installed to run any of the examples using zig or GLSL
arrays will always generate spirv arrays but a @Vector may generate arrays when it can't be represented by spirv vectors
that's an implementation detail of the driver but im positive they'd all do that
So based on this I'd want to use @Vector anytime I want a vec2, vec4, etc. and [4]f32 only when I want a GLSL equivalent of [4]float, for example?
i don't know what glsl compilers generate but that sounds about right
does the compute-uniform example crash for anyone else?
for me the compute pipeline just dies a few frames in causing a crash
with GPU debug mode on it says something about the piepline handle not being valid
it turns out I made a dumb mistake
I used defer instead of errdefer
so the pipeline in init gets freed a few frames in
bc of how long it takes Vulkan to free the pipeline handle
12/32 GPU examples done
I'm trying to move my project from Zig 14 to 15 but I'm having some issues, before it worked just fine now it crashes as soon as it opens a window, I included my logs for both running and debugging it in sdlvk.txt
That's actually nice: in debug mode it inserts a breakpoint so if you run under a debugger, you'll stop at that point and be able to examine memory and see what the issue is. Just a couple lines above line 689 in posix.zig will show the condition where it decides to break/exit.
debug.zig
70 pub fn castToNull() noreturn {
71 @branchHint(.cold);
72 call("cast causes pointer to be null", @returnAddress());
73 }
main_callbacks.zig
182 pub export fn SDL_AppEvent(
183 app_state: ?*anyopaque,
184 event: *c.SDL_Event,
185 ) callconv(.c) c.SDL_AppResult {
186 if (@hasDecl(root, "event")) {
187 const ret = root.event(@alignCast(@ptrCast(app_state)), events.Event.fromSdl(event.*)) catch |err| {
188 std.log.err("{s}", .{@errorName(err)});
189 if (@errorReturnTrace()) |trace| {
190 std.debug.dumpStackTrace(trace.*);
191 }
192 return c.SDL_APP_FAILURE;
193 };
194 return @intFromEnum(ret);
195 } else return c.SDL_APP_CONTINUE;
196 }
looks like its some kind of alignment issue
I'm trying to use HLSL for my shaders, but having trouble getting them to build on macOS. I thought it was something I goofed but trying the gpu_examples with zig build run -Dexample=compute-uniforms -Dshader_format=hlsl results in the same error: SDL3: [Error:General] Shadercross was not built with DXC support, cannot compile using DXC! error.
Is HLSL not supported on macOS?
HLSL is made for DirectX so possibly not
This is where the error comes from (assuming I have the right repo): https://github.com/libsdl-org/SDL_shadercross/blob/4ce748310f57d405b4eb2a79fbbc7e974d6491ec/src/SDL_shadercross.c#L563
Seems like SDL_shadercross needs to be compiled with SDL_SHADERCROSS_DXC enabled
what platform are you running this for? Are you using the latest master version of zig-sdl3? I also use zig 0.15.1
HLSL support is not supported yet sorry, it'll be done by the time shadercross is merged into master
Im running it on Windows, and I tried both the master and shadercross branch and got the same results
ok, I'll have to see if I can reproduce it later
I rewrote a part of my project without main callbacks and its working, so the problem seems to be something with main callbacks. My guess is its some weird function pointer aligning/casting inconsistency on windows, I might try to booting up one of my linux machines and seeing if my project works any different on there
also idk if anyone else has tried using this library with snektron's vulkan binding but they work together pretty well
... Are you still on Windows 7?
Its a theme lol
the tonemapping example is surprisingly in depth there's a lot of shaders and I need a way to load an HDR texture
I could just add stb image like the C code does but should I
also why doesn't SDL image support HDR lol
I'm having a strange behavior and wondering if others have encountered the same before. Each time I build my app it crashes at the same time the first time I run the program and then it stops after that. Anyone encounter something similar before?
Illegal instruction at address 0x7ff67b197acf
C:\Users\user\AppData\Local\zig\p\sdl-0.2.6+3.2.20-7uIn9NgjfwHH5a6HhyLHat2nHU3OP5B05QHhKJKuxEex\src\gpu\SDL_gpu.c:3223:0: 0x7ff67aef9b9d in SDL_SubmitGPUCommandBuffer_REAL (SDL3.lib)
return COMMAND_BUFFER_DEVICE->Submit(
C:\Users\user\AppData\Local\zig\p\sdl-0.2.6+3.2.20-7uIn9NgjfwHH5a6HhyLHat2nHU3OP5B05QHhKJKuxEex\src\dynapi\SDL_dynapi_procs.h:957:0: 0x7ff67ae4de53 in SDL_SubmitGPUCommandBuffer (SDL3.lib)
SDL_DYNAPI_PROC(bool,SDL_SubmitGPUCommandBuffer,(SDL_GPUCommandBuffer *a),(a),return)
C:\Users\user\AppData\Local\zig\p\sdl3-0.1.1-NmT1QwTgIADixpCS2g5pBBON5AEfnjOox94dU0dtT-tq\src\gpu.zig:964:64: 0x7ff67ae23285 in submit (sdl3_zig_zcu.obj)
return errors.wrapCallBool(c.SDL_SubmitGPUCommandBuffer(self.value));
^
C:\Users\user\src\sdl3-zig\src\main.zig:273:30: 0x7ff67ae251b9 in init (sdl3_zig_zcu.obj)
try command_buffer.submit();
^
... (omitted to stay in Discord limits)
^
C:\Users\user\AppData\Local\Zigup\zig\0.15.1\files\lib\libc\mingw\crt\crtexe.c:259:0: 0x7ff67ae321bb in __tmainCRTStartup (crt2.obj)
mainret = _tmain (argc, argv, envp);
C:\Users\user\AppData\Local\Zigup\zig\0.15.1\files\lib\libc\mingw\crt\crtexe.c:179:0: 0x7ff67ae3221b in mainCRTStartup (crt2.obj)
ret = __tmainCRTStartup ();
???:?:?: 0x7ffbdbbee8d6 in ??? (KERNEL32.DLL)
???:?:?: 0x7ffbddd28d9b in ??? (ntdll.dll)
Oh, it's actually happening in two different spots. Might be something I'm doing then. Still seems weird it's only happening on the very first run after each rebuild.
I don't know sure what's happening exactly, but it looks like some issue with SDL's dynamic linker thing
basically SDL even when statically linked will still search for DLLs
if I had to take a guess for some reason that table isn't being populated correctly
ubsan trapping on an unitialized bool with an illegal bit pattern is my guess. vulkan had one of those that was fixed in 3.2.22 (you're on 3.2.20) so try updating zig-sdl3
https://github.com/libsdl-org/SDL/pull/13830
Thanks, I'll give this a try tonight if I can
Just trying this out for a few minutes before bed. I would need to be using Zig nightly for this at the moment right?
I don't think so, 0.15.1 should be fine
zig fetch --save git+https://github.com/Gota7/zig-sdl3#v0.1.1 (from the README) resolves to the same commit that I already have in bulid.zig.zon
Should I go with zig fetch --save git+https://github.com/Gota7/zig-sdl3#zig-master and make whatever changes necessary with the API changes in zig-sdl3
ìs it possible to use @sqrt with zig shaders?
error: TODO (SPIR-V): implement unary operation 'sqrt' for vulkan os
Was trying something with the gpu examples
you can do an approximation
something like:
inline fn sqrt(x: f32) f32 {
//TODO check and handle x <= 0
//TODO check and handle x == 0
var s = x;//initial guess
inline for (0..3) |_| {
s = (s + x/s) * 0.5;
}
return s;
}
adjust the amount of iterations depending on what you use as initial guess, the range of given x and the required precision
this is with 3 iterations for inputs in the range (0,10]
i feel like adding sqrt to the vulkan spirv should be trivial
thanks
does a similar approximation exist for cbrt?
is it just the 0.5?
s = (s + x/(s*s)) * 0.5
should work. not sure about the quality of the convergence though
i will check when i get home
/// returns the next approximation of x := base^(1/q)
pub fn iterateRoot(F: type, base: F, q: usize, x: F) F {
switch (q) {
0 => unreachable,
1 => return base,
else => {
const w = 1.0 / @as(F, @floatFromInt(q));
return (1 - w) * x + w * base / naturalPower(F, x, q - 1);
},
}
}
i think that weights like this will be ideal, however the convergence gets worse quickly for higher values of q.
There are probably other approximations that converge faster, but i would have to look those up
try just using the default master branch master
I did update SDL3 since the last tagged release, and zig-master I don't think is maintained anymore?
Should the README be updated in that case?
EDIT: created a PR here: https://github.com/Gota7/zig-sdl3/pull/133, no worries if that is not what you intended
That worked, though, by the way
has anyone done dear imgui with zig-sdl3?
the README should not be updated, I just need to make a new tag and then edit it then
oh wait
Sounds good, I'll abandon the PR
you mean to remove the zig-master
Oh
I recently got it working, but it was a bit of a challenge
One thing I don't like about it is the additional SDL3 dependency in the project (i.e. needing both castholm/SDL and Gota7/zig-sdl3), when zig-sdl3 already depends on SDL. I couldn't find a way to set the include path of the ImGui source to point to the SDL source that is inside zig-sdl3. Does anyone know if it's possible?
@mellow sedge i wrote some little helper functions that lets me write shaders like this:
const gpu = @import("gpu.zig");
pub const vertex_index = gpu.ptr(u32, .input, "vertex_index");
pub const uv = gpu.ptr(@Vector(2, f32), .output, "uv");
pub const position = gpu.ptr(@Vector(2, f32), .output, "position");
fn main() void {
gpu.location(uv, 0);
position.* = switch (vertex_index.*) {
0 => .{ -1, -1 },
1, 4 => .{ 1, -1 },
2, 3 => .{ -1, 1 },
5 => .{ 1, 1 },
else => unreachable,
};
uv.* = position.*;
}
comptime {
gpu.main(main, .vertex);
}
``` this compiles to spirv target with the correct callconv and addrspace. But it can also be imported when compiling for the cpu. So one could do comptime pipeline checks like this:
```rs
const std = @import("std");
const expect = std.testing.expect;
const gpu = @import("shaders/gpu.zig");
const Canvas = @import("shaders/canvas.vert.zig");
test Canvas {
try expect(@typeInfo(Canvas).@"struct".decls.len == 3);
try expect(gpu.AddressSpace.from(Canvas.vertex_index) == .input);
try expect(gpu.AddressSpace.from(Canvas.uv) == .output);
try expect(gpu.AddressSpace.from(Canvas.position) == .output);
}
I now your were looking into comptime pipeline checks in the past. Did you find a satisfying solution?
Might this be of help to you?
@stark elk I did end up finding a solution in the old repo, but this appears to be a lot cleaner assuming I can generate the gpu.ptrs with comptime schenanigans
Happy to help with future comptine schenanigans :) just hit me up :)
points i am still looking into, with what i currently got
- gpu.ptr to not need a name
- automate gpu.location calls
I was able to kinda automate the location calls
For comptime checking with shaders I'll probably have you use a function to call another function with the inputs as parameters and outputs as a struct and do some magic on how I call the function
i would try to require vertex outputs and fragment inputs to be in the same order. That way one can just iterate over the decls and compare if the count and types match 🤔
i will try that today and report back 👍
That'll be cool
i didnt quite get to the prototype yet. i got side tracked by a couple of simplifications :)
prototype vertex/fragment compatibility check:
pub fn checkVertexFragment(Vertex: type, Fragment: type) !void {
const outputs = decls(Vertex, .output);
const inputs = decls(Fragment, .input);
if (outputs.len != inputs.len) @compileError("vertex outputs must match fragment inputs");
inline for (outputs, inputs) |o, i| {
if (o != i) @compileError("vertex outputs must match fragment inputs");
}
}
I really need to extend the template to support Android and Emscripten
I think that'll be my next goal after the GPU examples
haven't had much time or the motivation to work on the GPU examples much lately bc I ran into the tonemap example
which is surprisingly involved
I might just skip it for now
save it for last
13/32 GPU examples done
14/32 GPU examples done
almost halfway
also added a new shader format to the examples, .hsl_runtime
now normal .hlsl will just compile the HLSL shaders to SPIR-V using glslang
as I imagine there is probably an audience for people who want their shaders procompiled but still written in HLSL
This is so awesome!
In your experience is there any obvious benefit of hlsl over glsl? So far I only used the latter 😃
Also are you planning for an example for a compute shader?
from my experience I think it's just personal taste looking at the shader code I ported from HLSL to GLSL and zig, I like GLSL the most. I'm used to it more, nothing scientific. Though I really like how HLSL has explicit inputs and outputs. There are compute shaders on the shadercross branch working already, just not zig variants as they are not currenly possible due to compiler breaking support for compute shaders
though when it comes to personal projects I'll use zig for everything as having reflection for checking and having all code in the same language is nice
ButtonFlags in mouse.zig needs all the enum instances (c.SDL_BUTTON_LEFT etc) wrapped with c.SDL_BUTTON_MASK(...) in toSdl() and fromSdl(), the enum is 1,2,3,... and the mask fn handles the shifting to 2,4,8,...
can make GH issue in 12h if you want it there instead of a random discord message
Done, thanks
I really want to get this done before the end of the year to keep up with my own goals for personal projects, so here is what I want to do:
- September - Finish porting GPU examples from SDL
- October - Finish shadercross, runtime HLSL example, and zig shader reflection example. Update the template project to work for Android and Web
- November - Release 1.0.0
- December - Release 1.1.0 + 1.2.0
this isnt to do much with SDL3 but you guys are definently they right people to ask, when making a spirv shader do I need just a function like
pub fn vert() callconv(.spirv_vertex) void {}
Or do I need to make an entire module in the build system?
👌
I found out I started this project August last year man it went by so quick I didn't know I worked on this for over a year 😿
I just found this project. looks really cool! I am relatively new to zig. I struggle a little with translating the build.zig line:
lib.root_module.addImport("sdl3", sdl3.module("sdl3"));
...into something working in an init zig project. The screenshot shows how I attempted to do it and the error. But I miss some basic concept understanding of the whole build.zig file.
Can anyone pinpoint how I can fix this?
The main.zig file has this as the very first line which is what seems to break:
const sdl3 = @import("sdl3");
Add the import to exe.root_module if you want to use it from main.zig, mod applies to root.zig and its subfiles, but not main.zig
wow, thanks! window is now showing!🙏
15/32 GPU examples done
does anyone have any examples of build.zig for the master branch of zig?
thank you for doing all this work! I am a total rookie in zig as well as c and sdl and I find it hard to follow c examples as I simply don't have enough knowledge in this area. making a zig version really lowers the bar for ppl like me
np
I'm currently 17/32 examples done
each zig example file is standalone too, so assuming you have the shaders and build system in place it's just copy paste
better alternative than a mega-executable with all the examples
I have nothing in place - but I would like to learn about shaders so all this sounds really nice
Nice project @broken bluff
I have a doubt,
In C we have SDL_GetPointerProperty
This function returns a property pointer,
In C, we can then override and we can then set the callback, How to set the pointer callback in zig? Can we just do it through property.pointer.callback = ? will this be fine?
what function are you talking about?
Can I use setPointerPropertyWithCleanup?
Like, is this used to set a callback as well?
Example in C:
CustomEventData *ced = SDL_GetPointerProperty(custom_events_property, name, NULL);
if (ced != NULL) {
// Overriding callback
ced->callback = callback;
res = true;
}
Like, this in zig?
fn testPropertiesCleanupCb(user_data: ?*void, value: *std.array_list.Managed(u32)) void {
_ = user_data;
value.deinit();
}
...
try group.set("a", Property{ .number = 5 });
try group.set("b", Property{ .boolean = false });
var arr = std.array_list.Managed(u32).init(std.testing.allocator);
try arr.append(8); // Ensure no memory leakage.
try group.setPointerPropertyWithCleanup("c", std.array_list.Managed(u32), &arr, void, testPropertiesCleanupCb, null);
...
an example @hidden marsh
and when you get a property in zig, it will return a tagged union
thanks a lot
ye np
18/32 examples done
just finished the MSAA one which I imagine will be useful
Done (25/32):
- Clear Screen
- Clear Screen Multi-Window
- Basic Triangle
- Basic Vertex Buffer
- Cull Mode
- Basic Stencil
- Instanced Indexed
- Textured Quad
- Textured Animated Quad
- Clear 3D Slice
- Basic Compute
- Compute Uniforms
- Draw Indirect
- Compute Sampler
- Copy And Readback
- Copy Consistency
- Texture 2d Array
- Triangle MSAA
- Cubemap
- Window Resize
- Blit 2d Array
- Blit Cube
- Blit Mirror
- Generate Mipmaps
- Latency
Not Done:
- Tone Mapping
- Custom Sampling
- Depth Sampler
- Compute Sprite Batch
- Pull Sprite Batch
- Texture Type Test
- Compressed Textures
Do we have a SDL_SetStringProperty implementation?
I did ptrcast to register a custom event with its name and a custom callback
yes, you have .set
but, it takes property as a value?
yeah, you give it the tagged union you want
try group.set("trial", Property{ .string = "Hello World!" });
Also, SDL_itoa?
don't use that
ok, thanks
in zig you should just use format strings and printing instead
aw man, one of my hacky tricks doesn't work when going through the optimizer :<
since you can't hold opaque types, to sample twice I just have you call the function twice
unfortunately that falls apart if you put it through the optimizer...
I can't have you do all the samples at once in the function for N amounts bc idk how to have a programmatic number of contraints...
So unfortunately I'd have to have one big inline block that does all the sampling
Or just not use the optimizer for this one
If only the UVs were not runtime only known and different from each other, then I could build the assembly string
Wait what if I type the uvs in inline assembly as a pointer to vec2's
Then in select the proper index based on the count maybe in a loop or something
That could work
Or just an array or something
could you just have the inline definions once at the start of each shader? to avoid that error? (i dont really know what i am talking about though 🙊 )
unfortunately you can't declare variables in one inline assembly block and then use them in another, I tried it
and since these are SPIR-V specific opaque types I can't really save an "OpTypeImage" to a zig variable to use later
so in order to be valid SPIR-V and zig code, all the sampling must be done in the same inline block as "OpTypeImage"
I wonder if there is a flag I can pass to the optimizer though that would make it less pedantic, but I doubt it
OH actually, I can do --remove-duplicates to "Removes duplicate types, decorations, capabilities and extension instructions" and --validate-after-all to "Validate the module after each pass is performed." I might also need to add --skip-validation to not validate the SPIR-V before optimizing. It warns I should use this option with caution but I think I know what I'm doing
basically I'm thinking I can be clever and run a pass of the optimizer tool to remove the duplicate types, then run another pass of the optimizer to properly optimize
so my silly sampling function might be practical to use after all
another idea would be to make the inline assembly variable names depend on bind and set. Or maybe even pass @src() to every call like with dvui. 🤔
that wouldn't work
the problem isn't the names, in fact the names are per each inline assembly call and get turned in to IDs
oh i see >.<
the problem is that you can't declare the same type twice
while the SPIRV does work and indeed I tried it, I guess it's against spec
oh that is annoying
those 2 rules kinda force you to write a single custom asm block. >.<
(if it werent for the 🪄 you found)
yeah, I'll definitely try it when I'm at my PC tonight I got worried that I would have to mandate some ugly inline assembly...
I'd rather just have me write some ugly assembly once and then anyone could copy-paste the function
yep that works :>
noooo
and the worst part is this feature is in MR... https://github.com/ziglang/zig/pull/24681/files#diff-1e3cbe7dfd82d5e898c350fad1f6d9206d8a1675c2b418272474f3a701f10b48R125
@novel monolith is there a work around for now?
oh it looks like I can just do OpCapability ImageQuery in SPIR-V assmbly directly for now, epic
man
unfortunately the depth cube sampler won't work properly in zig :<
unfortunately, since I need to write to the fragment depth I need to set the execution mode, which is currently impossible...
evil idea, what if using SPIRV tools disassemble the SPIRV, replace the execution mode, then reassemble it
hmmmmmmmmm
that way I could also do compute shaders in zig too
nice
just pushed it up now
it is so cursed
I run the output SPIRV into a disassembler, then run a custom build tool on it that adds the execution mode, then assembles the SPIRV back and then optimizes it
later I'll try seeing if I can use this method to get compute kernels working on the current zig version
as far actual practicality goes for a project on this method, idk I feel like it's perfectly viable. Definitely a hacky workaround, but if you're dealing with zig shaders you should have spirv-tools installed anyways for optimizing so ensuring you have the disassembler and assembler tool just sitting around isn't too far fetched
I don't recommend using zig for shaders really, however I am the stubborn I want zig to run on everything including my GPU, and love the compile time stuff that can be done
my goal with these examples is to prove that using zig shaders for real graphics dev is viable, even if not really practical or clean
yeah the state is unfortunate rn. i'll try to rebase that PR (as soon as im free) and bug mlugg again to review it
thnx, I really hope it is in the next release
I'm just glad I found a workaround even though it's really hacky
now I can probably do compute kernels too
which I'm excited about
This is awesome! What a creative solution 😄😄😄
How does SDL_PeepEvents work, is it sdl3.events.peep? But it only takes 3 arguments?
got the gradient example working too with some more inline assembly help
luckily the extension inline assembly just worked, I'm happy about that
there we go, pushed
now all the examples that are finished that involved compute kernels now have zig versions of the compute kernels as well
I'm just happy all of this is possible I didn't expect this to work at all lol
I'm sorry, am I getting a miscompilation????
YEP
it works fine in release fast
it's a miscompilation
another subtle bug
this is not correct behavior
almost done with this zig shader though, once I finish this example I'll submit these bugs to the zig issue thing
any chance for merging https://github.com/Gota7/zig-sdl3/pull/121 ? 😄
sorry I still need to review I should probably do that I keep forgetting
I tried getting SDL_cross working yesterday, using bits and pieces stolen from your WIP branch, and the DXG stuff was causing me huge pains. Is that at all in progress now, or is it todo, or did I just rip off your code the wrong way? 😄
(I'm not making a competing spirv cross. I just looked at your code and jiggled it a bit and stuck it in my own local project to try to get some of the code sample stuff working. so "stole" is a joke)
no worries
I haven't done the DXC stuff yet
as a personal opinion you don't need runtime HLSL source support (which is what DXC is for) unless you want to support hot-reload shaders
I don't know any other reason where it wouldn't be advantageous to pre-compile your shaders to SPIR-V
and if hot reload is for development purposes, then you could just have the reload run your system's shader compiler anyways
what do you use instead? glsl?
nah you can still use HLSL, just put it through glslang or something
I was attempting to get my shaders to recompile at build time with zig build, without using any stuff installed on the OS.
ah I see yeah I definitely should make a GPU template that has a shader compiler build tool using shadercross
this is a legit use
Also, I was starting with what was in the SDL gpu examples project, and they start with HLSL, and cross compile to support all targets (SPIRV, Metal, and DXIL I think?) so I was seeing if that was possible with zig build.
I think DXC is the big blocker for that on your shader cross build implementation? Is that correct?
TBH I would be happy with any textual shader format that supported all features. So GLSL would be fine as an input. I am much more used to GLSL than HLSL anyway.
For some reason, the hacky SDL_Cross cli implementation I threw together (with some of your code bits for help) still complained it couldn't take GLSL as an input. I only managed to get it working with SPRIV input.
I didn't end up pulling in the vulkan headers tho. Maybe that + some preprocessor define was required to get the SDL_Shadercross cli to accept GLSL inputs, and they just have bad error messages when everything isn't linked and enabled.
Yeah, shadercross only supports HLSL or spirv inputs
If anyone wants to contribute pls help me figure out why custom allocators do not work I am so confused 
I was bored and curious so I cloned the repo and ran the hello world example and your realloc function is broken, you're not memcpying the data from the old allocation over to the new one
WAIT REALLY
that was my mistake?? holy shot thanks
I never would of caught that
you don't know how long I've been staring at these
on master it also seems to cause the compiler to hang, possibly because of the while loop used to calculate size and alignment
I rewrote it like this and now it works, it also makes use of remap. I think it's correct but I can't promise for sure, either way you're completely free to steal and adapt it however you'd like
const Allocation = extern struct {
size: usize,
data: void align(@alignOf(std.c.max_align_t)),
};
fn makeAllocation(size: usize, zero_init: bool) ?[*]u8 {
const bytes = custom_allocator.allocWithOptions(u8, @sizeOf(Allocation) + size, .of(Allocation), null) catch return null;
if (zero_init) @memset(bytes, 0);
const allocation: *Allocation = @ptrCast(@alignCast(bytes.ptr));
allocation.size = bytes.len;
const mem: [*]u8 = @ptrCast(&allocation.data);
return mem;
}
fn allocMalloc(size: usize) ?[*]u8 {
return makeAllocation(size, false);
}
fn allocCalloc(nmemb: usize, size: usize) ?[*]u8 {
return makeAllocation(nmemb * size, true);
}
fn allocRealloc(mem: ?[*]u8, size: usize) ?[*]u8 {
const old_mem = mem orelse return allocMalloc(size);
const old_data: *align(@alignOf(std.c.max_align_t)) void = @ptrCast(@alignCast(old_mem));
const old_allocation: *Allocation = @fieldParentPtr("data", old_data);
const old_bytes_ptr: [*]align(@alignOf(Allocation)) u8 = @ptrCast(old_allocation);
const old_bytes = old_bytes_ptr[0..old_allocation.size];
if (custom_allocator.remap(old_bytes, @sizeOf(Allocation) + size)) |new_bytes| {
const new_allocation: *Allocation = @ptrCast(@alignCast(new_bytes.ptr));
new_allocation.size = new_bytes.len;
const new_mem: [*]u8 = @ptrCast(&new_allocation.data);
return new_mem;
}
const new_mem = makeAllocation(size, false) orelse return null;
@memcpy(new_mem[0..size], old_mem[0..size]);
custom_allocator.free(old_bytes);
return new_mem;
}
fn allocFree(mem: [*]u8) void {
const data: *align(@alignOf(std.c.max_align_t)) void = @ptrCast(@alignCast(mem));
const allocation: *Allocation = @fieldParentPtr("data", data);
const bytes_ptr: [*]align(@alignOf(Allocation)) u8 = @ptrCast(allocation);
const bytes = bytes_ptr[0..allocation.size];
custom_allocator.free(bytes);
}
thank you, I will copy this and make an example showcasing the allocator
btw, a tip if you didn't already realize: if you build with -Dc_sdl_sanitize_c=full you will get slightly more useful messages from ubsan. in this case with a debug allocator it will say
member access within misaligned address 0xaaaaaaaaaaaaaaaa for type 'SDL_VideoDisplay' (aka 'struct SDL_VideoDisplay'), which requires 8 byte alignment
which makes it a bit easier to see that something is not getting initialized
good to know thnx, I forgot that flag existed somehow 😵💫
I decided that even though I want things to be one file when possible, it only makes sense to make the inline assembly stuff for zig GPU code common
the textured quad fragment shader now looks like:
const common = @import("common.zig");
const std = @import("std");
const tex0 = common.Sampler2d(2, 0);
extern var tex_coord_in: @Vector(2, f32) addrspace(.input);
extern var color_out: @Vector(4, f32) addrspace(.output);
export fn main() callconv(.spirv_fragment) void {
std.gpu.location(&tex_coord_in, 0);
std.gpu.location(&color_out, 0);
color_out = tex0.texture(tex_coord_in);
}
here's a file with all the common shader code atm
this is amazing!
that actually looks very usable now ☺️
Thnx :>
Oh that looks sweet
Maybe after all this zig-sdl3 stuff I'll make it full featured and PR to std.gpu
But given that invalid bitcode is produced in most cases I'm hesitant that it would be accepted
Regardless having a fully featured wrapper would be great and prevent people from needing to learn SPIR-V assembly to do anything
thanks to @atomic girder, the template now supports building for web! zig build -Dtarget=wasm32-emscripten to build
CI doesn't work for some weird reason, made an issue for it: https://github.com/Gota7/zig-sdl3/issues/145
hopefully it works well for everyone else though :>
Android support next on the list
GPU examples are tedious and I want to work on the other parts of GPU so I can get the shadercross branch merged as soon as possible. I could then just make issues for the unfinished GPU examples. Here is my TODO list for the rest of the month:
- Template android support
- GPU template that uses shadercross at build time rather than at runtime
- GPU template that uses zig shaders and comptime checking
- GPU runtime HLSL example (shader-toy like program with hot-reload)
- Finish GPU examples
this is a lot, let's see if I can do it lol
though tbh the GPU template projects really are not that bad
v0.1.5 released
made it so many functions return tuples rather than structs
this is the most notable example
Cool, I've only read about doing that so far. Any observations about it?
I think this is a lot nicer than the return structure for variables that are distinct enough and you would access frequently
GPU template work is... going lol
it's bc the dependency is named sdl not sdl3 I feel dumb lol
got it to run shadercross as part of the build process for the template
ofc I still need to work out the whole DXC thing for the build step but at least building shadercross is working surprisingly well so far, the zig build system is really cool in how you can just build a build tool and use it perfectly fine
been there!
hm any ways to build dxcompiler in zig have not been updated to 0.15.1...
now what
I could update it myself but rahhhh
Been trying to update Mach's dxcompiler to 0.15.1 but having to deal with changes to http and zstd decompression
Ugh
Been working on the zig shader reflection template
Once that's in a good state might try cleaning things up to merge into master
Then just make issues for things that are not fully done but seems like kinda cop out since I want everything in master to work lol
Could always take parts out of the pull to master I suppose
ok what if I just make you have to have DXC installed on your system and I just use the system library
you should only be using DXC for dev anyways
plus I don't want building examples to take 10 billion years
plus if you want to ship something with DXC compiled into it you're doing something wrong
(unless what you are shipping happens to be a shader toy thing)
If I am only interested in glsl I do not need dxc, correct?
If so, could you make it configurable so that dxc is not a requirement when one does not use hlsl ?
yeah, it'll be configurable
you only need DXC for HLSL input that isn't precompiled to SPIRV
Probably not specific to your project, but I find the biggest barrier to using the lib is not having lsp jump/completes into the project. I'm using zig fetch, and I'm new enough that I don't know if this is universal/fault of lsp or something else.
Any ideas on how to fix that?
First is making sure your ZLS version corresponds to your Zig version, since Zig moves fast and breaks stuff often, ZLS has to move just as fast. If you go to https://zigtools.org/zls/install/ it will let you enter your zig version string and give you a download for that exact matching ZLS version. If you are using VSCode, set it up settings for the zig ext to use your copy of Zig and the version of ZLS that you downloaded instead of copies the ext manages. One other thing making it not work could be missing trys on instance creation, the lib has a lot of falliable fns and ZLS typically won't pop up suggestions on results that haven't been error-unwrapped.
Yeah lsp works fine for me
Putting this project on hold bc I'm running out of motivation and burning out
Has been over a year of working on this after all :p
and we thank you for your service! it's been cool and fun
take care
thnx :> I will return will just be some time
@mellow sedge just wondering if you still need a build of dxc? I took a crack at porting latest dxc version and it seems to be working