Russian Qt Forum

Qt => Установка, сборка, отладка, тестирование => Тема начата: ieroglif от Декабрь 14, 2009, 09:15



Название: заточка кода под быстродействие.
Отправлено: ieroglif от Декабрь 14, 2009, 09:15
посоветуйте, чего почитать для создания максимально быстро действующего кода на Qt?
посмотрите класс - может чего подскажите для убыстрения?

класс создан для обсчитывания объектов на 3d сцене, сортировки этих объектов по глубине и вызова их метода рисования (в порядке сортировки)

qglrenderer.h
Код:
#ifndef QGLRENDERER_H
#define QGLRENDERER_H

#include <QObject>
#include <QMap>
#include "glheaders.h"
#include "qglcamera.h"

class QGLObject;

class QGLRenderer : public QObject
{
Q_OBJECT
public:
    QGLRenderer();
void RegisterObject(QGLObject *obj);
void UnregisterObject(QGLObject *obj);
void Render();
bool HasObjects();

static QGLCamera *camera;
public slots:
void ToRender(QGLObject *obj);
private:
QMap<QGLObject*,bool> objects;
};

#endif // QGLRENDERER_H

qglrenderer.cpp
Код:
#include "qglrenderer.h"
#include "qglobject.h"
#include <QList>

QGLCamera* QGLRenderer::camera;

QGLRenderer::QGLRenderer()
{
objects.clear();
}

void QGLRenderer::RegisterObject(QGLObject *obj)
{
if ( objects.contains(obj) ) return;
objects.insert(obj,false);
connect(obj,SIGNAL(ToRender(QGLObject*)),this,SLOT(ToRender(QGLObject*)));
}

void QGLRenderer::UnregisterObject(QGLObject *obj)
{
if ( objects.contains(obj) ) {
objects.remove(obj);
disconnect(obj,SIGNAL(ToRender(QGLObject*)),this,SLOT(ToRender(QGLObject*)));
}
}

void QGLRenderer::ToRender(QGLObject *obj)
{
RegisterObject(obj);
objects[obj] = true;
}

void QGLRenderer::Render()
{
QGLObject *obj;
QMap<GLfloat,QGLObject* > map;
QList<QGLObject* > r_map;
QMap<QGLObject*,bool>::const_iterator i = objects.constBegin();
while ( i != objects.constEnd() ) {
if ( i.value() == true ) {
obj = i.key();
map.insertMulti(obj->DistanceTo(),obj);
}
i++;
}
QMap<GLfloat,QGLObject* >::const_iterator j = map.constBegin();
while ( j != map.constEnd() ) {
obj = j.value();
r_map.append(obj);
j++;
objects[obj] = false;
}
for ( int k=r_map.size()-1;k>=0;k-- ) {
r_map.at(k)->Render();
}
}

bool QGLRenderer::HasObjects()
{
if ( objects.isEmpty() ) return false;
return true;
}

на сколько "выгодно/невыгодно" использование контейнеров типа QList или QMap ?
на данный момент этот код обсчитывает около 600 объектов (сравнивает их растояние до камеры, и потом вызывает им функцию рисования) на сцене, выдавая 20-25 фпс, с туманом и 3-4 источниками света при следующем железе-софте:
Asus z99h видюха intel 945, оперативы 1.5 гига, ос Kubuntu 9.04 полуубитый всякими экспериментами, Qt 4.5.2
и я уже упарился от такого мракобесия.
хочется сделать красивую сцену, но стоит докинуть текстурку - получаю минус в скорости. докидываю источник света - та же хрень и так далее... в общем, не предлагайте оптимизировать ноутбук (лучше дайте бабло на это.. а предложить я и сам себе могу), а посоветуйте, в чём может быть загвозка кода? где искать возможности ускорения?


Название: Re: заточка кода под быстродействие.
Отправлено: BRE от Декабрь 14, 2009, 09:52
Что значит 600 объектов?
А сколько это в полигонах?
1 объект из 10000 полигонов != 10 объектам из 100 полигонов каждый.


Название: Re: заточка кода под быстродействие.
Отправлено: ieroglif от Декабрь 14, 2009, 10:17
600 объектов - это 600 объектов.
у меня не учитываются точки пересечения и прочее - всё просто.
надо просто отсортировать объекты по дальности от камеры что бы вывести их по удалению от камеры.
так что количество полигонов не влияет на сортировку по глубине.
полигонов суммарно несколько тысяч (и конечно окажется очень обломным, если даже несколько тысяч полигонов мои руки отображают криво и медленно).
Я понимаю что их число тоже влияет на скорость, но вывод объекта уже постарался оптимизировать по максимуму - в максе сделано минимальное количество полигонов, полигоны отрисовываются разовым массивом
Код:
void QGLMesh::Draw()
{
glNormalPointer(GL_FLOAT,0,normales);
glVertexPointer(3,GL_FLOAT,0,vertexes);
glDrawArrays(GL_TRIANGLES,0,numVertex);
}
В общем, в этом вопросе есть много доков в сети и есть откуда набираться знаний по оптимизации. Я ничуть не отказываюсь от советов по любым вопросам, просто сейчас хотелось бы углубиться в вопросы касательные именно Qt.
А тут - вопросы
1. ООП проектирования. неверная архитектура - это уже однозначный минус. К сожалению не получилось пока найти чего-то в сети по этому вопросу, поэтому буду рад, если есть чего.
2. C++ программирования под Qt - вот это, как мне кажется, в этом форуме и обсуждается в первую очередь. Соотсвественно - как писать под Qt на С++ максимально быстрый код? где кроются подводные камни, как делать правильно? как не надо делать? для примера как выложил кусок кода, в котором подозреваю один из подводных камней.


Название: Re: заточка кода под быстродействие.
Отправлено: BRE от Декабрь 14, 2009, 10:26
Метод render:
Для чего несколько раз перекладывать из одного контейнера в другой?
Из map в r_map, а только потом рисуем объекты из r_map?
Код
C++ (Qt)
       QMap<GLfloat,QGLObject* >::const_iterator j = map.constBegin();
       while ( j != map.constEnd() ) {
               obj = j.value();
               r_map.append(obj);
               j++;
               objects[obj] = false;
       }
       for ( int k=r_map.size()-1;k>=0;k-- ) {
               r_map.at(k)->Render();
       }
 


Название: Re: заточка кода под быстродействие.
Отправлено: niXman от Декабрь 14, 2009, 10:34
В общем, код вообще не оптимизирован :(
1. Как вам наверное известно, вставка элементов в нераспределенный контейнер, требует выделения памяти и/или связывания указателей предыдущий/следующий(это в том случае, если контейнером является двусвязный список), если же контейнером является вектор, это еще хуже.
Но QMap<> реализован на основе списка.

2. "r_map.at(k)->Render()" - очень медленный код.


Название: Re: заточка кода под быстродействие.
Отправлено: niXman от Декабрь 14, 2009, 10:39
Я про доступ по индексу.
map<>, быстрей индексируется по ключу.


Название: Re: заточка кода под быстродействие.
Отправлено: ieroglif от Декабрь 14, 2009, 10:59
BRE , честно сказать, сейчас смотрю на этот кусок и сам не понимаю почему именно так =( попробывал переписать, поиграться - перестало корректно сортировать и работать.
Помню что QMap был выбран специально как самосортирующийся.
niXman , понимаю что код не отимизированный - программист я не особый, только учусь. Можно ссылки на доки-маны ума поднабраться, или пример как оно должно быть?


Название: Re: заточка кода под быстродействие.
Отправлено: niXman от Декабрь 14, 2009, 11:06
http://www.ozon.ru/context/detail/id/1273200/
http://www.ozon.ru/context/detail/id/2342923/
http://www.ozon.ru/context/detail/id/2381848/
http://www.ozon.ru/context/detail/id/3817580/

желательно все :)


Название: Re: заточка кода под быстродействие.
Отправлено: lit-uriy от Декабрь 14, 2009, 11:16
ieroglif по поводу контейнеров Qt и их шустрости смотри Базовые контейнеры (http://www.doc.crossplatform.ru/qt/4.4.3/containers.html) (на русском)

И в частности раздел "Алгоритмическая сложность"


Название: Re: заточка кода под быстродействие.
Отправлено: ieroglif от Декабрь 14, 2009, 12:06
niXman, lit-uriy спасибо большое - пошёл читать.

Оффтопиком спрошу ещё - может посоветуете ещё чего почитать по общей архитектуре? Делаю игру, описал геймплей - всё нормально. Дошёл до сетевой игры, и понял что текущая архитектура классов не увязывается с сетевой игрой и наступил ступор - как вообще делаются сетевые движки?


Название: Re: заточка кода под быстродействие.
Отправлено: panAlexey от Декабрь 14, 2009, 12:39
http://www.ozon.ru/context/detail/id/1273200/
http://www.ozon.ru/context/detail/id/2342923/
http://www.ozon.ru/context/detail/id/2381848/
http://www.ozon.ru/context/detail/id/3817580/
желательно все :)
"Решение сложных задач на C++" - 2 раза указал. Убери, а то впадет в рекурсию :)


Название: Re: заточка кода под быстродействие.
Отправлено: niXman от Декабрь 14, 2009, 12:47
Книги то разные ;)


Название: Re: заточка кода под быстродействие.
Отправлено: panAlexey от Декабрь 14, 2009, 13:08
Книги то разные ;)
Не уверен. Проверь первую и последнюю ссылку.
По крайне мене название одинаковое.
Или так показалось..


Название: Re: заточка кода под быстродействие.
Отправлено: Dendy от Декабрь 14, 2009, 14:39
... как вообще делаются сетевые движки?

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


Название: Re: заточка кода под быстродействие.
Отправлено: Igors от Декабрь 14, 2009, 14:58
1) На 600 единицах (объектах) проходит все что угодно и много на контейнерах не сэкономить. Все же я бы делал попроще

Цитировать
struct CDistObj {
 OGLObject * mObj;
 float  mDist;

 bool operator < ( const CDistObj & sec ) const { return mDist < sec.mDist; }
};

QSet <CDistObj> theDistObj;
// очевидные операции вставки и.т.п

2) Рендер "по расстоянию от камеры" дает ограниченные возможности, но если уж Вы так решили - то почему Вы каждый раз выводите ВСЕ объекты "задом наперед"? Делаете по расстоянию - так крутите оптимизацию с буфером (и при удалении тоже)

3)
Цитировать
хочется сделать красивую сцену, но стоит докинуть текстурку - получаю минус в скорости. докидываю источник света - та же хрень и так далее...
Хммм... а на что Вы рассчитывали? Если при добавлении текстуры/света скорость падает - то при чем здесь контейнеры?  :) Откуда убежденность что все должно быть real-time на любом железе?  Для начала отключите туманы и прочие красоты.


Название: Re: заточка кода под быстродействие.
Отправлено: ieroglif от Декабрь 14, 2009, 17:42
1) На 600 единицах (объектах) проходит все что угодно и много на контейнерах не сэкономить. Все же я бы делал попроще

Цитировать
struct CDistObj {
 OGLObject * mObj;
 float  mDist;

 bool operator < ( const CDistObj & sec ) const { return mDist < sec.mDist; }
};

QSet <CDistObj> theDistObj;
// очевидные операции вставки и.т.п
спасибо, понял пока не очень, но думать буду.

2) Рендер "по расстоянию от камеры" дает ограниченные возможности, но если уж Вы так решили - то почему Вы каждый раз выводите ВСЕ объекты "задом наперед"? Делаете по расстоянию - так крутите оптимизацию с буфером (и при удалении тоже)
т.е. задом наперёд? и можно чуть по-подробнее - какую именно оптимизацию и с каким буффером курить? просто поподробнее, что бы точно стало ясно куда копать?

3)
Цитировать
хочется сделать красивую сцену, но стоит докинуть текстурку - получаю минус в скорости. докидываю источник света - та же хрень и так далее...
Хммм... а на что Вы рассчитывали? Если при добавлении текстуры/света скорость падает - то при чем здесь контейнеры?  :) Откуда убежденность что все должно быть real-time на любом железе?  Для начала отключите туманы и прочие красоты.
да блин.. я понимаю что железо у меня не привлекает к программированию 3д вообще, не говоря уж о программировании красивого 3д.. тот же код на других машинах (с нормальным железом) уже даёт 90-120 фпс вместо 24 моих, но всё же ощущать себя таким убогим совсем не хочется - тогда полностью пропадает интерес к программингу - вот и спрашиваю - где же ещё можно выдрать фпсы? на чём ещё можно выдрать чуть-чуть и сделать по симпатичнее?


Название: Re: заточка кода под быстродействие.
Отправлено: Igors от Декабрь 14, 2009, 18:10
спасибо, понял пока не очень, но думать буду.
Вам нужно держать массив сортированным и вставлять в него, правильно? Ну так QSet для этого и предназначен. Это имеет смысл если анимация сводится к добавлению/удалению. А если нет - то все еще проще QVector<QDistObj> и qSort

т.е. задом наперёд? и можно чуть по-подробнее - какую именно оптимизацию и с каким буффером курить? просто поподробнее, что бы точно стало ясно куда копать?
Полагаем что "очередность" меняется часто, от кадра к кадру (иначе нет смысла возиться). Были объекты [0..10], новый объект вставляем на место 5 (например). Значит можно перерисовать от 5-го нового до начала, хвост не трогать. При удалении - наоборот. Как содрать буфера в OGL - (depth и.т.п) - разберетесь.

да блин.. я понимаю что железо у меня не привлекает к программированию 3д вообще, не говоря уж о программировании красивого 3д.. тот же код на других машинах (с нормальным железом) уже даёт 90-120 фпс вместо 24 моих, но всё же ощущать себя таким убогим совсем не хочется - тогда полностью пропадает интерес к программингу - вот и спрашиваю - где же ещё можно выдрать фпсы? на чём ещё можно выдрать чуть-чуть и сделать по симпатичнее?
Почему Вы думаете что 3D = fps и OGL?  :) У меня кадр может считаться минуты а иногда и часы (на приличном железе) - и я совсем не страдаю от отсутствия фпс'ов, не в них счастье. Все зависит от того что и как рендерится и с каким качеством. Не говоря уже о том что рендер - это довольно малая часть от всего 3D вообще. Смотрите на вещи "ширше" :)


Название: Re: заточка кода под быстродействие.
Отправлено: ilot от Декабрь 22, 2009, 06:15
На мой взгляд контейнер QMap здесь не подходит (не для таких задач он нужен). Тем более, что не стоит использовать указатели в качестве ключей. Предлагаю следующий вариант:

В классе QGLRenderer заменить QMap на:
Код:
typedef QPair<QGLObject*, bool> RegistRecord;
QVector<RegistRecord> objects;
тогда метод render() можно записать так:
Код:
for(int i = objects.size() - 1; i >= 0; i--)
{
objects[i].first->Render();
objects[i].second = false;
}

Это не нужно (контейнер итак пустым создается):
Код:
QGLRenderer::QGLRenderer()
{
objects.clear();
}

niXman: при вставки элементов в вектор перераспределение памяти выполняется не каждый раз, а только тогда, когда исчерпывается выделенная емкость. При желании можно заранее зарезервировать нужное место (см. методы capacity(), reserve()) поскольку автор примерно знает, сколько у него будет объектов. Но в данном случае это вовсе не узкое место - в приведенных примерах контейнеры содержат не сами объекты, а указатели на них. А это значит, что объем данных, которыми оперируют контейнеры нижточно мал! Поэтому метод render() даже в варианте автора должен работать очень быстро (из контейнера в контейнер перекидываются только указатели).

Другое дело, что "скрывается" за указателями QGLObject* ? К сожалению из приведенного кода не ясно как создаются объекты типа QGLObject, как потом в дальнейшем используются (реализация метода QGLObject::Render() тоже осталась за кадром). Вообщем, пока складывается такое мнение, что вся проблема в используемых методах отрисовки. Возможно они просто неправильно/неоптимально используются.


Название: Re: заточка кода под быстродействие.
Отправлено: ieroglif от Январь 10, 2010, 16:44
после долгого перерыва возвращаюсь к проекту. установил под венду последний Qt, собрал в нём свой проект - тот же самый код работает в два раза быстрее чем в линухе, выдавая под 60 фпс. начинаю задумываться, что узкое место не только в моём коде..

ilot, QGLObject-ы создаются заранее, модельки загружаются тоже заранее, в общем, там всё подготовлено к отрисовке и относительно оптимизированно и хоть возможности оптимизации даже мне видны, но не думаю что это даст сильный прирост... циклов там нет.. просто загружаются массивы координат и текстур в    glNormalPointer, glVertexPointer и вызывается glDrawArrays. массивы тоже подготавливаются при запуске программы.

в общем, на данный момент (после первого запуска в венде и офигения от результата) считаю это проблемой своей карточки (intel 945 чипсет) и начинаю думать над сетевой частью проекта.