3

i'm writting handler for OpenGL texture and i'm thinking about safety and performance. Which level of optimization should remove marked if statements?

 struct Texture2D { GLuint ID; inline Texture2D(): ID(0) {}; inline explicit Texture2D(GLuint id): ID(id) {}; ~Texture2D(); void GenTexture(bool regen = false); void DeleteTexture(); void BindTexture(); void Parameterf( GLenum pname, GLfloat param ); void Parameteri( GLenum pname, GLint param ); void glTexParameterfv( GLenum target, GLenum pname, const GLfloat *params ); void glTexParameteriv( GLenum target, GLenum pname, const GLint *params ); static Texture2D binded; }; inline void Texture2D::GenTexture(bool regen) { if(ID){ if(regen) DeleteTexture(); else return; } glGenTextures(1,&ID); } inline void Texture2D::DeleteTexture() { glDeleteTextures(1,&ID); ID = 0; } inline void Texture2D::BindTexture() { glBindTexture(GL_TEXTURE_2D, ID); binded.ID = ID; } inline void Texture2D::Parameterf( GLenum pname, GLfloat param ){ if(binded.ID == ID) // THIS BindTexture(); // THIS glTexParameterf(GL_TEXTURE_2D,pname,param); } inline void Texture2D::Parameteri( GLenum pname, GLint param ){ if(binded.ID == ID) // THIS BindTexture(); // THIS glTexParameterf(GL_TEXTURE_2D,pname,param); } inline Texture2D::~Texture2D() { DeleteTexture(); } // in this function void loadTexture(...) { Texture2D t; t.GenTexture(); t.BindTexture(); // if statements in next functions t.Parameterf(...); t.Parameterf(...); t.Parameterf(...); t.Parameterf(...); t.Parameterf(...); } 
15
  • Why should any level of optimisation do so? Commented Aug 4, 2010 at 14:19
  • 4
    shouldn't those be !=? (Also, past participle of bind is bound </grammar nazi>) Commented Aug 4, 2010 at 14:21
  • Did you maybe intend for those tests to be != ? The compiler is going to have a VERY tough time proving that the static variable isn't modified during opengl calls, so in general it can't eliminate the conditional test. Commented Aug 4, 2010 at 14:21
  • @Neil; they're inlined, so only the first is necessary. Commented Aug 4, 2010 at 14:22
  • @row I don't see what inlining has to do with it. Commented Aug 4, 2010 at 14:26

3 Answers 3

4

None.

Sad story, but C++ assumes that if you call a function, then this function might produce all kinds of side effects, including changing the value of binded.ID (which the function somehow knows to do)

Except

If you make sure that the functions you invoke have absolutely no legal way to know about your bindend.ID, either directly (by referencing it) or indirectly (because somebody else take a pointer of it and passed it around). Here's a simple example (assuming that side_effect() is in a different translation unit)

int side_effect(); int k=1; int main() { side_effect(); if (k!=0) return 0; side_effect(); if (k!=0) return 0; side_effect(); if (k!=0) return 0; } 

side_effect() can use and change k legally by declaring it as an external. No call of side_effect can be optimized away.

int side_effect(); static int k=1; int main() { side_effect(); if (k!=0) return 0; side_effect(); if (k!=0) return 0; side_effect(); if (k!=0) return 0; } 

It is not possible for side_effect to access k in an allowed manner, because you can't access statics in another translation unit. Therefore the code can be optimized to side_effect(); return 0 because k will not change, as long as side_effect() does not poke around in the memory. Which would be undefined behavior of course.

int side_effect(); void snitch(int*); static int k=1; int main() { snitch(&k); // !!! side_effect(); if (k!=0) return 0; side_effect(); if (k!=0) return 0; side_effect(); if (k!=0) return 0; } 

The compiler has no way to know, if snitch() saves its argument in a place where side_effect() can change it, therefore no call to side_effect() can be eliminated.

You get the same situation, if you have k as a local variable: If there is a possibility that some unknown routine can access k in a legal way, then the compiler can not make optimizations based on the value of k.

PS: Making k const does not help, because it is legal to cast a const away. const-ness can not be used as a optimization hint.

Sign up to request clarification or add additional context in comments.

1 Comment

Modern compilers that do link time code generation potentially have the information to know if k could be changed by side_effect. However it's still extremely difficult to prove it's safe in c++ so I wouldn't expect it, and agree with the answer in practise
2

This will depend on the compiler and your best bet is to test - compile and inspect the emitted machine code.

2 Comments

It shouldn't be depended on compiler because as explained Luther Blissett. Variable can be changed during GL calls.
Actually, the best bet is to just write clear code, and optimize only if you've determined that these statements are a bottleneck. But yes, testing is the only way to determine what a compiler does.
2

No level of optimisation can (correctly) remove those tests. They could only be removed if both arguments were compile-time constants, and neither of these are, or if the compiler can prove that they won't change value between the tests.

Since binded is static, the compiler can't know that the calls to the GL functions won't alter it.

1 Comment

Not completely true, it can also be removed if they're local to the stackframe, but these are global. +1 either way.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.