Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement Default for some structs? #10

Closed
mpalomas opened this issue Jan 2, 2025 · 5 comments
Closed

Implement Default for some structs? #10

mpalomas opened this issue Jan 2, 2025 · 5 comments

Comments

@mpalomas
Copy link

mpalomas commented Jan 2, 2025

Hi, thanks for this crate (and happy new year).

I was wondering if you could also derive Default for some/all of the generated structs.

My use case is SDL_GPU. To use this API, you need to use tons of structs, and they have a lot of fields... Those C APIs were designed to be used with the "magic c struct initializer" mindset: you directly initialize what you need (only what you need) when you need it. That works because in C, you can use partial initialization tricks to only provide values for SOME of the fields. Other fields will by default get zeroed. And the API was designed to work with this mind: zeroed structs are reasonable default values in SDL_GPU.

Exemple of GPU usage in C:

SDL_GPUGraphicsPipelineCreateInfo pipelineCreateInfo = {
		.target_info = {
			.num_color_targets = 1,
			.color_target_descriptions = (SDL_GPUColorTargetDescription[]){{
				.format = SDL_GetGPUSwapchainTextureFormat(context->Device, context->Window)
			}},
		},
		.vertex_input_state = (SDL_GPUVertexInputState){
			.num_vertex_buffers = 1,
			.vertex_buffer_descriptions = (SDL_GPUVertexBufferDescription[]){{
				.slot = 0,
				.input_rate = SDL_GPU_VERTEXINPUTRATE_VERTEX,
				.instance_step_rate = 0,
				.pitch = sizeof(PositionTextureVertex)
			}},
			.num_vertex_attributes = 2,
			.vertex_attributes = (SDL_GPUVertexAttribute[]){{
				.buffer_slot = 0,
				.format = SDL_GPU_VERTEXELEMENTFORMAT_FLOAT3,
				.location = 0,
				.offset = 0
			}, {
				.buffer_slot = 0,
				.format = SDL_GPU_VERTEXELEMENTFORMAT_FLOAT2,
				.location = 1,
				.offset = sizeof(float) * 3
			}}
		},
		.primitive_type = SDL_GPU_PRIMITIVETYPE_TRIANGLELIST,
		.vertex_shader = vertexShader,
		.fragment_shader = fragmentShader
	};

A lot of the fields above are omitted, and their values are by default zeroed.

But in Rust we cannot do that without Default, for instance

#[repr(C)]
#[derive(Clone, Copy)]
#[cfg_attr(feature = "debug-impls", derive(Debug))]
pub struct SDL_GPUColorTargetDescription {
    /// The pixel format of the texture to be used as a color target.
    pub format: SDL_GPUTextureFormat,
    /// The blend state to be used for the color target.
    pub blend_state: SDL_GPUColorTargetBlendState,
}

blend_state here is another struct with a bunch of fields. To create my SDL_GPUColorTargetDescription instance I would need to provide values for ALL fields for SDL_GPUColorTargetBlendState. That makes the Rust equivalent very verbose.

With Default, it would be a bit better.

@maia-s
Copy link
Owner

maia-s commented Jan 2, 2025

Yes, this is a good point! In principle I can add Default impls for almost all the generated structs, but I'm a little worried about default making a struct that isn't valid to pass to SDL as is. Maybe that's ok though, this is a sys crate after all.

@maia-s
Copy link
Owner

maia-s commented Jan 2, 2025

I've implemented this in 9b10a2d
edit: 82d5c81 adds Default impls for structs with pointers (defaulting them to null)

@mpalomas
Copy link
Author

mpalomas commented Jan 4, 2025

wow so quick many thanks! will try this out over the weekend!

@mpalomas
Copy link
Author

mpalomas commented Jan 4, 2025

Works for me. SDL GPU code now looks like this:

let info = SDL_GPUGraphicsPipelineCreateInfo {
        target_info: SDL_GPUGraphicsPipelineTargetInfo {
            num_color_targets: 1,
            color_target_descriptions: &SDL_GPUColorTargetDescription {
                format: unsafe { SDL_GetGPUSwapchainTextureFormat(gpu_device, window) },
                ..Default::default()
            },
            ..Default::default()
        },
        vertex_input_state: SDL_GPUVertexInputState {
            num_vertex_buffers: 1,
            vertex_buffer_descriptions: &SDL_GPUVertexBufferDescription {
                slot: 0,
                input_rate: SDL_GPUVertexInputRate::VERTEX,
                instance_step_rate: 0,
                pitch: size_of::<PositionTextureVertex>() as u32,
            },
            num_vertex_attributes: 2,
            vertex_attributes: [
                SDL_GPUVertexAttribute {
                    buffer_slot: 0,
                    format: SDL_GPUVertexElementFormat::FLOAT3,
                    location: 0,
                    offset: 0,
                },
                SDL_GPUVertexAttribute {
                    buffer_slot: 0,
                    format: SDL_GPUVertexElementFormat::FLOAT2,
                    location: 1,
                    offset: (size_of::<f32>() * 3) as u32,
                },
            ]
            .as_ptr(),
        },

        vertex_shader,
        fragment_shader,
        primitive_type: SDL_GPUPrimitiveType::TRIANGLELIST,
        ..Default::default()
    };

which is really not too far away from how we write in C!

@maia-s
Copy link
Owner

maia-s commented Jan 4, 2025

Excellent! I'll go ahead and close this, then. It'll be in the sdl3-sys 0.2.0 release, which I'll release when SDL has published their next prerelease (which should be soon!)

@maia-s maia-s closed this as completed Jan 4, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants