Что такое gdi драйвер

Обновлено: 30.06.2024

Direct2D и GDI являются API-интерфейсами двухмерной отрисовки в режиме интерпретации и имеют некоторую степень аппаратного ускорения. В этом разделе рассматриваются различия между Direct2D и GDI, включая предыдущие и представляющие различия в функциях аппаратного ускорения обоих API.

Этот раздел содержит следующие компоненты.

Различия между Direct2D и GDI

GDI отображает непрозрачные геометрические объекты, такие как многоугольники, эллипсы и линии. Он отображает текст с псевдонимами и ClearType, а также поддерживает прозрачное смешение через API Алфабленд. Однако его обработка прозрачности не согласуется, и большинство интерфейсов API GDI просто игнорируют альфа-канал. Несколько интерфейсов API GDI гарантируют, что альфа-канал будет содержать после операции. Что более важно, отрисовка GDI не позволяет легко сопоставляться с трехмерными операциями, а современный GPU эффективно визуализируется в трехмерной части его подсистемы визуализации. Например, строки с псевдонимами Direct2Dпредназначены для реализации просто как два треугольника, отображаемых на GPU, в то время как GDI использует алгоритм рисования линий бресенхам.

Direct2D отображает непрозрачные, прозрачные, псевдонимы и сглаженные примитивы. Современные интерфейсы пользователя часто используют прозрачность и анимацию. Direct2D упрощает создание современного пользовательского интерфейса, поскольку он имеет ограниченную гарантию того, как он принимает и визуализирует прозрачное содержимое, а все его примитивы подготавливаются к просмотру с помощью аппаратного ускорения. Direct2D не является чистым надмножеством GDI: примитивы, которые были бы неоправданными при реализации в GPU, отсутствуют в Direct2D. Так как Direct2D построен с помощью этого акцента на трехмерном ускорении, его также легко использовать с Direct3D.

начиная с Windows NT 4, GDI работает в режиме ядра. Приложение вызывает GDI, который затем вызывает аналог режима ядра, который передает примитивы в собственную модель драйвера. Затем этот драйвер отправляет результаты в глобальный драйвер монитора режима ядра.

начиная с Windows 2000, gdi и драйверы gdi были запущены в независимом пространстве ядра, именуемом "пространство сеанса". Адресное пространство сеанса создается для каждого сеанса входа в систему, и каждый экземпляр GDI выполняется независимо в этом отдельном адресном пространстве режима ядра. Однако Direct2D работает в пользовательском режиме и передает команды рисования с помощью драйвера Direct3D пользовательского режима в драйвер режима ядра.

рис. 1. Direct2D по сравнению с GDI

Аппаратное ускорение GDI и Direct2D

Самое важное различие между Direct2D и аппаратным ускорением GDI — это базовая технология, которая их выполняет. Direct2D находится на вершине Direct3D, а GDI имеет собственную модель драйвера, интерфейс драйвера устройства GDI (DDI), соответствующий примитивам GDI. Модель драйвера Direct3D соответствует тому, что отображает оборудование для отрисовки трехмерной графики в GPU. Когда DDI GDI был впервые определен, большинство устройств ускорения экрана нацелены на примитивы GDI. Со временем в ускорении трехмерной игры было включено больше и больше, чем при ускорении приложения. Как следствие, API BitBlt был аппаратным ускорением, а большинство других операций GDI — нет.

Это позволяет настроить этап для последовательности изменений в способе отображения GDI на экране. на следующем рисунке показано, как визуализация отображения GDI изменилась с Windows XP на Windows 7.

рис. 2. развитие отрисовки отображения GDI

Существует также ряд дополнительных факторов, которые привели к изменению модели драйвера GDI , как описано ниже.

Повышение сложности и размера драйверов экрана

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

Трудности при синхронизации сеанса и глобальных адресных пространств ядра

в Windows XP драйвер экрана существует в двух разных адресных пространствах: пространстве сеанса и пространстве ядра. Компоненты драйвера должны реагировать на события, такие как события управления питанием. Это необходимо синхронизировать с состоянием драйвера в адресном пространстве сеанса. Это сложная задача, которая может привести к дефектам, когда драйверы экрана пытаются работать с этими отдельными адресными пространствами.

Управление составным окном

диспетчер окон рабочего стола (DWM), диспетчер окон компоновки, появившийся в Windows 7, отображает все окна в виде экранов, а затем объединяет их вместе, чтобы они отображались на экране. Для этого необходимо, чтобы GDI мог подготовиться к просмотру на поверхности, которая затем будет отображена Direct3D для отображения. Это потребовало проблемы в модели драйвера XP, поскольку GDI и Direct3D были стеками драйверов параллельного выполнения.

в результате в Windows Vista драйвер отображения DDI для gdi был реализован в качестве стандартного видеодрайвера (cdc), который выводит содержимое GDI в битовую карту системной памяти, которая состоялась на экране.

визуализация GDI в Windows 7

модель драйвера, используемая в Windows Vista, требует, чтобы каждое окно GDI было использовано как поверхность видеопамяти, так и область системной памяти. Это привело к тому, что системная память использовалась для каждого окна GDI.

сравните Direct2D и ускорение GDI в Windows 7

Direct2D и GDI являются как плоскими API-интерфейсами рендеринга в режиме ожидания, так и аппаратным ускорением. Однако существует ряд различий, которые остаются в обоих API.

Расположение ресурсов

По умолчанию GDI сохраняет свои ресурсы в определенных точечных рисунках в системной памяти. Direct2D сохраняет свои ресурсы в видеопамяти видеоадаптера. Когда GDI требуется обновить видеопамять, это необходимо сделать на шине, если ресурс уже не находится в сегменте памяти апертуры или если операция может быть выражена напрямую. В отличие от этого, Direct2D может просто перевести свои примитивы в примитивы Direct3D, так как ресурсы уже находятся в видеопамяти.

Метод подготовки к просмотру

Для обеспечения совместимости GDI выполняет большую часть его отрисовки для апертуры памяти с помощью ЦП. В отличие от этого, Direct2D преобразует вызовы API в примитивы Direct3D и операции рисования. Затем результат отображается на GPU. Некоторые из модулей отрисовки GDI. s выполняются на GPU при копировании памяти апертуры на поверхность видеопамяти, представляющая окно GDI.

Масштабируемость

Вызовы отрисовки Direct2D— это все независимые потоки команд для GPU. Каждая фабрика Direct2D представляет собой другое устройство Direct3D. GDI использует один командный поток для всех приложений в системе. Метод GDI может привести к накруткиию ресурсов GPU и контекста рендеринга ЦП.

Расположение

Direct2D работает полностью в пользовательском режиме, включая время выполнения Direct3D и драйвер пользовательского режима Direct3D. Это помогает предотвратить системные сбои, вызванные дефектами кода в ядре. Однако GDIимеет большую часть функциональных возможностей в пространстве сеанса в режиме ядра и его поверхность API в пользовательском режиме.

Доступность аппаратного ускорения

GDI — это аппаратное ускорение в Windows XP и ускоренное на Windows 7 при запуске диспетчер окон рабочего стола и использовании драйвера WDDM 1,1. Direct2D является аппаратным ускорением практически любого драйвера WDDM и независимо от того, используется ли DWM. В Vista GDI всегда отображается в ЦП.

Модель представления

при первоначальном построении Windows недостаточно памяти, чтобы все окна сохранялись в своем собственном растровом изображении. В результате GDI всегда отображается логически непосредственно на экране, при этом применяются различные области отсечения, чтобы убедиться, что приложение не было отображено за пределами окна. В модели Direct2D приложение подготавливается к просмотру в буфере, а результат отображается при прорисовке приложения. Это позволяет Direct2D выполнять сценарии анимации гораздо более плавно, чем GDI.

Заключение

существующий код GDI продолжит работать в Windows 7. Однако при написании нового кода отрисовки графики следует учитывать Direct2D , поскольку он использует преимущества современных графических процессоров.

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

Проблема

Утечка или использование слишком большого числа GDI объектов.

Симптомы:

Почему?

Как исправлять?

Если Вы живете в аккуратном управляемом CLR’ом мире, то вероятность 9 из 10, что у Вас в приложении обычная утечка памяти. Проблема хоть и неприятная, зато довольно обыденная и есть по меньшей мере дюжина отличных инструментов для ее поиска. Подробно останавливаться на этом не буду. Вам лишь будет нужно использовать любой профилировщик, чтобы посмотреть, не увеличивается ли число объектов-оберток над GDI ресурсами, это: Brush, Bitmap, Pen, Region, Graphics. Если это действительно так, то Вам повезло, можете закрывать вкладку со статьей.

Если не нашлась утечка объектов-оберток, то значит у Вас в коде есть прямое использование функций GDI и сценарий, при котором они не удаляются.

Что Вам будут советовать другие?

Официальное руководство от Microsoft или другие статьи по этому поводу, которые Вы найдете в интернете, будут советовать примерно следующее:

Найти все Create%SOME_GDI_OBJECT% и узнать, есть ли соответствующий ему DeleteObject(или ReleaseDC для HDC-объектов), а если и есть, то, возможно, существует сценарий, при котором он не вызовется.

Есть еще чуть улучшенная версия этого метода, она содержит дополнительный первый шаг:


Проект, над которым я работаю, имеет кодовую базу в более 9 миллионов строк и еще примерно столько же в third-party библиотеках, сотни вызовов функций GDI, размазанных по десяткам файлов. Я потратил много сил и кофе, прежде чем понял, что вручную просто невозможно это проанализировать ничего не упустив.

Что предложу я?

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


После чего запустил процесс на отладку в Visual Studio, а здесь выбрал его в дереве процессов. Первая точка останова сработала мгновенно:


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


Задача: Найти те вызовы функций GDI, которым не соответствует удаление. В логи присутствует все необходимое: список вызовов функций в хронологическом порядке, их возвращаемые значения и параметры. Получается, что мне нужно взять возвращаемое значение функции Create%SOME_GDI_OBJECT% и найти вызов DeleteObject с этим значением в качестве аргумента. Я выделил все записи в Api Monitor, вставил в текстовый файл и получил что-то вроде CSV с разделителем TAB. Запустил VS, где думал написать программу, чтобы попарсить это, но, прежде чем она загрузилась, мне пришла в голову идея получше: экспортировать данные в базу и написать запрос, чтобы выгрести то, что меня интересует. Это был правильный выбор, потому что позволил очень быстро задавать вопросы и получать на них ответы.

Есть множество инструментов, чтобы импортировать данные из CSV в базу, потому не буду на этом останавливаться (mysql, mssql, sqlite).

У меня получилась вот такая таблица:


Написал функцию mysql, чтобы получать дескриптор удаляемого объекта из вызова апи:


И наконец запрос, который найдет все текущие объекты:

(Строго говоря, он просто найдет все вызовы Delete на все вызовы Create)



На рисунке сразу видны вызовы, на которые так и не нашлось ни одного Delete.

Остался последний вопрос: Как найти откуда вызываются эти методы в контексте моего кода? И здесь мне помог один хитрый трюк:

  1. Запустить приложение на отладку в VS.
  2. Найти его в Api Monitor и выбрать.
  3. Выбрать нужную функцию Api и поставить точку останова.
  4. Терпеливо нажимать “Далее”, пока она не вызовется с интересующими параметрами. (Как же не хватала conditional breakpoints из vs
  5. Когда дойдете до нужного вызова, перейти в VS и нажать break all.
  6. Отладчик VS будет остановлен в месте, где создается утекающий объект и останется лишь найти, почему он не удаляется.

Резюме:

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

Вот он, для тех кому было лень читать или кто уже забыл с чего все начиналось, пока читал:

image

Сегодня принтер несильно отличается от компьютера. У него есть процессор, память, операционная система и постоянная память-накопитель. Если принтер сетевой, то у него есть сетевая карта и веб-сервер, позволяющий его администрировать. Принтеры не только поддерживают разные сетевые протоколы, но и принимают задания на специфичных языках, которые описывают разметку страниц и документов. Таким образом, на крупном предприятии программные средства печати должны взаимодействать с разными аппаратными реализациями протокола печати, возможно даже неизвестными. Конфигурирование печати принтера труднее, чем кажется на первый взгляд. Пользователи воспринимают печать как должное, однако, для получения качественного результата нужно пройти не один шаг.

В этой статье предлагаю рассмотреть и сравнить технологии печати, с которыми вы сталкиваетесь, выбирая новый принтер, проводя допечатную подготовку документа или работая с электронными PDF-копиями документов. И конечно, если вы пытаетесь перехватить и проанализировать задание на печать.

О языках принтеров

Что такое задание на печать? Это программа, написанная на специальном языке программирования – Page Description Language (PDL).

Печатаемые страницы кодируются в PDL и занимают меньший размер, а значит, передаются быстрее необработанных изображений. PDL не зависят ни от самих устройств, ни от разрешающей способности. Принтеры преобразуют задания на специализированном языке в понятный для устройства формат. Это значит, что принтеры содержат языковые интерпретаторы. Также как у языков программирования «а ля Java», у этих языков не одна версия и каждая работает немного по-своему.

Преобразование PDL в растровые изображения выполняется программой-обработчиком: процессором растровых изображений, Raster Image Processor или просто RIP.

Самые известные PDL языки: Postscript, PCL5, PCL6

PostScript – самый распространённый из всех. Первоначально разработан компанией Adobe. Требует наличия лицензии для использования, поэтому на сегодняшний день используется преимущественно в высокопроизводительных устройствах верхнего ценового сегмента. Почти все программы, компонующие страницы, могут генерировать задания на PostScript. Это полнофункциональный язык программирования. Написанные программы можно просматривать с помощью текстового редактора. В них много круглых скобок, а также символов / %!

P.S. Эти символы ищутся интерпретаторами для распознавания заданий на печать.

Пример PostScript:


Также PostScript является стандартом для MAC и профессиональным стандартом.

PCL – или Printer Common Language – альтернатива PostScript от Hewlett Packard (далее HP). Язык понятен принтерам других производителей, некоторые умеют работать только с ним. PCL – не язык программирования, он просто сообщает на принтер как ему следует напечатать страницы. Задания на PCL бинарные и непонятны для человека, зато короче по размеру, чем PostScript.

Существуют фильтры, преобразующие Postscript в PCL. Версии PCL разнятся не так сильно как PostScript, но достаточно, чтобы вызывать раздражение. Задания печатаются немного не так на разных моделях принтеров. Причина в диалектах со специальными командами. В отличие от PostScript, PCL изначально заточен именно на управление принтером, а не на переносимость страницы, поэтому для достижения наилучшего результата печати необходимо использовать команды под соответствующий принтер. Именно поэтому в операционной системе (ОС) указывается модель принтера, в противном случае генерируются иные PCL команды, интерпретируемые неправильно или вовсе игнорируемые.

На самом деле, вопрос не только в железе: существует так называемая эмуляция.

Эмуляция PCL – это значит, что разработчик стандарта (т.е. HP) не лицензировал или не тестировал принтер производителя на совместимость с PCL.

Эмуляция PostScript – Adobe не получал отчисления за свой интерпретатор PostScript, вместо этого некоторые вендоры написали собственный код. Политика лицензирования породила диалекты языков – схожие, но не повторяющие оригинал в точности. На практике оба могут выполняться с ошибками, но случается такое редко.

Чтобы вас окончательно запутать, HP определила два семейства языков PLC5 (5e – черно-белый, и 5c – цветной) и PCL6 (PCL/XL). Новые HP принтеры поддерживают оба. Ранее существовал и PCL4, но сейчас он слишком архаичный. Начиная с PCL5 5e, также были введены такие новшества, как: поддержка разрешения 600 dpi, двунаправленный обмен данными между принтером и компьютером и новые шрифты для Microsoft Windows.

Пример PCL5:


Пример PCL6:


PDF – еще одна разработка Adobe – Portable Document Format. Это формат документов, использующий часть возможностей PostScript, основа издательского дела и программ Office. PDF-документы не зависят от ОС и платформы. Очень часто формат используется для обмена документами с возможностью просмотра и печати. PDF – язык описания документов, а не страниц. Позволяет описывать не только страницы, но и всю структуру документа, главы, взаимосвязь текстовых столбцов друг с другом, правки и так далее. Плюс, куча возможностей мультимедиа.

Есть принтеры, которые интерпретируют PDF напрямую. Есть масса программ-трансляторов и визуальных редакторов с возможностью преобразования PDF, например, в PostScript. Это преобразование даже может быть скрыто от пользователя.


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

HP-GL/2 – Hewlett-Packard Graphics Language – Служат для печати векторной графики в составе документа.

HPGL – язык поддержки плоттеров. Поддерживается почти всеми HP-принтерами.

PJL – Printer Job Language. Язык заданий для принтера, метаязык от HP, описывает какой PDL должен использоваться для задания, каким будет формат бумаги, сколько копий нужно напечатать, симплексное задание или дуплексное и так далее.

О драйверах

Драйвер принтера и поддержка – ПО, преобразующее файл в понятный для принтера. Задачи и функции драйвера отвечают на вопросы: «Что если принтер не поддерживает все языки?», «Имеется задание postscript, а принтер распознает только PCL 5E. Нужно напечатать PDF, что делать, если принтер его не интерпретирует?».

Система сможет сделать все самостоятельно (выяснить язык PDL файла, выполнить преобразования). Вы также можете преобразовать файл вручную. Браузеры умеют преобразовывать HTML в postscript или в PDF. Open Office может преобразовать .doc в PDF. Из postscript можно преобразовать почти в любой формат, в том числе PCL.

GDI – ещё задание на печать можно просматривать и интерпретировать централизованно, на ПК. Также можно отправлять готовые обработанные растровые изображения на принтер «без интеллекта». Именно так и работают многие Windows GDI-принтеры. Такие принтеры обладают весьма незначительным количеством логических инструкций и совсем не обладают интерпретаторами PDL. Вместо этого растеризацию выполняет обслуживающий компьютер. Часть информации для взаимодействия с GDI скрыта в коде Windows под патентами. Эта секретность затрудняет разработку аналогов в системах Linux, и, по сути, является преимуществом. Аналогично ситуация развивается с поддержкой новейших моделей принтеров. Впрочем, ситуация меняется благодаря существованию демона CUPS с поддержкой многих Win Printers с помощью реверс инжиниринга.

О сервере печати

В Windows печать через протокол IPP появилась, начиная с Windows 2000. На клиентах с Windows 7 и новее, поддержка протокола IPP, как правило, уже установлена. Также есть Internet Printing – windows реализация сервера печати Internet через IPP. Для его установки необходимо сначала установить службу веб сервера MS IIS

О безопасности для принтеров

Какая операционная система используется принтером? Некоторые модели имеют Linux-based дистрибутив на борту. Понять, что же установлено на принтере, либо поменять пароли по умолчанию можно лишь закопавшись в документацию производителя. Неразбериха с операционной системой усугубляется тем, что средства графического администрирования имеют тенденцию сокрытия сведений о различиях производителей.

В заключение хочу еще раз сказать, что проблемы печати многогранны, некоторые из них остались за рамками статьи. В следующий раз надеюсь рассказать о ведении журналов, PPD-файлах и форматах бумаги. О том, как попросить монохромный принтер распечатать двусторонний цветной документ в неизвестном ему формате b4, а также о всевозможных утилитах печати и командах совместимости.


Думаю, многим приходилось сталкиваться с проблемой, что GDI+ тормозит, а тормозит, потому что не ускоряется железом.
Вот и я как-то писал редактор уровней

и понял, что GDI+ мне больше не хватает, нужно переходить на что-то ускоренное, причем за минимальное время. Немного погуглив, я решил остановить свой выбор на библиотеке OpenTK.

Почему выбор пал именно на OpenTK? Во-первых, OpenTK предоставляет класс GLControl (является прямым наследником UserControl), который позволяет упростить переход на данную библиотеку. Во-вторых, в комплекте идет класс TextPrinter, который позволяет довольно просто выводить текст на экран. В-третьих во время гугления я нашел небольшой архив «Engine.zip» с набором классов для 2D-отрисовки, инициализации OpenGL и прочими приятностями.

  • DrawString — выводит текст
  • DrawImage — рисует GLImage
  • DrawLine — рисует линию
  • DrawRectangle — рисует прямоугольник
  • FillRectangle — рисует закрашенный прямоугольник
  • DrawPoint — рисует точку
  • DrawPoints — рисует несколько точек
  • DrawMultiImage — рисует GLMultiImage (для отрисовки нескольких одинаковых изображений разом — это гораздо быстрее, нежели рисовать по одному, если таких изображений много)
Некоторые моменты
  1. Первое с чем я столкнулся: контрол вообще не перерисовывался при запуске, решилось просто, нужно не забыть вызвать метод SwapBuffers в конце OnPaint, GLControl уже имеет встроенную функциональность DoubleBuffer, нужно только переключить буфер
  2. Следующий момент, о который я споткнулся — это черные прямоугольники вместо изображений. Решалось вызовом image.SetBlending() перед отрисовкой, сейчас в библиотеке все изображения рисуются с блендингом, поэтому с этим проблем быть не должно
  3. Когда я второй контрол перевел на рельсы OpenTK, то оказалось, что первый контрол после этого перестал выполнять свои функции, решилось вызовом метода MakeCurrent в OnPaint перед отрисовкой элементов
  4. TextPrinter (основа для DrawString) иногда падает при выводе текста, тут ничего не поделаешь — класс глючный и на определенных сочетаниях качества отрисовки, шрифта и размера шрифта он падает, пришлось подбирать шрифт и размер
  5. Еще нужно отслеживать, что контрол загрузился и только после этого работать с OpenTK/GLGraphics, а также проверять, что контрол не в режиме дизайнера форм
  6. При изменении размеров контрола нужно не забыть вызвать GLGraphics.Resize(Width, Height)
Заключение


Библиотека лежит на GoogleCode, под BSD лицензией. Если кому понадобится — пользуйтесь на здоровье. Чтобы понять как работать с библиотекой — посмотрите исходный текст сэмпла, который идет в комплекте, он очень простой:

Все описанные выше «моменты» в нем учтены.
Данную библиотеку я пока не рекомендовал бы использовать для продуктов, нацеленных на массового пользователя — она слишком молода для этого, но в утилитах вполне пригодна к использованию.
На данный момент планов по развитию библиотеки у меня нет — мне ее функционала хватает. Но багфиксы и патчи приветствуются :)

Судя по тому, что я прочитал на OpenTK форуме, TextPrinter (используется для вывода текста) в будущем будет исключен из библиотеки, но, возможно, в отдельный проект. Так что его судьба пока что туманна. Сейчас он в состоянии Deprecated, поэтому дает warnings при компиляции библиотеки.

Вот теперь редактор карт работает значительно быстрее и ничего не тормозит, чего и вам желаю!

UPD: забыл указать ссылку на сайт OpenTK
UPD2: исправил баг с путями в исходниках сэмпла (как в архиве, так и в SVN)

Читайте также: