DH API does not notify of texture change

Binding textures returned by the DH API as usual* results in broken code. (usual* = how you'ld usually do it in MC modding)
DhApiResult<Integer> depthId = DhApi.Delayed.renderProxy.getDhDepthTextureId();
if(depthId.success) {
RenderSystem.activeTexture(GL_TEXTURE6);
RenderSystem.bindTexture(depthId.payload);
}
DhApiResult<Integer> depthId = DhApi.Delayed.renderProxy.getDhDepthTextureId();
if(depthId.success) {
RenderSystem.activeTexture(GL_TEXTURE6);
RenderSystem.bindTexture(depthId.payload);
}
The issue here is that DH doesn't use Minecraft's built-in GL State manager RenderSystem (yarn mappings). The problem only becomes apparent when DH reinitializes the LODRenderer. This action will: 1. glDeleteTextures the old texture 2. glGenTextures a new texture 3. On some systems the old and new texture will have the same id (valid by OpenGL Spec) 4. Call RenderSystem.bindTexture with the same texture id. 5. RenderSystemwill not call glBindTexture because it thinks the same old texture is still bound. 6. A deleted texture is now bound to GL_TEXTURE6 I hope my description was clear enough. The DH API does not provide a way to notice this texture change. Probably the only way to circumvent this issue is on my side is to do this:
RenderSystem.bindTexture(depthId.payload);
GL11.glBindTexture(GL_TEXTURE6, depthId.payload);
RenderSystem.bindTexture(depthId.payload);
GL11.glBindTexture(GL_TEXTURE6, depthId.payload);
This will keep MC's state management and the "real" state "in sync", but results in wasted performance and is generally not a nice solution,
21 Replies
BackSun
BackSun•15mo ago
I don't understand your issue. Are you only querying the depth texture once and assuming it will never change?
Wendelin
WendelinOP•15mo ago
No, I query it every frame. But when DH initializes a new LODRenderer (when the config is changed f.e.), the new depth texture gets the same OpenGL id as the previous one had[1] (which is permitted by the spec). So when I query it again and call RenderSystem.bindTexture(depthId), the state manger fails to detect that the texture has changed, since the id stayed the same. [1] this is not guaranteed, but it can and does happen. i.e.
void bindTexture(int id) {
if(oldId != id)
GL11.bindTexture(id)
}
void bindTexture(int id) {
if(oldId != id)
GL11.bindTexture(id)
}
The issue is that the id stayed the same, so the new texture is never bound. And there is no way for me to know when the texture changed.
BackSun
BackSun•15mo ago
Why not just use GL11.BindTexture() then? Otherwise I could potentially add events for when the LodRenderer has been created/destroyed.
Wendelin
WendelinOP•15mo ago
GL11.BindTexture has two drawbacks: - I still have to bind the texture every frame, even if it is still bound from the previous frame. - RenderSystem won't be aware of the updated binding. Meaning that I also would have to 1) query the previously bound texture 2) bind the depth texture 3) restore the previously bound texture It would be better if I could only bind the texture when it isn't already bound. But since the texture id is not reliable to detect such a change, I can't. I think an event would be the best solution. Alternatively DH could also use RenderSystem (or the underlying GlStateManger), instead of the current solution (GLState.saveState and restore). This would also somewhat improve the performance of DH, because currently, as I see it, GLState.saveState does a bunch of glGet calls every frame, which can be rather slow on some systems. But I'm not sure it would be worth the effort.
BackSun
BackSun•15mo ago
I don't think re-binding the texture every frame is that big of an issue. We have to bind and unbind a number of things every frame to prevent modifying Minecraft's GL state. We are very intentionally not using MC's RenderSystem or GlStateManager since we try to keep our systems as separate from MC as possible. Again, I can look into adding an API event that would fire when the renderer is created/destroyed or when the textures are (re)created.
Wendelin
WendelinOP•15mo ago
I have to agree, re-binding the texture every frame is not such a big deal, but still. An event would be much appreciated. If you'll be adding an event, I'ld suggest a ResourceChanged or RenderTargetChanged event, rather than a LodRenderer related one, since that is what's actually of interest. Knowing when the LodRenderer is initialized is not very useful by itself.
BackSun
BackSun•15mo ago
My current plan is something along the lines of Lod Depth/Color Textures Created Event
Wendelin
WendelinOP•15mo ago
Yeah, something like that would be great. But does that mean you'll finally have to update the modrinth page 😄?
BackSun
BackSun•15mo ago
Once the next stable build of DH has been released, yes 😉
Wendelin
WendelinOP•3w ago
So, I just realized Better Clouds still has this issue. So what is the correct solution now? Listen to the DhApiBeforeTextureClearEvent, set a flag, and call glBindTexture in addition to GlStateManager._bindTexture to make the two sync up, if the flag is set?
BackSun
BackSun•3w ago
Please refresh my memory. What issue specifically are you referencing? Also as of the latest DH version we are firing MC’s GL state manager alongside manually firing the underlying GL calls, so those should be synced up now.
Wendelin
WendelinOP•3w ago
The issue is that, if I remember it correctly, DH generates a new texture, but that happens to have the same ID as the old one. GlStateManager tracks which texture is bound to what unit and doesn't rebind if the ID is the same. So the new texture is never bound. The "correct" way would be to use _deleteTexture when DH deletes the old texture, since that clears GlStateManager's internal state for all units to which the ID was bound to. Also, why don't people ever report such bugs. This has been an issue with Better Clouds and DH since over a year, and I only just found out about it because I used both together myself. 😭 I'm on the latest version (1.21.5) of DH btw
BackSun
BackSun•3w ago
GitLab
common/src/main/java/com/seibel/distanthorizons/common/wrappers/min...
This is a mod that adds a Level Of Detail (LOD) system to Minecraft. This implementation renders simplified chunks outside of the normal render distance allowing for an...
Wendelin
WendelinOP•3w ago
Something fishy is going on. Simply subscribing to DhApiBeforeTextureClearEvent makes the issue go away (it's also never called?). I guess I need to dig deeper. Nevermind, that had a different cause. Rights so DhApiBeforeTextureClearEvent is not what I thought it was. DhApiColorDepthTextureCreatedEvent is maybe the right one.
Wendelin
WendelinOP•3w ago
Yes, seems you did
No description
Wendelin
WendelinOP•3w ago
I assume this will be fixed, but for backwards compatability, would you say DhApiColorDepthTextureCreatedEvent is the correct event to fix the GlStateManager state?
BackSun
BackSun•3w ago
Fair enough, I’ll have to get those fixed at some point. I don’t understand the question.
Wendelin
WendelinOP•3w ago
If I'm going to fix this DH issue in my mod, so that users can use older versions of DH without my mod breaking, then I need to fix up the GlStateManager state. Is DhApiColorDepthTextureCreatedEvent the correct event to do that? Basically I would sync up the GlStateManager texture binding state after every time that this even is fired. Just want to be sure that this event covers all cases when DH's depth texture is (re)created.
BackSun
BackSun•3w ago
Gotcha. Dang it past me, why did you fire that event before the texture is created instead of after, that makes it basically useless… I’ll have to fix that someday. As a temporary fix DhApiBeforeTextureClearEvent looks to be your best bet.
Wendelin
WendelinOP•3w ago
Nah, DhApiBeforeTextureClearEvent is fired every frame. I mistakenly assumed different. But DhApiColorDepthTextureCreatedEvent seems fine if I delay the syncing to the next time my render code is called. Anyway, thanks for the responses! I'm happy I'm finally able to fix this issue after I forgot about it for a year 😅
BackSun
BackSun•3w ago
lol happy I was able to help. I’ll have to look into cleaning up those API methods at some point, although I was planning on going on vacation for a bit, so we’ll see when that happens.

Did you find this page helpful?