Russian Qt Forum

Qt => Общие вопросы => Тема начата: Igors от Апрель 14, 2016, 07:51



Название: Интерактивное (почти) управление
Отправлено: Igors от Апрель 14, 2016, 07:51
Добрый день

Есть 3 параметра (QLineEdit'ы со спиннерами): скорость (или газ), поворот и сдвиг. Есть фиксированное число кадров, на каждом параметры могут иметь разные значения. Параметры рулят объектами, напр больше скорость - объект движется быстрее. По существу все как в игре, поэтому логично запустить анимацию (т.е. показывать кадр за кадром) и сделать упр-е клавишами (напр стрелками).

Но есть одно обстоятельство: в отличие от игры время смены кадра может быть любым в зависимости от сложности сцены. Где-то и вытянет 30fps, а где-то только 5 а то и меньше. Это нормально, там тонны расчетов (а не только рисование).

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

Спасибо


Название: Re: Интерактивное (почти) управление
Отправлено: Racheengel от Апрель 15, 2016, 17:45
В играх в основном берется фиксированный fps и уже исходя из реального времени расчета кадров некоторые кадры могут скипаться.
Да, картика станет дерганой, но общий fps не пострадает.


Название: Re: Интерактивное (почти) управление
Отправлено: Igors от Апрель 16, 2016, 09:25
В играх в основном берется фиксированный fps и уже исходя из реального времени расчета кадров некоторые кадры могут скипаться.
Да, картика станет дерганой, но общий fps не пострадает.
Обычно (и не только в играх) это называется "drop frames". Здесь никаких пропусков нет, проблема такая

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

А хотелось бы так: QLineEdit обновляется при нажатии на клавишу и/или спыннер, юзер видит что установил. Он понимает что новое значение скорости будет задействовано на след кадрах, это нормально.


Название: Re: Интерактивное (почти) управление
Отправлено: Racheengel от Апрель 17, 2016, 02:49
Хм... а почему обработка событий зависит от вычисления геометрии?
Есть поток, который занят гуем и событиями, но геометрия то в другом (надеюсь) считается?
Откуда указанный эффект возникает?


Название: Re: Интерактивное (почти) управление
Отправлено: Igors от Апрель 17, 2016, 09:08
Хм... а почему обработка событий зависит от вычисления геометрии?
Есть поток, который занят гуем и событиями, но геометрия то в другом (надеюсь) считается?
Не надейтесь, сейчас все в главной нитке. Кода настолько много что хз кто может тормозить - могут все. Напр рисование многочисленных окон (в том числе и с OpenGL) запросто может оказаться узким местом, но это должно быть в главной нитке. По поводу др операций..

Пример: рисование требует текстур (картинок), причем их набор может быть всяким-разным в зависимости от многих установок. Др словами нужно подгружать/выгружать картинки с диска. Сейчас это делается перед началом каждого рисования. Да, формально эта трудоемкая операция загрузки UI-независима и "может быть вынесена в др поток". Ну а зачем? Ведь "иметь свободное UI" я все равно не могу. Как только выйду в событийный цикл - нарвусь на событие требующее др рисования, и что тогда делать с текущим?

Стандартная реакция типа
Цитировать
Фу, как неграмотно грузить картинки в paintEvent! Кривой дизайн! Нужно все картинки заранее загрузить и.т.п.
Ну конечно не в paintEvent, c OpenGL можно рисовать когда угодно. А главное - расклад картинок  может измениться в 100 местах, отследить все - проще застрелиться. Поэтому логично грузить их когда они действительно нужны, на фазе подготовки рисования.
 
Вообще рекомендация "вынести в др поток" слишком популярна и дается к месту и не к месту  :)


Название: Re: Интерактивное (почти) управление
Отправлено: Racheengel от Апрель 17, 2016, 12:20
Ну, в данном случае классическая рекомендация, как я вижу, будет к месту.  Выносить и еще раз выносить.
У нас тоже был 3д плоттер, который рендерился в основном потоке. Тормозил безбожно.
Пришлось порезать на потоки, после чего проблема тормозов ушла раз и навсегда.


Название: Re: Интерактивное (почти) управление
Отправлено: Igors от Апрель 17, 2016, 12:31
Ну, в данном случае классическая рекомендация, как я вижу, будет к месту.  Выносить и еще раз выносить.
Ну почему Вы всегда говорите банальность - и только банальность? :) В предыдущем посте я описал проблемы "выноса", прочитайте, потом (может) "я вижу".


Название: Re: Интерактивное (почти) управление
Отправлено: Racheengel от Апрель 18, 2016, 10:45
Если "тормозит хз что, я не знаю что, но тормозит же", то профайлер в помощь.
Определите, что тормозит, и дальше по ситуации.
Или там настолько все плохо, что уже не поддается распознаванию?
Картинки, как минимум, тоже можно раскидать по потокам, или частично закэшировать.
Банально? Да. Но ведь и задача пока тоже выглядит банальной.
Есть еще что то, о чем мы " пока не знаем"?


Название: Re: Интерактивное (почти) управление
Отправлено: lit-uriy от Апрель 18, 2016, 14:26
"Наконец "просралось", дело дошло до событий, и выяснилось что надавил значение куда больше чем думал."
Ну собственно тут и ответ.
до тех пор пока не просралось, виджеты управления блокируем и показываем некий индикатор занятости.


Название: Re: Интерактивное (почти) управление
Отправлено: Igors от Апрель 18, 2016, 15:36
Или там настолько все плохо, что уже не поддается распознаванию?
Почему "плохо"? Как только объем приложения превышает некоторый предел - никто (включая автора) уже не представляет все подробности. Я всего лишь один из авторов, навскидку вспомню пяток-десяток операций - уже хорошо. Это нормально, человеческие возможности ограничены.

Определите, что тормозит, и дальше по ситуации.
А Вы уверены что это правильный подход? Для той или иной сцены(данных) узкие места могут быть совершенно разными. Ну хорошо, допустим нашли какое-то, но "вынос в поток" не имеет смысла. Почему - давайте еще разжую

"Вынос тела" имеет смысл если UI переживет его временное отсутствие. Напр галерея иконок может грузиться довольно долго, тогда написать пока "Loading", и диалог все же открыть. Но такая возможность есть далеко не всегда, напр объекты в окнах должны рисоваться с текстурами, на них надписи не сделать. И. как уже говорилось, UI не должно конфликтовать с фоновой загрузкой.

Ну и что неясно, и зачем упорно лепить одну-единственную рекомендацию из букваря? :)

Ну собственно тут и ответ.
до тех пор пока не просралось, виджеты управления блокируем и показываем некий индикатор занятости.
Так этот индикатор и будет все время "занят" т.к. время схватывания событий ничтожно по сравнению с выполнением рабочих операций



Название: Re: Интерактивное (почти) управление
Отправлено: Igors от Апрель 18, 2016, 17:10
Запустить нитку - наблюдателя которая по таймеру подсматривает события клавы. Когда нужное событие обнаружено - отрисовать QLineEdit (с измененным значением) в QPixMap и шлепнуть его на экран. С добрым старым КвыкДроу это было совершенно реально, можно даже было лочить пыксели на время копирования. Сейчас нет конечно, да и с "подсматриванием" в Qt большие проблемы  :'(

Не, конечно легко повторять "UI только в главной нитке" - ну а если вот НАДО? И вообще - что собсно имеется ввиду? Qt вызовы "not thread-safe" или ОС? Если только первое - обойти можно.


Название: Re: Интерактивное (почти) управление
Отправлено: Bepec от Апрель 18, 2016, 19:43
По сути опять у Igors коллапс идей в мини черную дырку.
1) изменение spinbox/lineEdit с отложенным выполнением. (подробнее в п.3)
2) ускорение расчётов/отрисовки - не имеет решения, ибо "ну и пусть тормозит внутри, я хочу ускорить ничего не меняя" © Igors.
3) разделение органов управления и расчёта. Решается добавлением промежуточной переменной - той, которая рассчитывается "сейчас". Как только расчёт завершён для "сейчас", происходит сравнение с спинбоксом, если есть изменение - начало нового расчёта с изменением переменной "сейчас". Обе переменные видны пользователю, устанавливаемая пользователем в виде edit, текущая в виде label.

А все вместе эти проблемы нерешаемы.


Название: Re: Интерактивное (почти) управление
Отправлено: Racheengel от Апрель 18, 2016, 22:34
"Наконец "просралось", дело дошло до событий, и выяснилось что надавил значение куда больше чем думал."
Ну собственно тут и ответ.
до тех пор пока не просралось, виджеты управления блокируем и показываем некий индикатор занятости.

Ну в общем почти. Только блокировать надо лишь при изменении значения. А при следующей отрисовке разблокировать.
Тогда по идее нельзя будет много раз поменять значение в пределах одного кадра.
Но все это полумеры и основной проблемы не решают. ..


Название: Re: Интерактивное (почти) управление
Отправлено: Old от Апрель 19, 2016, 00:03
Но все это полумеры и основной проблемы не решает..
А какую собственно вы хотите решить проблему? Отзывчивость GUI? :)
Ну так она решается предложенным вами методом. По другому гуй нормально разгрузить не получиться.
Как-то вы сами за сомневались в решении, которое сами же решили использовать. :)


Название: Re: Интерактивное (почти) управление
Отправлено: Igors от Апрель 19, 2016, 10:01
Напомню задачу (как я ее вижу)
А хотелось бы так: QLineEdit обновляется при нажатии на клавишу и/или спыннер, юзер видит что установил. Он понимает что новое значение скорости будет задействовано на след кадрах, это нормально.
Т.е. нужно обеспечить feedback, простую реакцию на действия пользователя. Как уже неоднократно упоминалось, это совсем не значит что "UI свободно" (т.е. принимает события в штатном режиме), напротив, обработка других событий не должна начинаться до окончания расчетов и рисования.

Тогда по идее нельзя будет много раз поменять значение в пределах одного кадра.
??? Наоборот, пусть меняет много раз если успевает - это желательно


Название: Re: Интерактивное (почти) управление
Отправлено: Racheengel от Апрель 19, 2016, 11:01
Цитата: Old
Но все это полумеры и основной проблемы не решает..
А какую собственно вы хотите решить проблему? Отзывчивость GUI? :)
Ну так она решается предложенным вами методом. По другому гуй нормально разгрузить не получиться.
Как-то вы сами за сомневались в решении, которое сами же решили использовать. :)

Загрузка основного потока, имхо, тут основная проблема. А обновления гуя уже как следствие.


Название: Re: Интерактивное (почти) управление
Отправлено: lit-uriy от Апрель 19, 2016, 12:24
??? Наоборот, пусть меняет много раз если успевает - это желательно
Нихрена не понял. Это ведь и было проблемой:
Наконец "просралось", дело дошло до событий, и выяснилось что надавил значение куда больше чем думал.
что вообще значит "Если успеет"?

Пользователь внёс изменения -> блокировка ввода -> расчёт -> отображение результата -> разблокировка ввода -> цикл замкнуть тут.



Название: Re: Интерактивное (почти) управление
Отправлено: Old от Апрель 19, 2016, 12:39
Загрузка основного потока, имхо, тут основная проблема. А обновления гуя уже как следствие.
Скажем так, основная проблема в "тупизме GUI" продолжительные паузы между этапами обработки событий, накопившихся в очереди.
Какие решения возможны:
* увеличить частоту отработки processEvents, возможно для этого придется разбивать долгую работу на части, между которыми обрабатывать события. Недостатки: ручной менеджмент всего этого разбиения (этакий ручной greenthreads) :) Такое сложно сопровождать и расширять.
* вынести все тяжелые операции в отдельный поток, оставив GUI-потоку непрерывную обработку событий.

Рабочая нитка:
Код:
void work()
{
    for(;;)
    {
        readUserCtl();     // Читаем значения из GUI установленные пользователем
        readTextures();   // 40 минут
        calcGeometry(); // 1 час 15 минут
        renderScene();   // 3 часа
    }
}
Пока обрабатывается очередной кадр, пользователь может без задержек менять любые параметры, а для следующего кадра будут взяты те, которые рабочая нитка прочтет в начале расчета кадра.


Название: Re: Интерактивное (почти) управление
Отправлено: Igors от Апрель 19, 2016, 12:46
Загрузка основного потока, имхо, тут основная проблема. А обновления гуя уже как следствие.
Прямолинейно разгрузить главную нитку легко может оказаться нереальным.

что вообще значит "Если успеет"?
Напр кадр считается секунду(ы). За это время он напр 5 раз нажал "газ", каждое увеличило значение на 0.1, на следующем кадре газ намного больше. На здоровье ЕСЛИ он видел (и значит согласен) с этим.  

Пользователь внёс изменения -> блокировка ввода -> расчёт -> отображение результата -> разблокировка ввода -> цикл замкнуть тут.
Это соответствует режиму "шаг" (т.е. следующий кадр по действию юзера). А когда "автомат", остается только принять все накопившиеся события и опять уйти на расчет. А накопиться их может немало.



Название: Re: Интерактивное (почти) управление
Отправлено: Old от Апрель 19, 2016, 12:48
Прямолинейно разгрузить главную нитку легко может оказаться нереальным.
Конечно. Все зависит от того, кто и как ее загружал. :)


Название: Re: Интерактивное (почти) управление
Отправлено: lit-uriy от Апрель 19, 2016, 14:47
так, вроде я понял, что тебе надо.

См. скриншот во вложении

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

Сделал так:
С ползунка данные отправляются когда пользователь его отпустит;
Со спинбокса - когда произойдёт таймаут после изменения его величины.


Название: Re: Интерактивное (почти) управление
Отправлено: Igors от Апрель 20, 2016, 12:14
Напомню условие
Но есть одно обстоятельство: в отличие от игры время смены кадра может быть любым ..
Почему-то спокойно принять это условие оказалось невозможным, внимание сосредоточилось только на одном: как сделать время меньше. Да, тогда проблема рассосется сама собой - но это уже др задача (кстати куда более сложная).

Что делать если требуется отрисовка (обычно небольшая), но событийный цикл глухо забит? Использовать вторичный цикл - тоже не гуд. Гораздо естественнее действовать наоборот - заведем нитку которая будет обслуживать нажатия юзера пока главная занята. Но здесь срабатывает заученное правило "UI ТОЛЬКО в главной нитке". Кстати откуда оно взялось? (я лично не помню). Вероятно Qt так снимает кучу ненужных вопросов, но может перетерпеть нативняк NSWindow/HWND куда выгоднее?

Хорошо, смотрю типа "PeekMessage other thread". Ответ однозначен - нет, в др нитке никаких событий не придет. И объяснение почему: окно принимает месяги в той нитке где оно было создано. Позвольте, так значит и создавать (и рисовать) нативные окна в др нитке МОЖНО? И события есть? Тогда что мешает "накрыть виджет прозрачным стеклом", т.е. в др нитке создать окно поверх нашего и спокойно обновлять его. Или как? Или я что-то неправильно понял?


Название: Re: Интерактивное (почти) управление
Отправлено: Old от Апрель 20, 2016, 12:44
Гораздо естественнее действовать наоборот - заведем нитку которая будет обслуживать нажатия юзера пока главная занята. Но здесь срабатывает заученное правило "UI ТОЛЬКО в главной нитке".
А что поменялось? В чем вы видите этот "наоборот"? Это все то же, что предлагал Racheengel.


Название: Re: Интерактивное (почти) управление
Отправлено: Smogg от Май 08, 2016, 00:50
А есть другие варианты кроме learning by doing?
Писать продакшен код всяко лучше вместо того, чтобы говнокодить абстрактную муйню по примерам из книжек.
Глупость брякнули, право) Сначала learning, а уж потом doing. Как говаривал Ницше: "Лишь построив дом научаешься тому, что должен был знать с самого начала". Научится-то научился, но дом-то уже построен!

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

А дом, что дом... Если крепкий получился - то пусть стоит, а если нет, то сам развалится. Зато будет опыт, "как строить нельзя" :)


Как показывает практика, всё реально, вопрос лишь в количестве костылей :D