Skip to content

Allowed creating uninitialized images (for use as storage textures)#17760

Merged
alice-i-cecile merged 13 commits intobevyengine:mainfrom
Lege19:main
Feb 10, 2025
Merged

Allowed creating uninitialized images (for use as storage textures)#17760
alice-i-cecile merged 13 commits intobevyengine:mainfrom
Lege19:main

Conversation

@Lege19
Copy link
Copy Markdown
Contributor

@Lege19 Lege19 commented Feb 9, 2025

Objective

#17746

Solution

  • Change Image.data from being a Vec<u8> to a Option<Vec<u8>>
  • Added functions to help with creating images

Testing

  • Did you test these changes? If so, how?
    All current tests pass
    Tested a variety of existing examples to make sure they don't crash (they don't)
  • If relevant, what platforms did you test these changes on, and are there any important ones you can't test?
    Linux x86 64-bit NixOS

Migration Guide

Code that directly access Image data will now need to use unwrap or handle the case where no data is provided.
Behaviour of new_fill slightly changed, but not in a way that is likely to affect anything. It no longer panics and will fill the whole texture instead of leaving black pixels if the data provided is not a nice factor of the size of the image.

This allows `Image` to be used to create an uninitialized texture for
use as a storage texture
@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented Feb 9, 2025

Welcome, new contributor!

Please make sure you've read our contributing guide and we look forward to reviewing your pull request shortly ✨

@Lege19
Copy link
Copy Markdown
Contributor Author

Lege19 commented Feb 9, 2025

When I ran cargo check I didn't enable all features. :(

let texture_end = texture_begin + rect_width * format_size;
atlas_texture.data[begin..end]
.copy_from_slice(&texture.data[texture_begin..texture_end]);
let Some(ref mut atlas_data) = atlas_texture.data else {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This could be moved out of the loop and it should maybe be turned into an error instead of a log.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll move it outside the loop, although I'm not sure what you mean by an error instead of a log. It's an error already, just not a panic, but we shouldn't panic unless we have to

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Error as in, return a Result::Err not just a log.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should I also keep the error! ?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this requires me to add another variant to TextureAtlasBuilderError. Which isn't currently non_exhaustive, should I make it non_exhaustive?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

more generally, is it Bevy policy to always make error enums non_exhaustive

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Given the prevalence of breaking changes at this stage, we don't particularly care about non_exhaustive.

And in some cases, like the ECS, we can pretty reliably predict that error enums are exhaustive.

Co-authored-by: IceSentry <IceSentry@users.noreply.github.com>
Copy link
Copy Markdown
Contributor

@IceSentry IceSentry left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Overall this looks like a useful change, but I would prefer if you used expect() instead of unwrap in code that isn't inside a test. I didn't add a comment on every unwrap but a few of them should definitely be updated.

@alice-i-cecile alice-i-cecile added A-Rendering Drawing game state to the screen C-Usability A targeted quality-of-life change that makes Bevy easier to use S-Waiting-on-Author The author needs to make changes or address concerns before this can be merged C-Feature A new feature, making something new possible M-Migration-Guide A breaking change to Bevy's public API that needs to be noted in a migration guide and removed C-Usability A targeted quality-of-life change that makes Bevy easier to use labels Feb 9, 2025
@Lege19 Lege19 requested a review from IceSentry February 10, 2025 13:48
Copy link
Copy Markdown
Contributor

@IceSentry IceSentry left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we should just return Err and let users decide if they want to log. Other than that LGTM

@IceSentry IceSentry added S-Needs-Review Needs reviewer attention (from anyone!) to move forward and removed S-Waiting-on-Author The author needs to make changes or address concerns before this can be merged labels Feb 10, 2025
@alice-i-cecile alice-i-cecile added S-Ready-For-Final-Review This PR has been approved by the community. It's ready for a maintainer to consider merging it and removed S-Needs-Review Needs reviewer attention (from anyone!) to move forward labels Feb 10, 2025
@alice-i-cecile
Copy link
Copy Markdown
Member

Nice error handling, and a well-motivated little fix. Thanks.

@alice-i-cecile alice-i-cecile added this pull request to the merge queue Feb 10, 2025
Merged via the queue into bevyengine:main with commit 3978ba9 Feb 10, 2025
@mintlu8
Copy link
Copy Markdown
Contributor

mintlu8 commented Apr 3, 2025

Please revert this change. Uninitialized images can be expressed as a zero sized Vec. This change hurts the usability of Image a lot. You cannot use

let Some(data) = &mut data else {return;}

in a lot of situations since Image has a lot of methods that cannot be split borrowed for now. Basically the only thing you can do that has any form of ergonomics is .as_mut().unwrap(), which is bad.

@Lege19
Copy link
Copy Markdown
Contributor Author

Lege19 commented Apr 3, 2025

There is certainly a valid argument with the unwrap thing. But using an empty Vec to represent an uninitialised Image is just a really bad idea. It's functionally equivalent to an Option but utterly fails to express the intent and is very arguably not 'correct'. I don't consider it an option. There definitely needs to be a way to have uninitialised images, and there is significant gain from unifying all image related things with this one type. Most users don't need to read image data, and writing image data isn't a problem.

This has already passed code review and been merged so I'm not sure what the protocol is for reverting something. But any case I don't have the power to do that.

@Lege19
Copy link
Copy Markdown
Contributor Author

Lege19 commented Apr 3, 2025

Also doesn't

let Some(ref mut data) = &mut data else {return;}

work just fine?

@IceSentry
Copy link
Copy Markdown
Contributor

Yeah, reverting isn't the solution here. Most users don't need to access the data directly and it makes sense to use Option for uninitialized images.

Using if let should work in many cases, but also, if you know the image is always initialized you can use unwrap or expect. There's nothing wrong with that. You could add an if check at the top of the function just to be sure, but it won't change in the middle of the function.

@mintlu8
Copy link
Copy Markdown
Contributor

mintlu8 commented Apr 4, 2025

There definitely needs to be a way to have uninitialized images.

I agree.

Most users don't need to access the data directly and it makes sense to use Option for uninitialized images.

After some thought, I think the real solution is we should add some methods to edit the image, then we can sort of side step this issue.

image.edit_region::<Srgba>(rect, |x, y, rgba: &mut Srgba| {

})

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

A-Rendering Drawing game state to the screen C-Feature A new feature, making something new possible M-Migration-Guide A breaking change to Bevy's public API that needs to be noted in a migration guide S-Ready-For-Final-Review This PR has been approved by the community. It's ready for a maintainer to consider merging it

Projects

No open projects
Status: Done

Development

Successfully merging this pull request may close these issues.

4 participants