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(...);
}
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 thatside_effect()is in a different translation unit)side_effect()can use and changeklegally by declaring it as an external. No call ofside_effectcan be optimized away.It is not possible for
side_effectto accesskin an allowed manner, because you can't access statics in another translation unit. Therefore the code can be optimized toside_effect(); return 0because k will not change, as long as side_effect() does not poke around in the memory. Which would be undefined behavior of course.The compiler has no way to know, if
snitch()saves its argument in a place whereside_effect()can change it, therefore no call toside_effect()can be eliminated.You get the same situation, if you have
kas a local variable: If there is a possibility that some unknown routine can accesskin a legal way, then the compiler can not make optimizations based on the value of k.PS: Making
kconst does not help, because it is legal to cast a const away. const-ness can not be used as a optimization hint.