-
-
Notifications
You must be signed in to change notification settings - Fork 21.4k
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
Add texture partial update method #80164
base: master
Are you sure you want to change the base?
Add texture partial update method #80164
Conversation
Your branch is a couple of months behind the current Edit: I see you pushed a merge commit at the same time I wrote this. Please rebase instead to keep a single commit in the PR. See PR workflow. |
d94a0cc
to
316e86b
Compare
Reference #80781, fixed this issue |
d75283b
to
30aed6b
Compare
7f07049
to
46003e4
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It looks like you have lost a few of the changes you made in the last PR, particularly, it looks like this has lost the ability to specify a sub region of the source image
ERR_FAIL_COND(p_data.is_null() || p_data->is_empty()); | ||
|
||
Texture *texture = texture_owner.get_or_null(p_texture); | ||
ERR_FAIL_COND_MSG(p_data->is_compressed() || texture->compressed, "Compressed texture is not supported."); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ERR_FAIL_COND_MSG(p_data->is_compressed() || texture->compressed, "Compressed texture is not supported."); | |
ERR_FAIL_COND_MSG(p_data->is_compressed() || texture->compressed, "Compressed texture is not supported for partial texture updates. Please use an uncompressed image instead."); |
|
||
Texture *texture = texture_owner.get_or_null(p_texture); | ||
ERR_FAIL_COND_MSG(p_data->is_compressed() || texture->format > Image::FORMAT_RGBE9995, "Compressed texture is not supported."); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ERR_FAIL_COND_MSG(p_data->is_compressed() || texture->format > Image::FORMAT_RGBE9995, "Compressed texture is not supported."); | |
ERR_FAIL_COND_MSG(p_data->is_compressed() || texture->format > Image::FORMAT_RGBE9995, "Compressed texture is not supported for partial texture updates. Please use an uncompressed image instead"); |
After thinking, I changed the api, now the parameter data:Image is a wrapper for the target area data. This makes the api clearer. |
If the texture is updated from a specific sub region of the src image, when the texture is three-channel, it will be converted to four-channel. This is very expensive if the texture is large |
46003e4
to
6864e88
Compare
Can I know what's holding this PR back? I can try to help contribute; it was rebased but never merged. There's no solution or alternative to this functionality not existing; there's just no way to edit terrains or modify images without FPS dropping significantly when updating the entire image. |
If hasn't been approved so it can't be merged, we are currently in feature freeze and this can't be considered before 4.2 has been released |
@npip99 I suggest testing this pull request and uploading a testing project that makes use of it to demonstrate it's working. |
We are using this PR in a custom fork for a new project (with terrain destruction like in Lumencraft, but in Godot 4), so I can confirm it works. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks like this PR lost some of the work done in #75892
We should get the API back to the state it was in before (i.e. users should be able to specify a sub-region). There is no performance benefit to removing that ability from the API. The code can easily do the following:
- If the sub-region is the size of p_image, copy directly (as you have now)
- If the sub-region is smaller than p_image, grab a slice of the image (like we did in 3.x)
godot/drivers/gles3/rasterizer_storage_gles3.cpp
Lines 965 to 968 in e96c42f
Ref<Image> p_sub_img = p_image; if (src_x > 0 || src_y > 0 || src_w != p_image->get_width() || src_h != p_image->get_height()) { p_sub_img = p_image->get_rect(Rect2(src_x, src_y, src_w, src_h)); } - If the sub-region is larger than p_image, error
If we remove the sub-region from the API, we just force the user to do step 2. We don't actually save any performance and we make the API harder for users to use. Further, users will see the change as a regression, because something that was easy to do in 3.x is now hard
@@ -109,6 +109,7 @@ class RenderingServer : public Object { | |||
virtual RID texture_proxy_create(RID p_base) = 0; | |||
|
|||
virtual void texture_2d_update(RID p_texture, const Ref<Image> &p_image, int p_layer = 0) = 0; | |||
virtual void texture_2d_update_partial(RID p_texture, const Ref<Image> &p_data, Vector2i p_dst_pos, int p_dst_mipmap = 0, int p_layer = 0) = 0; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just linking back to the previous PR's reviews #75892 (comment)
It seems like you have lost some of the API changes suggested by reviewers.
This is done intentionally and is not some work lost. |
Why would the whole p_image have to be converted? If the src_rect is 10x10, but the src_image is 2048x2048, can't it be possible to just copy and convert the data from the 10x10 source subregion, without copying or converting the entire 2048x2048 image.
That's true, the user can call Image.get_region in GDScript, and then pass that into the new function signature. But, it might be possible to write code that makes texture_2d_update_partial(src_image, src_rect) faster than in GDScript calling Image.get_region and passing that. Given that it's a low-level function given exclusively for acceleration and speed, it would be useful to leave every opportunity available for it to be as efficient as it can be. In my case, I'm keeping an "Image" instance in GDScript and editing it every single frame, and then I simply wish to blit a subrectangle back to the ImageTexture every single frame so that the 3D Model's texture updates in realtime. I personally track and update the minX/maxX/minY/maxY for every pixel update, so that I can give the src_rect during the blits. In this case, even if src_rect as an argument isn't more efficient (yet), it's also a much simpler API for this type of usage. I imagine my usage is in-general the most common usage for this exact function. I think for now, with the current solution, it should be possible to just call Image.get_region internally, making it no faster than the user doing GDScript Image.get_region, but it also shouldn't be any slower either. And leave any future optimizations to the future (Any future optimizations wouldn't affect the Big-O or anything fundamental, it would just be slightly faster). In my case, I'd appreciate the opportunity for optimization in a future PR to be beneficial, as every incremental slight improvement allows me to increase the resolution of the modifiable texture in my game. |
Since this only needs to be done for all three-channel textures, the special processing is inelegant. |
Hello, this issue also can be fixed by this PR! Zylann/godot_heightmap_plugin#445 |
Due to some operational errors, I had to resubmit the pr.
Add texture_2d_update_partial method for RenderingServer.
Compressed textures are not supported, they are usually not present in use cases for this function.
Bugsquad edit:
texture_2d_update_partial
method #75892