glDeleteTextures, подтекает? - PullRequest
       12

glDeleteTextures, подтекает?

0 голосов
/ 20 февраля 2010

Я обнаружил довольно отвратительное поведение glDeleteTexture, удаляющее только части памяти (со стороны графического процессора и по мере восстановления текстур ради скорости в ОЗУ), что в моем случае является ошибкой showtopper, моя программа ест все память.

Я не хочу / не требую, чтобы вы читали весь код, это просто демонстрация, я бы лучше знал, как на самом деле использовать glDeleteTextures, чтобы он не утечка любая память.

В примере кода для компиляции требуется Qt 4.5 или новее:

glleak.pro

QT += opengl

SOURCES += main.cpp \
    glleak.cpp
HEADERS += glleak.h

main.cpp

#include <QtOpenGL>
#include <QtGui>
#include "glleak.h"

int main(int argc, char** argv){
    QApplication app(argc, argv);
    glleak gll(0);
    gll.show();
    return app.exec();
}

glleak.h

#ifndef GLLEAK_H
#define GLLEAK_H

#include <QGLWidget>
#include <QMouseEvent>
#include <QDebug>
#include <QList>

class glleak : public QGLWidget
{
    Q_OBJECT
public:
    glleak(QWidget* parent = 0);
    virtual ~glleak();
protected:
    void initializeGL();
    void paintGL();
    void resizeGL(int w, int h);
    void drawScene(GLenum mode);

    void wheelEvent(QWheelEvent* event);

    void hardcoreTexturing();
private:
    QList<GLuint> texels;

};

#endif // GLLEAK_H

glleak.cpp

glleak::glleak(QWidget* parent) :
        QGLWidget(parent)
{
}

glleak::~glleak()
{
}


void glleak::initializeGL(){
    glClearColor(0.0f,0.0f,0.0f,0.0f);
    glEnable(GL_TEXTURE_2D);
    glEnable(GL_MULTISAMPLE);
    glLineWidth (1.5f);
    glPointSize(4.5f);
    glEnable (GL_BLEND);
    glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
}

void glleak::resizeGL(int w, int h){
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    glOrtho(-w/2.0, w/2.0, h/2.0, -h/2.0, -1.0, 1.0);
    glMatrixMode(GL_MODELVIEW);
    glViewport(0, 0, w, h);
    glLoadIdentity();
}

void glleak::paintGL(){
    glPushMatrix();
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    glLoadIdentity();
    glColor3f(1.0f,1.0f,1.0f);
    drawScene(GL_RENDER);
    glPopMatrix();
}




void glleak::drawScene(GLenum mode){
    qDebug() << "drawed #" << texels.count() << " Textures";
    hardcoreTexturing();
}


void glleak::hardcoreTexturing(){
    glEnable(GL_TEXTURE_2D);
    for ( int i(0); i<texels.count(); ++i){
        glPushMatrix();
        glTranslatef(1.1f*i, 2.2f*i, 0.0f);
        glBindTexture(GL_TEXTURE_2D, texels.at(i));
        glBegin(GL_QUADS);
        {
            glTexCoord2i(0,0);
            glVertex2i(-128,-128);

            glTexCoord2i(0,1);
            glVertex2i(-128,128);

            glTexCoord2i(1,1);
            glVertex2i(128,128);

            glTexCoord2i(1,0);
            glVertex2i(128,-128);

        }
        glEnd();
        glPopMatrix();
    }
    glDisable(GL_TEXTURE_2D);
}


void glleak::wheelEvent(QWheelEvent* event){
    glEnable(GL_TEXTURE_2D);
    int n(50);
    if (event->delta()>0){
        qDebug() << "gen textures";
        for (int i(0); i<n; ++i){
            QImage t("./ballmer_peak.png","png");
            GLuint tex(0);
            glGenTextures(1, &tex);
            glBindTexture(GL_TEXTURE_2D, tex);
            glTexImage2D( GL_TEXTURE_2D, 0, 3, t.width(), t.height(), 0, GL_RGBA, GL_UNSIGNED_BYTE, t.bits() );
            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
            glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
            texels.append(tex);
        }
    }
    else{
        qDebug() << "del textures";
        for (QList<GLuint>::iterator i(texels.begin()); i!=texels.end();){
            glDeleteTextures(1, &(*i));
            i = texels.erase(i);
            if (--n <= 0)
                break;


        }
    }
    glDisable(GL_TEXTURE_2D);
        updateGL();
}

ballmer_peak.png Изображение для загрузки и рендеринга

Примечание: скомпилируйте демонстрацию: просто поместите все это в папку, переименуйте ваше изображение в ballmer_peak.png , вызовите qmake, make, ./glleak Примечание: Использование демонстрации: Использование колесика мыши для создания или удаления 50 текстур одновременно

Если я использую glDeleteTextures совершенно неправильно, скажите, пожалуйста, как его использовать. У меня нет идей, так как мое использование соответствует официальному использованию OpenGL glDeleteTextures .

Ответы [ 7 ]

1 голос
/ 25 мая 2011

Я не запускал ваш пример кода, но я получаю аналогичную вещь на Windows7-64bits. Использование для каждой текстуры glGenTextures () и glDeleteTextures () может привести к утечке памяти, но я вижу увеличение количества дескрипторов моего потока (например, в TaskManager, но я также могу проверить это из источника). Похоже, glDeleteTextures () не освобождает дескриптор. Возможно, он сделает это позже, но 24-часовые тесты показывают, что он никогда не освобождает ручку. Похоже, утечка внутри драйвера (nVidia GTX285, драйвер 270.61). В конце концов, программе действительно не хватает памяти. Я начинаю думать, что это проблема с драйверами ...

1 голос
/ 14 апреля 2011

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

1) Не следует помещать это в цикл for, который инициализирует текстуры. Вам нужно поместить его перед циклом и назвать его ОДИН РАЗ, с количеством текстур, необходимых в качестве первого параметра. Скажи == 50:

glGenTextures (50, & tex);

2) tex должен быть статическим массивом из n GLuints и должен сохраняться (не как автоматическая переменная, как у вас!) До тех пор, пока не будет вызван glDeleteTextures, снова, ONCE - не в цикле:

glDeleteTextures (50, & tex);

Думайте о tex как о хранилище для хранения идентификаторов текстур. Важно использовать его, а не указывать отдельный QList, как вы это делали, для связывания текстур, поскольку (как указано в ссылке OpenGL) нет никакой гарантии, что идентификаторы текстуры будут представлять собой непрерывный набор целых чисел. Я должен представить, что ваша утечка произошла, потому что внутри OpenGL теряет исходный указатель на локальную (автоматическую) переменную, которую вы использовали для генерации каждой текстуры, поэтому память текстур теряется.

Надеюсь, это поможет!

0 голосов
/ 10 января 2012

Ваш тест в моей системе хорошо кушает память и не освобождает ее сразу, когда я удаляю все текстуры, но если я подожду некоторое время, память возвращается в систему. Похоже, что драйвер OGL использует какой-то ленивый алгоритм освобождения памяти.

0 голосов
/ 03 января 2012
for (QList<GLuint>::iterator i(texels.begin()); i!=texels.end();)

переключиться на

for (QList<GLuint>::iterator i(texels.end()); i!=texels.begin();)
0 голосов
/ 26 марта 2011

Возможно, я ошибаюсь, но когда я скомпилировал и запустил ваш код, у меня не возникло никаких проблем? Увеличение до 650 текстур (не может быть увеличено далее: получите сообщение «убито») и мое использование памяти увеличилось с 1% до 24% и обратно до 1%. Повышение до 200 и повторное снижение также не вызывает проблем: использование оперативной памяти по-прежнему составляет 1% в конце. Насколько я понимаю, это вызвало бы огромные утечки в вашей системе? Ubuntu 10.10 здесь (Qt 4.7.0).

0 голосов
/ 20 февраля 2010

Вам может потребоваться вызвать makeCurrent () в верхней части wheelEvent.

Для paintEvent, resizeEvent и т. Д. Qt предоставляет реализацию, которая обрабатывает это перед вызовом paintGL / resizeGL / etc, но для других событий, таких как wheelEvent, вы должны сделать это сами.

0 голосов
/ 20 февраля 2010

Нет ничего, что выглядит неправильно в вашем коде. Итак ... Что заставляет вас думать, что у вас утечка памяти? Что заставляет вас думать, что это текстуры именно этой утечки?

Возможно, но крайне маловероятно, что реализация OpenGL, которую вы используете, протекает. Это будет зависеть от реализации.

Какой бы механизм вы не использовали для проверки утечек памяти, что произойдет, когда вы освободите контекст OpenGL?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...