Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате |
Форум программистов > Visual C++/MFC/WTL > CDC и много потоков |
Автор: mrgloom 23.8.2011, 16:18 | ||
есть такой код.
возможно ли рисовать несколькими потоками в одном CDC? |
Автор: Earnest 23.8.2011, 16:31 |
Не стоит. MFC-объекты вообще к конкретному потоку относятся. Кроме того, Draw обычно происходит в результате обработки сообщения OnPaint (и делать иначе редко когда рекомендуется). А WM_PAINT всегда обрабатывается в том потоке которому принадлежит окно. Короче, никакого смысла в многопоточном рисовании нет. |
Автор: mrgloom 23.8.2011, 16:53 | ||||
попробовал так.
error C2248: 'CObject::CObject' : cannot access private member declared in class 'CObject' видимо все дело в CDC ну а если я хочу рисовать быстрее, то как этого добиться? |
Автор: Earnest 24.8.2011, 07:08 |
CObject не имеет конструктора копирования. Точнее, имеет, но закрытый - т.е. это концептуально не копируемый объект. Равно как и CDC и почти все MFC-объекты. Однако никто не мешает передавать dc по ссылке, а сейчас у тебя действительно копирование. И вообще, судя по коду, ты слабо себе представляешь механизм передачи параметров. И с чего ты вообще взял, что в потоках рисование будет быстрее? Если проблема тормозов на рисовании возникает, она наверняка в организации твоего кода - всяких глупостях типа передачи массива в функцию по значению, а также в функции Draw: выделение буфера под 2 точки динамически, да еще в цикле для каждой линии - это просто шедевр. Ты бы азы подучил, прежде чем в буст и потоки лезть... Ты уж не обижайся, но это какой-то кошмар, твой код... |
Автор: mrgloom 24.8.2011, 09:53 | ||
так лучше?
вроде бы еще говорили, что лучше рисовать через PolyPolyLine ну тогда надо знать, что из точек собрана связанная последовательная фигура. наблюдая за тем, что загружено только 1 ядро. наверно надо сделать, отдельный поток на рисование, и отдельный на все остальное. |
Автор: mrgloom 24.8.2011, 10:51 |
хотя нет так как я написал выше не получится. т.к. получаются лишние связи. а мне надо вывести все независимыми линиями. boost_draw(CDC* dc, vector<Line>& vec) tg.create_thread(boost::bind(&boost_draw, &dc,vec[idx])); так действительно работает, но быстрее (по ощущениям) вроде и не стало. |
Автор: mrgloom 24.8.2011, 14:51 |
хмм оказалось, что даже автокад как то странно работает с потоками.(т.е. не использует все ядра) а если все выводить в картинку\текстуру, то это будет как бы "рендеринг", и это уже можно делать в несколько потоков?(или глупая идея) у меня была структура структур(прямоугольников и более сложных примитивов) которую я распарсил в линии и построил quadtree счет идет на милионы линий. вот теперь думаю, что не очень, то это была хорошая идея, лучше было оставить структурами, но в таком случае не очень понятно как создавать quadtree. |
Автор: Earnest 24.8.2011, 20:20 | ||||
Ну сам подумай, доступ к растру придется как-то делить - нельзя же позволять нескольким потокам писать в одну область памяти одновременно. А эта синхронизация может сожрать весь выигрыш... А делить пространство, типа первый поток рисует только в первую треть, второй - во вторую и т.д. - тоже неудобно - линии-то где угодно заканчиваются. Миллионы линий - это серьезно, здесь действительно нужно оптимизировать вывод. Навскидку, могу предложить след. варианты. 1) Если линии относительно постоянны, то можно один раз нарисовать их во внеэкранный буфер, а затем быстро бросать на экран по мере надобности (когда WM_PAINT приходят). Внеэкранный буфер обновлять по мере необходимости. Причем, чтобы не тормозило, делать это можно и в отдельном потоке, только организовать так, чтобы блокировка не сразу на весь вывод действовала, а как-то разбить (чтобы можно было частично нарисованные линии вывести на экран). 2) Можно попробовать выводить линии в несколько потоков, но в несколько отдельных растров (разные линии, разумеется), а потом эти растры быстренько объединить подходящей битовой операцией (ИЛИ, например, если фон черный). Но памяти, конечно, отожрется много... Автокад использует какую-то интересную схему кэширования чертежа: обновления, которые время от времени происходят, длятся довольно долго, но зато потом, между ними отрисовка такая быстрая, что больше напоминает выброс растра на экран... но тем не менее это дело масштабируется (так же быстро) в довольно широких пределах... вряд ли растр... Сама бы хотела знать, как они это делают...
Не надо путать структуры индексирования со структурами хранения... Никто ведь не мешает хранить структуры, а дерево строить для линий, используя какую-то ссылочную схему - т.е. линия представляется не как 2 точки, а как ссылка на i-е ребро структуры N. |
Автор: mrgloom 25.8.2011, 10:19 | ||||||||
определить какие линии куда попадают я смогу с помощью quadtree, только вместо выполнения поиска для 1 области, у меня получится несколько таких операций. ну если линии такие большие, что попадают в несколько кусков, то будут рисоваться по несколько раз.(тут только добавляется одна операция отсечения ненужной части.) самый плохой вариант, это когда все линии попадают во все куски, т.е. рисуется такой "забор". только не понятно как это реализовать\рисовать ибо я рисую через Polyline и у нее есть параметр CDC и всё, т.е. непонятно как образно выражаясь взять n кусков памяти под потоки транслировать туда линии, а потом склеить всё в 1 кусок памяти и вывести этот кусок на экран.
что значит линии постоянны? их число постоянное, но вот для того чтобы их например сместить на экране, я к каждой точке прибавляю смещение(возможно это неправильный подход) и делаю это прямо в draw() и чтобы изменить масштаб соответственно тоже самое. т.е. у меня есть init_lines где хранятся неизменяемые линии, которые я считал, а temp_lines это те которые я вывожу при каждом draw()
что такое внеэкранный буфер в терминах GDI? (еще нашел такое http://www.rsdn.ru/forum/winapi/2246791.flat.aspx) что такое растр в терминах GDI?
ну да идея ясна, работаем как с линиями, а когда выводить выводим как структуры по несколько точек,если структура попадает не полностью выводим как линии. я изначально сделал все для линий, чтобы было проще. по идее даже можно у любой структуры описать её BoundingRect и работать с ней целиком. и еще уточнение я вывожу сначала картинки через dc.StretchBlt , а потом накладываю линии через PolyLine, если это важно. и еще я уменьшаю кол-во выводимых линий во-первых отсекая по текущему view по quadtree и если малое увеличение не вывожу маленькие детали, т.е. у меня не просто quadtree, а quadtree+ level of detail. |
Автор: Earnest 25.8.2011, 16:10 | ||
Т.е сами линии у тебя не изменяются. Можно поступить, например, так. Завести внеэкранный буфер размером, скажем в 9 текущих экранов (или 4, или... в общем, в зависимости от масштаба - хоть на весь экстент, если размер растра позволит). И нарисовать туда соответствующую часть линий. Выбрасывать на экран соответствующую часть (в зависимости от текущего положения) При скроллинге использовать сдвиг экрана (ScrollDC? это очень быстро) + дорисовывать недостающею часть из буфера. При масштабировании вниз можно тоже не пересчитывать сразу, а использовать StretchBlt/ Пересчитывать буфер начинаем, когда масштаб \ смещение выйдут за пределы Это пара compatible DC + bitmap (обычно compatible, но не обязательно) Растр == битмап, который выбирается в мемори-контекст Отсекать отдельными линиями (ребрами) - очень неэффективно, лучше уж сразу фигуры. Приведу пример из своего приложения. Хранится много графики (в основном полилинии и полигоны, хотя есть и текст и точки и окружности...) В каждой полилинии - до нескольких тысяч точек, полилиний-полигонов иногда сотни тысяч. Т.е., если считать в ребрах, то получаем миллионы линий. Хранится все в даблах, в некоторых логических координатах. Для каждого объекта хранится экстент. Все это добро разделено на слои, как в Автокаде. Есть структура, которая определяет текущее положение и масштаб экрана и, соответственно, преобразование координат. При отрисовке происходит даже не отсечение, а просто проверка на попадание объекта в экран (по экстенту). Затем полилиния пересчитывается в координаты экрана (в целые). Удаляются точки-дубликаты (они возникают при масштабировании-округлении). Рисуем через Polyline или Polygon. Т.е. линейно просматриваются (на предмет экстента) ВСЕ объекты. И притормаживать начинает только при выводе близком к вью-ол, и только если объектов сотни тысяч, и линии длинные (не отсекаются). Внеэкранный буфер имеет размер экрана, без запаса, так проще за ним следить. Т.е. буфер обновляется при любом изменении позиции-масштаба, включении-выключении слоев, изменении объектов и т.д. При рабочем масштабе (т.е. когда на экране можно что-то редактировать) все летает (вместе с подложенным под векторные данные растром). Поэтому никакми дополнительными индексами и потоками не озабачиваюсь. В общем, что хочу сказать... думаю, ты не там ищешь что оптимизировать. Действительно ли тебе нужно квадро-дерево? (Если ты ввел его только для оптимизации вывод, то имхо зря...) Тормоза могут возникать из-за неоптимальных вызово GDI-функций - я уже говорила, они страшно дорогие. Т.е. все эти смены перьев и прочая нужно оптимизировать очень жестко. Толстые линии и линии не солид тоже могут тормозить... |
Автор: mrgloom 8.9.2011, 13:56 | ||
про вывод графики понял, его ускорить можно только если использовать что то типа двойного буфера. у меня получается что перед вывоводом надо из общего кол-ва примитивов выделить те, которые попадают в область+те которые не видны на масштабе, это занимает процессорное время. (если выводить все, то тормозит)
не понял как это? как хранятся примитивы? |
Автор: mrgloom 8.9.2011, 14:13 |
есть еще идея не строить это квад-дерево(ибо и место занимает и время на построение) а просто у каждого примитива построить его boundrect (ограничивающий прямоугольник) и проверять пересечение этих прямоугольников с видимым прямоугольником в несколько потоков. Добавлено через 1 минуту и 27 секунд или из этих boundrect примитивов построить R-tree или просто взять сетку с константным шагом. |
Автор: Earnest 9.9.2011, 08:36 | ||
Именно их я и называю экстентами. И не надо никакого R-дерева, попробуй сначала быть проще... И несколько потоков тоже не надо... И что ты называешь примитивами? Отдельные отрезки или полные фигуры? Лучше второе - их меньше ![]() На худой конец, используй самый простой пространственный индекс - кластеры постоянного размера (или сетку) - просто поддерживать, просто использовать, а выигрыш дает приличный. Я использую такой индекс в расчетных утилитах, когда нужно искать что-то рядом с чем-то; а для вывода на экран - только проверку экстентов (которые, разумеется, хранятся для каждого объекта). |