Вопрос

Я пишу обработчик для текстур OpenGL и думаю о безопасности и производительности.На каком уровне оптимизации следует удалить отмеченные операторы if?


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(...);
}
Это было полезно?

Решение

Никто.

Печальная история, но C++ предполагает, что если вы вызываете функцию, то эта функция может вызвать всевозможные побочные эффекты, включая изменение значения Bind.ID (о чем функция каким-то образом знает).

Кроме

Если вы убедитесь, что вызываемые вами функции не имеют абсолютно никакого законного способа узнать о вашем bindend.ID, либо напрямую (ссылаясь на него), либо косвенно (потому что кто-то другой взял указатель на него и передал его).Вот простой пример (предполагая, что side_effect() находится в другой единице перевода)

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() можно использовать и менять k юридически, объявив его внешним.Нет звонка side_effect можно оптимизировать.

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;
}

Это невозможно для side_effect чтобы получить доступ k разрешенным способом, поскольку вы не можете получить доступ к статике в другой единице перевода.Поэтому код можно оптимизировать для side_effect(); return 0 потому что k не изменится, пока Side_effect() не ковыряется в памяти.Конечно, это было бы неопределенное поведение.

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;
}

Компилятор не имеет возможности узнать, если snitch() сохраняет свой аргумент в месте, где side_effect() может изменить его, поэтому нет вызова side_effect() можно устранить.

Вы получите ту же ситуацию, если у вас есть k как локальная переменная:Если существует вероятность того, что какая-то неизвестная процедура сможет получить доступ k законным способом, то компилятор не сможет проводить оптимизацию на основе значения k.

ПС: Изготовление k const не помогает, потому что отбросить константу можно.const-ness не может использоваться в качестве подсказки по оптимизации.

Другие советы

Это будет зависеть от компилятора, и ваша лучшая ставка - проверять - компилировать и проверять излучаемый машинный код.

Ни один уровень оптимизации не может (правильно) Удалить эти тесты. Они могут быть удалены только в том случае, если оба аргумента были константами времени компиляции, и ни один из них не являются, либо если компилятор может доказать, что они не будут изменять значение между тестами.

С binded Статичен, компилятор не может знать, что вызовы функций GL не изменит его.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top