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

Error message when using texture from viewport inside itself #81928

Open
JonqsGames opened this issue Sep 19, 2023 · 8 comments
Open

Error message when using texture from viewport inside itself #81928

JonqsGames opened this issue Sep 19, 2023 · 8 comments

Comments

@JonqsGames
Copy link
Contributor

Godot version

4.2

System information

Windows 11

Issue description

Implementing a similar effect than describe in : https://www.youtube.com/watch?v=VSwVwIYEypY
I think it's intended but server spams an error :
RenderingDeviceVulkan::draw_list_bind_uniform_set: Attempted to use the same texture in framebuffer attachment and a uniform (set: 1, binding: 3), this is not allowed.
It's still works as expected, could this error be removed or ignored ?
Maybe it could be a warning clarifying that this has 1 frame delay.

Maybe doing this is not recommended in that case this issue can be usefull to other people know why

Steps to reproduce

Project from the tutorial is raising the error : https://github.com/CBerry22/Godot-Water-Ripple-Simulation-Shader

Minimal reproduction project

Create a viewport
Inside that viewport use the ViewportTexture from parent in a shader.

@nicholaskim6
Copy link

I'm also seeing this constantly and am wondering if there's a fix

@inkusgames
Copy link

Tracking down and trying to solve the same issue.

I am very new to GODOT so I may be making a rookie error.

I downloaded the sample project from the above video and when I execute that project I don't see the error, so in that we are having a different experience. However if I create any viewport and add it as the input texture on a shader I get the same error you reporting.

E 0:00:00:0784 RenderingDeviceVulkan::draw_list_bind_uniform_set: Attempted to use the same texture in framebuffer attachment and a uniform (set: 1, binding: 1), this is not allowed. <C++ Error> Condition "attachable_ptr[i].texture == bound_ptr[j]" is true. [godot_feedbackshader_test.zip](https://github.com/godotengine/godot/files/13476979/godot_feedbackshader_test.zip) <C++ Source> drivers\vulkan\rendering_device_vulkan.cpp:7241 @ RenderingDeviceVulkan::draw_list_bind_uniform_set()

I created a basic small project to test the issue.

godot_feedbackshader_test.zip

The above just increments the red channel each frame pushing UV into G and B channels. The error reports but does not stop the function from working.

Additionally the error does not happen if I change from Forward+ to Compatibility render mode.

@JonqsGames
Copy link
Contributor Author

I think the only thing to decide here is : Could this be a warning ?
I don't know exactly what is the risk of doing this, from what i understand it can't do any warm but the output can be a bit unpredictable in some case (The clear option you choose for the viewport for example).
IMO this can be a simple warning (and it could be ignored if needed)

@clayjohn
Copy link
Member

clayjohn commented Nov 27, 2023

I think some context behind this error would be helpful.

First, this error message has been around since the Vulkan renderer was written. Its not a new error.
Second, this error is for your information, it doesn't change any behaviour and its only enabled in debug builds
Last, this error protects you from doing something that is not technically supported by OpenGL or Vulkan.

That last point needs some clarification, especially since it appears to work when using OpenGL and Vulkan.

Writing to a framebuffer (viewport) and sampling that framebuffer at the same time is undefined behaviour in OpenGL and Vulkan. Undefined behaviour means that the specification doesn't tell GPU driver authors what to do. In Vulkan, you have the concept of framebuffer local load operations which allow you to read from the current pixel in the framebuffer, but this has some clear restrictions that make it very limited.

That being said, if a GPU driver author wants to allow you to read from the same framebuffer you are writing to, they can allow it. You just can't count on it working on other machines. The catch is that there is no way to check in advance if the GPU driver supports this. Its totally random, and they are not guaranteed to maintain support across driver updates either. So it might work on your computer one day, then break the next when you get an update.

In my experience, desktop GPU drivers mostly allow reading from the currently bound framebuffer as they tend to not be very strict while mobile drivers tend to forbid it entirely. Notably, ANGLE also totally forbids reading from the currently bound framebuffer. So any shader that relies on doing so will fail when exported to the web.

If you are writing a game that will only ever run on your device (and you control driver updates), its fine to rely on this behaviour. Otherwise, it is much safer to never rely on it. Since the Godot team doesn't control the hardware that Godot runs on, we need to forbid reading from the currently bound framebuffer (which is what ANGLE does).

If anything, the error should be added to the compatibility renderer as well so that users can get a helpful error before they rely on undefined behaviour that will break their game on mobile and web and any number of other devices

edit: For those of you following this issue, try running the MRP from the comment above in a web export. You end up with a blank screen and the following error spam:

image

@inkusgames
Copy link

Thank you for the details breakdown of the error message.

Is there an alternative and less risky approach if we are trying to write a processing shader the uses its output on the next pass as a source?

@clayjohn
Copy link
Member

Thank you for the details breakdown of the error message.

Is there an alternative and less risky approach if we are trying to write a processing shader the uses its output on the next pass as a source?

Yep, you just need to use two viewports. The reproduction project from the OP was actually updated to use the correct approach 6 days after this PR was opened https://github.com/CBerry22/Godot-Water-Ripple-Simulation-Shader. You can reference that project both before and after the change to see exactly what you need to do

@inkusgames
Copy link

I reworked the MRP to correctly implement the solution as @clayjohn pointed out.

https://github.com/inkusgames/godot4_shader_viewport_example

Thanks for the knowledge.

@dalexeev
Copy link
Member

dalexeev commented Sep 9, 2024

Related:

I noticed that the error only appears in Forward+ and Mobile modes, not in Compatibility. In Forward+/Mobile, the error only occurs if the ViewportTexture renders canvas items visible on the viewport itself. Rendering canvas items from outside the camera's visibility works correctly.

There is a workaround with CanvasLayer, see #70193 (comment).

Another workaround is to copy the ViewportTexture to an ImageTexture. Make sure render_target_update_mode is set to UPDATE_WHEN_PARENT_VISIBLE or UPDATE_ALWAYS.

extends Node2D

var _viewport_texture: ViewportTexture
var _image_texture: ImageTexture

@onready var _sub_viewport: SubViewport = $SubViewport
@onready var _sprite_2d: Sprite2D = $Sprite2D

func _ready() -> void:
    _sub_viewport.world_2d = get_world_2d()
    _viewport_texture = _sub_viewport.get_texture()
    _image_texture = ImageTexture.create_from_image(_viewport_texture.get_image())
    _sprite_2d.texture = _image_texture

func _process(_delta: float) -> void:
    _image_texture.update(_viewport_texture.get_image())

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

No branches or pull requests

7 participants