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

[3.x] Unbind texture slots when changing framebuffer #80481

Merged
merged 1 commit into from
Aug 16, 2023

Conversation

lawnjelly
Copy link
Member

@lawnjelly lawnjelly commented Aug 10, 2023

Prevent bugs whereby texture still in use.

Roughly based on @clayjohn's draft clayjohn@baf691a

Fixes #61632

Maintains a list of texture slots that have been bound in the current frame, so they can be unbound when setting a new render target.

Notes

  • Have pushed forward with this as clayjohn is busy with 4.x
  • I wasn't sure if we needed to keep it in frame.
  • Rather than keeping this up to date manually I figured a wrapper might be a better bet.

Clayjohn's original draft did this:

	// Unbind user textures that have been set since the last render target change.
	// Unbind the internal slots that may have been used by  Godot.
	for (int i = 1; i <= 13; i++) {
		glActiveTexture(GL_TEXTURE0 + storage->config.max_texture_image_units - i);
		glBindTexture(GL_TEXTURE_2D, 0);
	}
	// Unbind from 0 up to the max texture slot used by the user.
	for (int i = 0; i < storage->frame.max_texture_binding + 2; i++) {
		glActiveTexture(GL_TEXTURE0 + i);
		glBindTexture(GL_TEXTURE_2D, 0);
	}

This seems likely to duplicate unbinding for a bunch of slots.

I experimented with keeping a maximum slot from the beginning and minimum from the end of the texture unit range, but decided in the end it was probably the best trade off to keep a list of slots in use. In combination with a lookup table (bitfield used here) it should be very efficient with negligible cost.

@lawnjelly lawnjelly changed the title Unbind texture slots when changing framebuffer [3.x] Unbind texture slots when changing framebuffer Aug 10, 2023
@lawnjelly lawnjelly added this to the 3.x milestone Aug 10, 2023
@lawnjelly lawnjelly force-pushed the clay_unbind_textures branch 4 times, most recently from 8e51051 to 096d6cd Compare August 12, 2023 09:59
Prevent bugs whereby texture still in use.
@lawnjelly lawnjelly marked this pull request as ready for review August 12, 2023 10:07
@lawnjelly lawnjelly requested a review from a team as a code owner August 12, 2023 10:07
@lawnjelly lawnjelly modified the milestones: 3.x, 3.6 Aug 14, 2023
Copy link
Member

@clayjohn clayjohn left a comment

Choose a reason for hiding this comment

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

Looks great! I think the overhead of accidentally unbinding a texture slot that wasn't bound would be pretty low. But this doesn't add much more complexity to have the peace of mind that we aren't unbinding too much.

It would be nice to have this forward ported to 4.x as well.

@lawnjelly
Copy link
Member Author

It would be nice to have this forward ported to 4.x as well.

Sure, it's pretty simple.

@akien-mga akien-mga merged commit dcb097c into godotengine:3.x Aug 16, 2023
13 checks passed
@akien-mga
Copy link
Member

Thanks!

@harrisyu
Copy link
Contributor

I found 8 errors before running a project like this:

E 0:00:00.183   RasterizerStorageGLES3::GLWrapper::gl_active_texture: Condition "(unsigned int)p_texture >= texture_unit_table.get_num_bits()" is true.
  <C++ Source>  D:\build\godot-switch\godot-nx\drivers\gles3\rasterizer_storage_gles3.h:1519 @ RasterizerStorageGLES3::GLWrapper::gl_active_texture()

I think is because
gl_wrapper.initialize() must be called before using gl_wrapper.gl_active_texture().
get_num_bits() is 0 before gl_wrapper.initialize() .

@lawnjelly
Copy link
Member Author

You are correct initialize() is meant to be called before gl_active_texture(). It won't cause any problems but I'll see if I can work out where this is being called from, and see if we can initialize() earlier. 👍

@lawnjelly
Copy link
Member Author

Ah yes, silly me, I must have only tested GLES2. GLES3 is calling active texture in the storage initialize before the wrapper is initialized. Will fix this (should just be initializing the wrapper earlier in the function).

Until then just ignore these messages, they are benign.

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

Successfully merging this pull request may close these issues.

4 participants