Russian Qt Forum
Ноябрь 23, 2024, 05:25 *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

Войти
 
  Начало   Форум  WIKI (Вики)FAQ Помощь Поиск Войти Регистрация  

Страниц: [1] 2   Вниз
  Печать  
Автор Тема: Выжать скорость  (Прочитано 12300 раз)
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« : Июль 14, 2020, 14:23 »

Добрый день

Профайлер показывает что притормаживают такие фрагменты кода (проблема типовая)
Код
C++ (Qt)
void SetUniformFloat( QOpenGLShaderProgram * shader, const char * name, float value )
{
int loc = shader->uniformLocation(name);
Q_ASSERT(loc >= 0);
shader->setUniformValue(loc, value);
}
 
За счет того что таких вызовов много. Имена могут быть также именами структур/массивов напр
Код
C++ (Qt)
SetUniformFloat(shader, "diffuse", 0.5f);  // переменная
SetUniformFloat(shader, "color[0]", 0.5f);  // массив
SetUniformFloat(shader, "light[1].amout", 0.5f);  // массив структур
 
Поэтому приходится еще какое-то время тратить на создание имен с индексом

Как ускорить? Очевидно нужно кешировать location и value. Но прямолинейный подход, напр
Код
C++ (Qt)
QHash<std::string, QPair<int, float>> mHash;
практически не ускоряет, теперь время тратится на создание и сравнение std::string

Ну и по ходу дела (optional): стали бы Вы тут обобщать? Какие-то основания для этого есть - придется написать
Код
C++ (Qt)
SetUniformInt
SetUniformFloat
SetUniformVector3D
SetUniformVector4D
SetUniformMatrix3x3
SetUniformMatrix4x4
Оба (Qt и я) считают что нет, связываться с template здесь не стоит. А Вы ?  Улыбающийся

Спасибо
« Последнее редактирование: Июль 14, 2020, 14:25 от Igors » Записан
Авварон
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 3260


Просмотр профиля
« Ответ #1 : Июль 14, 2020, 15:06 »

теперь время тратится на создание и сравнение std::string

Так не создавайте
Записан
__Heaven__
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2130



Просмотр профиля
« Ответ #2 : Июль 14, 2020, 18:38 »

есть у меня ощущение, что в QOpenGLShaderProgram, glGetUniformLocation используется примерно та же мапа для поиска location по имени. Ещё думаю, не стоит исключать то, что может быть происходит обращение с видеокартой, на что тоже тратится время

Если исходник шейдера не изменяется перед его компиляцией, то по идее можно было бы попробовать после линковки извлечь все location и запихать в отдельную структуру. В функции
изменить аргумент name на location.

Я пробовал объединять QOpenGLShaderProgram с её location в одном классе, у которого были методы setModelViewMatrix, setColor и т.д
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #3 : Июль 15, 2020, 10:12 »

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

Если исходник шейдера не изменяется перед его компиляцией, то по идее можно было бы попробовать после линковки извлечь все location и запихать в отдельную структуру. В функции изменить аргумент name на location.

Я пробовал объединять QOpenGLShaderProgram с её location в одном классе, у которого были методы setModelViewMatrix, setColor и т.д
Вы исходите из предположения что шейдер - нечто сопливое, десяток-другой строк Улыбающийся Есть конечно и такие, но есть и по 1-2К строк. А главное - самих шейдеров много, и сейчас их число бурно растет. Организовывать какие-то структуры/классы для каждого - не вариант. Впрочем и для единичного случая вряд ли катит. Напр шейдер получает переменное число структур lights - и отделаться членами класса для хранения location не удается.

Кстати именно сейчас занимаюсь шейдером для отрисовки "wireframe over" (вместо glPolygonOffset что мы обсуждали в прошлом)

Так не создавайте
Каким образом?  Улыбающийся

А что же с "обобшением"? Наверное оно уже не модно  Улыбающийся
Записан
Авварон
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 3260


Просмотр профиля
« Ответ #4 : Июль 15, 2020, 11:54 »

Каким образом?  Улыбающийся

А что же с "обобшением"? Наверное оно уже не модно  Улыбающийся

Вам уже мильен раз рассказывали про std::string_view
Если вы poor man (т.е. у вас pre c++17), то можно использовать QLatin1String, опционально может понадобиться написать хэш-функцию.
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #5 : Июль 15, 2020, 13:48 »

Вам уже мильен раз рассказывали про std::string_view
Если вы poor man (т.е. у вас pre c++17), то можно использовать QLatin1String, опционально может понадобиться написать хэш-функцию.
Как у Вас лихо получается: надо лишь знать нужный класс - и дело в шляпе, все уже и решено Улыбающийся

Я использовал незатейливое const char * в роли ключа, т.е.
Код
C++ (Qt)
QHash<const char *, QPair<int, QVariant>> mHash;
 
И ДА. это дало желанный прирост в скорости. Но цена/расплата ужасна, отстреливается уже не "нога", а самое дорогое.
Код
C++ (Qt)
static const std::string u_diffuse("diffuse");
...
auto & data = mHash[u_diffuse.c_str()];
Все хорошо, адрес сишной строки никуда не убежит. Однако
Код
C++ (Qt)
std::string str("diffuse");
...
...mHash[str.c_str()]...
Ошибка, если в хеше уже есть "diffuse", то найдена она не будет, т.к. поиск по адресу (а не содержимому). Использование "современных фишек", думаю, никак не изменит ситуевину, т.к. в любом случае предполагается неизменность/константность ссылки. Для имен что я заранее не могу объявить константами (массивы, структуры) пришлось делать мапу в которой значения - неперемещаемые строки.

Можно ли избежать этого гемора ?
Записан
Авварон
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 3260


Просмотр профиля
« Ответ #6 : Июль 15, 2020, 14:44 »

Можно ли избежать этого гемора ?

Можно, нужно всего

лишь знать нужный класс - и дело в шляпе, все уже и решено Улыбающийся
Записан
__Heaven__
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2130



Просмотр профиля
« Ответ #7 : Июль 15, 2020, 18:11 »

Код:
но есть и по 1-2К строк
Но не по 1К юниформов, подозреваю

Код:
отделаться членами класса для хранения location не удается
Не понимаю, почему в const char * name удаётся отделаться строками. Вектор не мог бы хранить несколько location для этих структур?

Как вариант завести структуру со всевозможными location и вместо const char * name использовать её поля. Уродливо, но зато быстро
Записан
__Heaven__
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2130



Просмотр профиля
« Ответ #8 : Июль 15, 2020, 18:13 »

glPolygonOffset, кстати у меня прям норм прижился. Немного повозился с подбором параметров на разных картах и больше не возвращался к нему.
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #9 : Июль 17, 2020, 05:01 »

Не понимаю, почему в const char * name удаётся отделаться строками. Вектор не мог бы хранить несколько location для этих структур?

Как вариант завести структуру со всевозможными location и вместо const char * name использовать её поля. Уродливо, но зато быстро
Ну хорошо, вот метод установки униформов
Код
C++ (Qt)
struct MyShader : public QOpenGLShaderProgrram  {
 
void SetUniform( const  char * name,   // uniform or struct field name
const  QVariant & value,      // value to set
const char * structName = 0, // struct or array name
int structIndex = -1 ); // array index  
 
};
 
Примеры использования
Код
C++ (Qt)
shader->SetUniform("diffuse", QVariant(0.5f));  // установка uniform с именем "diffuse"
shader->SetUniform("amout", QVariant(0.5f), "light", 1);  // установка "light[1].amout"
Предложите реализацию метода SetUniform или свой метод с тем же ф-ционалом. Спасибо
Записан
__Heaven__
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2130



Просмотр профиля
« Ответ #10 : Июль 17, 2020, 20:10 »

я бы отказался от SetUniform в пользу методов setDiffuse(float) и setAmountOfLight(size_t index, float), setAmountOfLight(float)

locations при линковке шейдера сохранить в структуру
Код:
Locations {
  int diffuse = -1;
  vector<int>light;
}
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #11 : Июль 18, 2020, 09:49 »

я бы отказался от SetUniform в пользу методов setDiffuse(float) и setAmountOfLight(size_t index, float), setAmountOfLight(float)

locations при линковке шейдера сохранить в структуру
Код:
Locations {
  int diffuse = -1;
  vector<int>light;
}
Повторюсь: униформов "достаточно много" чтобы для каждого заводить свою переменную и методы. И что vector<int>? В шейдере light объявлен как
Код:
struct Light {
    int type;
    vec4 viewPosition;
    vec3  amount;
    vec3  specular;
    float coneInner;
    float spotCosCutoff;
    vec3  spotDirection;
    float spotExponent;
    float dropoffDist;
    float dropoffOver;
};
Неясно как Вы собираетесь заряжать данные для массива light'ов.
Записан
__Heaven__
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2130



Просмотр профиля
« Ответ #12 : Июль 18, 2020, 13:26 »

Да, я понял, что много юниформов. Соответственно и locations будет много + возможно много избыточных

Цитировать
шейдере light объявлен как

Я бы в таком случае использовал

Код:
Locations {
    vector<LightLocations> light

Цитировать
Неясно как Вы собираетесь заряжать данные для массива light'ов
Не работал с массивами, кроме как QVector3D, QMatrix4x4 и подобными - не знаю как выглядит эта зарядка. Я так понял по аналогии с этой
Цитировать
SetUniformFloat(shader, "light[1].amout", 0.5f);

Вместо "light[1].amout" брать locations.light[1].amount
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #13 : Июль 19, 2020, 07:46 »

Вместо "light[1].amout" брать locations.light[1].amount
Если я правильно понял Вы предлагаете как бы создать "образ" (или image) шейдера в C++ коде, т.е. те же переменные, структуры и массивы хранят location. Точнее пару (location + QVariant) т.к. location вычисляется при загрузке а значение меняется часто.

На мой взгляд как-то безыдейно. Заводить 100-150 переменных не имеющих никакой смысловой нагрузки не есть хорошо, таким место в контейнере. Да и заботы с тучей переменных найдутся (нужно как-то привязать строковые имена, синхронизировать размеры массивов и.т.п).

Собсно теперешний вариант меня вполне устраивает
Код
C++ (Qt)
void SetUniform( const  char * name,   // uniform or struct field name
const  QVariant & value,            // value to set
const  char * structName = 0, // struct or array name
int structIndex = -1 );       // array index  
 
Накидал строковых констант и заряжай себе. Неприятность только одна: провоцируется "отстрел ноги", для name(s) нельзя использовать даже строковый литерал. Как порешать эту злополучную "семантику" ?
Записан
Авварон
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 3260


Просмотр профиля
« Ответ #14 : Июль 19, 2020, 13:17 »

Неприятность только одна: провоцируется "отстрел ноги", для name(s) нельзя использовать даже строковый литерал. Как порешать эту злополучную "семантику" ?

Достаточно просто взять "нужный класс". Блин, я не понимаю, почему у стольких людей такая проблема с пониманием view? QString/std::string - есть операторы сравнения, хэширования, но тяжелое создание/копирование. char* - нет операторов сравнение, хеширования (то есть есть, но не те). Какое решение? Сделать тип, который ведет себя как char* (то есть не овнит, дешево создается/копируется) и который содержит _нужное_ поведение - сравнивает строки как строки, а не как указатели. Ба, мы только что изобрели std::string_view (и его аналоги QLatin1String, QStringView, gsl::span<char>, std::span<char>). Не нравится "готовый" класс - напишите свой, полезно для ума, может хоть тогда дойдет зачем это надо.
Записан
Страниц: [1] 2   Вверх
  Печать  
 
Перейти в:  


Страница сгенерирована за 0.269 секунд. Запросов: 23.