Repository: godotengine/godot (language: cpp)

Issue:
Rendering issues using BackBufferCopy node in 4.4 beta 1
### Tested versions

- Noticed issue with Compatibility renderer in v4.3.stable.official [77dcf97d8] but at the time assumed it was my lack of knowledge of the engine and what was possible with shaders. Not present in Forward+ renderer in 4.3 stable
- v4.4.dev7.official [46c8f8c5c] Noticed issue with Forward+ renderer. Still present in Compatibility renderer.
- v4.4.beta1.official [d33da79d3] Tested and still present with both renderers.
- Haven't had the the chance to see which version the issue starts at yet.

### System information

Godot v4.3.stable - Windows 10.0.19045 - Vulkan (Forward+) - dedicated NVIDIA GeForce RTX 3060 (NVIDIA; 32.0.15.6636) - 12th Gen Intel(R) Core(TM) i5-12400F (12 Threads)

### Issue description

I have a Camera2D node, and multiple TileMapLayers. The issue seems related to the TileMapLayer which is a child of a BackBufferCopy node. That TileMapLayer uses an additive blend mode, and has a sibling which uses a multiplicative blend.
When zooming out, there are bright lines appearing across the screen, with the rest of the areas appearing as though their additive blend mode no longer applies. Areas behind are darker, so it seems that the mult blend on the lower layer is still in effect.
I tested hiding and un-hiding each layer. The issue was still present whether the mult layer was visible or not.
Issue was still present if I removed the additive blend shader from the first layer.
Issue disappears if I remove the layer form the BackBufferCopy node.
I considered it could be related to the number of scenes I had displayed as I'm using a scene collection tileset source that's quite large, but my reproduction has very few nodes or textures.

I was using the BackBufferCopy for my first attemps at shaders, and didn't check it was still needed when I found a better way, so my project no longer needs this, but still seemed a good idea to report it. 
I tried to search through the issues, but none seemed similar enough that I could be sure they seemed related with my level of experience with rendering.

**Expected behaviour**
4.3 stabke, Forward+
This is what I expect to see:

https://github.com/user-attachments/assets/62c48aa7-5388-4632-87ef-8f8feed13d12

**Unexpected**
4.3 stable, Compatibility
Current version if I change renderers. What I saw early on and didn't understand if I was just doing something wrong:

https://github.com/user-attachments/assets/0e69a935-7d44-41d1-b1fd-9b72ea3a5b18

4.4 dev7, Forward+
What my project looks like if I open it in the newer version. beta 1 looks the same:

https://github.com/user-attachments/assets/928dd3f8-ea06-4342-a18e-91353e5a9571

4.4 beta 1, Forward+
My minimal reproduction version:

https://github.com/user-attachments/assets/4d2c176c-b82e-4ce3-a024-a29ecd54e473


### Steps to reproduce

Add a TileMapLayer as a child of a BackBufferCopy. Have other TileMapLayers below.
Add 400 x 400 tile area to first layer with tiles that are 128 x 128 pixels
Tiles on other layers (including BackBufferCopy child layer) are 1024 x 1024 pixels. Add enough to cover the first layer.
Add a Camera2D node and zoom the camera out far.
Tested with project below and issue first appears when map size is 128 x 128 tiles. 127 and lower doesn't show the issue.

### Minimal reproduction project (MRP)

Created with v4.4.beta1.official [d33da79d3]
[renderingreproduction.zip](https://github.com/user-attachments/files/18455493/renderingreproduction.zip)


Discussion / hints:
I just got the chance to test this in a few more releases.

v4.4.dev2.official [97ef3c837] and v4.4.dev3.official [f4af8201b] - I don't see the issue when opening my project.

v4.4.dev4.official [36e6207bb] - First version I see the issue in.

I can confirm this on 4.4.beta1 (Linux + NVIDIA) when using Forward+ or Mobile.

I bisected the regression to a657ea42f1e656695f502a0e5f50ea9e0e041c3e. cc @stuartcarnie 
I am reading that compatibility is also seeing the issue, meaning there is a general problem with batching, as the `RenderRD` batching implementation was copied from the GLES3 implementation.
>Unexpected
>4.3 stable, Compatibility
>Current version if I change renderers. What I saw early on and didn't understand if I was just doing something wrong:

Can also be reproduced on MacMini M1. _(`4.3 stable, OpenGL API 4.1 Metal - 89.3 - Compatibility`)_
I wasn't able to try out previous versions. --> `TileMapLayer` is not found

![Image](https://github.com/user-attachments/assets/75c5aed6-9ba8-4a4e-9476-55551cab1563)
I think I was able to find a workaround for "Compatibility".
@TanyaPegasus Does it also work in your productive project?

The issue is reproducible from a certain number of objects if they are visible. `$BackBufferCopy.show_behind_parent = true` somehow prevents this. (and `$BackBufferCopy/Add.top_level = true` to see the changes to the layer)

<details><summary>screenshot</summary>

![Image](https://github.com/user-attachments/assets/a0b256ed-0de7-45e6-b901-6f1ae75c77cc)

</details>

```gdscript
func _ready() -> void:
	$BackBufferCopy.show_behind_parent = true
	$BackBufferCopy/Add.top_level = true
	set_biome_tiles()
	set_overlay()
```

![Image](https://github.com/user-attachments/assets/c56c300b-b1ba-45aa-ad21-1812b70fa8ab)
Yes, I can confirm that with the Compatibility renderer in v4.3.stable.official [77dcf97d8] that code prevents the rendering issue in my project with significantly more scenes and textures being shown.
I do have more layers in my main project, and that puts an overlay over layers that aren't supposed to have one. I'm sure knowing something that fixes it helps narrow down the cause though.

I'll check Forward+ on the beta version now.
No rendering issues using forward+ and v4.4.beta1.official [d33da79d3] if I add this to my _ready function:

```
$BackBufferCopy.show_behind_parent = true
$BackBufferCopy/Add.top_level = true
```

As I said, it's also putting the overlay too high in my specific project, but I image that could be more to do with me not understanding how to tweak that to fit better.
> As I said, it's also putting the overlay too high in my specific project, but I image that could be more to do with me not understanding how to tweak that to fit better.

![Image](https://github.com/user-attachments/assets/2812968f-250e-4dc6-b588-0a5690850268)

with `z_index` you have more control over the order, this workaround also works without `show_behind_parent` and `top_level`


```gdscript
	$BackBufferCopy.z_index = -1
	$BackBufferCopy/Add.z_index = 10
```
_Reproducible with 4.4 beta 1 (compatibility and forward+ / Metal on MacOS)_


I was able to partially understand the C++ sources. Adjusting `show_behind_parent` or `z_index` and "executing" `BackBufferCopy` first is not a solution, because this will or can disable the backbuffer.


As soon as I find more time, I will first try to create an MRP with fewer nodes / draw calls.

<details><summary>some details</summary>

----------- 

The issues occur as soon as the `item_buffer_size` limit is reached and `BackBufferCopy` actions have been performed beforehand. In the RenderDoc application it looks like the correct buffers are not being used. _(To render the textures correctly. But I would need to do more testing first to confirm this)_

https://github.com/godotengine/godot/blob/b0655dc86f096b3496a9ab5b18965676d4fb35ba/drivers/gles3/rasterizer_canvas_gles3.cpp#L1549

![Image](https://github.com/user-attachments/assets/ab4ac68c-c069-4323-840f-8356543ebf3d)

OpenGL ES (Compatibility)
[rendering/gl_compatibility/item_buffer_size](https://docs.godotengine.org/en/latest/classes/class_projectsettings.html#class-projectsettings-property-rendering-gl-compatibility-item-buffer-size)

maybe for Vulkan (Forward+ / Mobile)
[rendering/2d/batching/item_buffer_size](https://docs.godotengine.org/en/latest/classes/class_projectsettings.html#class-projectsettings-property-rendering-2d-batching-item-buffer-size)

</details>
@Alex2782 nice find – that is indeed the issue; when increasing the `rendering/2d/batching/item_buffer_size` to 100000, the issue doesn't show up until zooming completely out. 

I will continue to debug the issue tonight to see what is going on.

Fix patch:
diff --git a/drivers/gles3/rasterizer_canvas_gles3.cpp b/drivers/gles3/rasterizer_canvas_gles3.cpp
index 55a6e4826050..8cbbda249b00 100644
--- a/drivers/gles3/rasterizer_canvas_gles3.cpp
+++ b/drivers/gles3/rasterizer_canvas_gles3.cpp
@@ -568,6 +568,8 @@ void RasterizerCanvasGLES3::canvas_render_items(RID p_to_render_target, Item *p_
 
 	// Clear out state used in 2D pass
 	reset_canvas();
+	state.current_batch_index = 0;
+	state.canvas_instance_batches.clear();
 	state.current_data_buffer_index = (state.current_data_buffer_index + 1) % state.canvas_instance_data_buffers.size();
 	state.current_instance_buffer_index = 0;
 }
@@ -662,8 +664,6 @@ void RasterizerCanvasGLES3::_render_items(RID p_to_render_target, int p_item_cou
 
 	if (index == 0) {
 		// Nothing to render, just return.
-		state.current_batch_index = 0;
-		state.canvas_instance_batches.clear();
 		return;
 	}
 
@@ -807,8 +807,6 @@ void RasterizerCanvasGLES3::_render_items(RID p_to_render_target, int p_item_cou
 	}
 
 	glDisable(GL_SCISSOR_TEST);
-	state.current_batch_index = 0;
-	state.canvas_instance_batches.clear();
 	state.last_item_index += index;
 }
 
diff --git a/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp b/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp
index de376599de4c..6388bc864110 100644
--- a/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp
+++ b/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp
@@ -913,6 +913,9 @@ void RendererCanvasRenderRD::canvas_render_items(RID p_to_render_target, Item *p
 		RenderingServerDefault::redraw_request();
 	}
 
+	texture_info_map.clear();
+	state.current_batch_index = 0;
+	state.canvas_instance_batches.clear();
 	state.current_data_buffer_index = (state.current_data_buffer_index + 1) % BATCH_DATA_BUFFER_COUNT;
 	state.current_instance_buffer_index = 0;
 }
@@ -2286,9 +2289,6 @@ void RendererCanvasRenderRD::_render_batch_items(RenderTarget p_to_render_target
 
 	RD::get_singleton()->draw_list_end();
 
-	texture_info_map.clear();
-	state.current_batch_index = 0;
-	state.canvas_instance_batches.clear();
 	state.last_instance_index += instance_index;
 }
 
@@ -2975,7 +2975,7 @@ void RendererCanvasRenderRD::_canvas_texture_invalidation_callback(bool p_delete
 	KeyValue<RID, TightLocalVector<RID>> *kv = static_cast<KeyValue<RID, TightLocalVector<RID>> *>(p_userdata);
 	RD *rd = RD::get_singleton();
 	for (RID rid : kv->value) {
-		// the invalidation callback will take care of clearing rid_set_to_uniform_set cache also
+		// The invalidation callback will also take care of clearing rid_set_to_uniform_set cache.
 		rd->free(rid);
 	}
 	kv->value.clear();
@@ -3008,7 +3008,7 @@ void RendererCanvasRenderRD::_render_batch(RD::DrawListID p_draw_list, CanvasSha
 			uniform_set = &iter->data;
 			RD::get_singleton()->uniform_set_set_invalidation_callback(rid, RendererCanvasRenderRD::_uniform_set_invalidation_callback, (void *)&iter->key);
 
-			// If this is a CanvasTexture, it must be tracked so that any changes to the diffuse, normal
+			// If this is a CanvasTexture, it must be tracked so that any changes to the diffuse, normal,
 			// or specular channels invalidate all associated uniform sets.
 			if (ts->owns_canvas_texture(p_batch->tex_info->state.texture)) {
 				KeyValue<RID, TightLocalVector<RID>> *kv = nullptr;


Test patch: