Jump to content
  • Advertisement
Sign in to follow this  
irreversible

OpenGL Texture updates: something I'm missing or driver quirk?

This topic is 1363 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

My OpenGL wrapper is pretty extensive so it's possible I'm missing something very trivial elsewhere. In fact, I'm very strongly inclined towards this, although I've gone over my own code with a pretty fine tooth comb. However, this behavior confounded me for a full day before I finally found the (apparent) root cause and I'm still not convinced why it would occur.

 

The problem has to do with texture updates via glMapBuffer(). In my case I needed to update two textures side by side - one continuously, one on demand. The former updated properly, the second one behaved in a most peculiar way.

 

As I tried to update the second texture and use it in two different places (eg rendering two quads with it in slightly different places in my code) I found that one of the calls drew the updated texture while the other one, despite the fact that everything was identical, drew the original texture, no matter what I did.

 

For the longest time this made absolutely no sense so I decided to dig deep and dismantle my entire texturing pipeline to make sure I wasn't accidentally changing it back, creating a duplicate or whatnot. Everything checked out. Until I compared how I was initializing either of the textures: I was generating the continuous one without any default data; the other one I provided with a default buffer.

 

Frankly I'm out of ideas as to why one should work as expected and the other should behave so seemingly irrationally, other than suspecting that the driver was quietly restoring the original texture data without me implicitly telling it to do so. Except that it makes no sense for the texture data to be persistent. The PBO update is asynchronous and identical in both cases. Additionally, since I'm still not finished on the driver wrapper, I have a tendency to check each and every GL call for errors and they all pass with flying colors.

 

Unless I'm blind, this is the only thing the docs have to say about the data pointer for glTexImage2D():

 

 

 

data may be a null pointer. In this case, texture memory is allocated to accommodate a texture of width width and height height. You can then download subtextures to initialize this texture memory. The image is undefined if the user tries to apply an uninitialized portion of the texture image to a primitive.

 

This specifies nothing about the behavior of a texture with default data.

 

Is this normal? Was I missing something incredibly trivial all these years and somehow just managed to get lucky with my textures? Or am I just not reading between the lines?

 

Incidentally, just to be sure I also updated my Nvidia drivers and the behavior is identical on current drivers and drivers from 7 months ago.

Share this post


Link to post
Share on other sites
Advertisement

Firstly, you want to be careful with OpenGL docs. You've linked to the OpenGL ES version of glTexImage2D which won't necessarily be the same as the one in OpenGL. You'l notice there's no mention of pixel buffer objects on that page.

 

It does mention the data parameter in a few places, but it's inline with the function description:

Data is read from data as a sequence of unsigned bytes or shorts, depending on type [...]

 

In short, if you don't have a pixel buffer object bound when you're calling glTexImage2D, then the pixel data in the pointer provided is stored in the texture. If one is bound, then the pixel data will be copied from the pixel buffer object, using data as an offset into the buffer.

 

As I tried to update the second texture and use it in two different places (eg rendering two quads with it in slightly different places in my code) I found that one of the calls drew the updated texture while the other one, despite the fact that everything was identical, drew the original texture, no matter what I did.

That sounds like an issue with the driver to me. I'm fairly certain that draw calls following a glTexImage2D call should wait on pending texture uploads if it happens asynchronously (in the case of using a pixel buffer object). Do you have any other graphics cards from a different vendor that you can test this on?

Share this post


Link to post
Share on other sites


Firstly, you want to be careful with OpenGL docs. You've linked to the OpenGL ES version of glTexImage2D which won't necessarily be the same as the one in OpenGL. You'l notice there's no mention of pixel buffer objects on that page.

 

Ah - indeed, I googled glTexImage2D directly and picked the first link. Thanks for pointing it out.

 


In short, if you don't have a pixel buffer object bound when you're calling glTexImage2D, then the pixel data in the pointer provided is stored in the texture. If one is bound, then the pixel data will be copied from the pixel buffer object, using data as an offset into the buffer.

 

This reads like normal expected behavior and is what I assumed in the first place.

 


[quote name='Irreversible']
As I tried to update the second texture and use it in two different places (eg rendering two quads with it in slightly different places in my code) I found that one of the calls drew the updated texture while the other one, despite the fact that everything was identical, drew the original texture, no matter what I did.[/quote]
That sounds like an issue with the driver to me. I'm fairly certain that draw calls following a glTexImage2D call should wait on pending texture uploads if it happens asynchronously (in the case of using a pixel buffer object). Do you have any other graphics cards from a different vendor that you can test this on?

 

I'm on a 750M right now. I do have a 460GTX on my desktop, but I don't think even any of my friends have a non-Nvidia card.

 

Overall this seems like a very obvious bug that should rear its head pretty quickly. Especially since I encountered this on v342.52, which was released last June or July and it's still here in the latest driver build (v347.52 from a few days ago).

Share this post


Link to post
Share on other sites

I'd suggest that you test this without the PBO.

 

A PBO is really only useful if you're not using the texture until a few frames after you update it, otherwise you'll likely find that just using glTexSubImage2D (not glTexImage2D which will fully respecify the texture) gives better performance and more predictable behaviour.

Share this post


Link to post
Share on other sites

I don't quite understand what you are doing with "default buffers" or what these are (maybe a few lines of code would help better understanding what you're doing).

 

Regardless, glTexImage2D has three (not two) modes of operation:

  1. No buffer object is bound and data = nullptr    ? Reserve memory for a texture of the specified size, do nothing else (not even zero memory). If something happens to be in that memory, you will see it. Whatever it is, it's undefined. It might just as well be some old buffer's contents that "looks about right" but is a few frames old.
  2. No buffer object is bound and data != nullptr   ? Reserve memory for a texture of the specified size, and then read pixel data from data. Presumably this works by copying into an unnamed buffer object nowadays, but it's still OpenGL 1.1 functionality. Which, in any case, must run synchronously since the driver cannot know for how long the data pointed to by data remains valid, so don't expect stellar performance.
  3. Buffer object is bound   ? Reserve memory for a texture of the specified size, type-pun data into an unsigned integer, and read pixel data from the buffer object starting at the offset data. This is what you will want to do in almost every case.

glTexSubImage2D, by contrast, only knows two very similar modes of operation: Copy data either from a buffer object (if any) or from the pointer data (if there's no buffer) into already allocated texture storage.

Edited by samoth

Share this post


Link to post
Share on other sites

do nothing else (not even zero memory). If something happens to be in that memory, you will see it. Whatever it is, it's undefined. It might just as well be some old buffer's contents that "looks about right" but is a few frames old.

Keep in mind that this specific part of the behaviour is not explicitly guaranteed. Some systems explicitly zero the memory as a security precaution (i.e. to prevent you reading back the content from another app's framebuffer, and OCR'ing any text).

Share this post


Link to post
Share on other sites

I'd suggest that you test this without the PBO.

 

A PBO is really only useful if you're not using the texture until a few frames after you update it, otherwise you'll likely find that just using glTexSubImage2D (not glTexImage2D which will fully respecify the texture) gives better performance and more predictable behaviour.

 

I'm pretty sure I did try a direct upload as well. I'll check again when I get some time.

 


I don't quite understand what you are doing with "default buffers" or what these are (maybe a few lines of code would help better understanding what you're doing).

 

The default contents are just the initial texture data. I'm creating my textures synchronously, because I'm already marshalling the commands to the render thread. In practice this means that my code fails to modify a texture that is created as-is when it is allocated, but can modify a texture buffer that is reserved, but whose data is not copied at creation time. Makes sense?

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

We are the game development community.

Whether you are an indie, hobbyist, AAA developer, or just trying to learn, GameDev.net is the place for you to learn, share, and connect with the games industry. Learn more About Us or sign up!

Sign me up!