godot icon indicating copy to clipboard operation
godot copied to clipboard

Add texture partial update method

Open Redwarx008 opened this issue 2 years ago • 12 comments

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:

  • Redo of #75892
  • Fixes #65762

Redwarx008 avatar Aug 02 '23 11:08 Redwarx008

Your branch is a couple of months behind the current master, and thus has merge conflicts. Could you rebase?

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.

akien-mga avatar Aug 02 '23 11:08 akien-mga

Reference #80781, fixed this issue

Redwarx008 avatar Aug 22 '23 02:08 Redwarx008

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

After thinking, I changed the api, now the parameter data:Image is a wrapper for the target area data. This makes the api clearer.

Redwarx008 avatar Aug 22 '23 13:08 Redwarx008

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

Redwarx008 avatar Aug 22 '23 13:08 Redwarx008

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.

npip99 avatar Nov 23 '23 01:11 npip99

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

AThousandShips avatar Nov 23 '23 12:11 AThousandShips

@npip99 I suggest testing this pull request and uploading a testing project that makes use of it to demonstrate it's working.

Calinou avatar Nov 23 '23 13:11 Calinou

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.

KoBeWi avatar Nov 23 '23 13:11 KoBeWi

Looks like this PR lost some of the work done in https://github.com/godotengine/godot/pull/75892

This is done intentionally and is not some work lost. Actually, a three-channel texture is not available, so here it will be converted into a four-channel texture. If subregions are used, the entire p_image will be converted, which has a significant impact on performance if its dimensions are very large. We can perform special processing for all three-channel textures here, but this is a hack. We can avoid this situation by forcing the user to obtain the sub-area outside first in the design of the API. Many APIs have changed from 3.x to 4.x, why not include this? What's more, it is not a commonly used API.

Redwarx008 avatar Nov 24 '23 01:11 Redwarx008

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.

We can avoid this situation by forcing the user to obtain the sub-area outside first in the design of the API.

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.

npip99 avatar Nov 25 '23 02:11 npip99

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.

Since this only needs to be done for all three-channel textures, the special processing is inelegant.

Redwarx008 avatar Nov 25 '23 11:11 Redwarx008

Hello, this issue also can be fixed by this PR! https://github.com/Zylann/godot_heightmap_plugin/issues/445

nackata avatar Jul 06 '24 13:07 nackata