Практикум прикладного программирования на C# в среде VS.NET 2005

Выбор подходящего устройства в DirectX

Показывать лекцию целиком

Файлы к лабораторной работе Вы можете скачать здесь.

Иногда возникает необходимость предусмотреть в приложении Direct3D возможность определения количества и типа установленных на компьютере видеоадаптеров для выбора наиболее оптимального режима работы приложения. В сборках DirectX существует статический класс Manager, который можно использовать для идентификации адаптеров и имеющихся в системе устройств. В данной работе мы рассмотрим

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

    Создание приложения

  • Создайте новый проект для C# с именем AdapterView
  • Добавьте в проект ссылки на сборки DirectX командой Project/Add Reference
  • Удалите из проекта ненужные в данный момент ссылки
  • Откройте файл Form1.cs в режиме View Code и отредактируйте блок директив "using" в заголовке файла для добавленных сборок, чтобы это выглядело так
  • using System;
    using System.Drawing;
    using System.Collections;
    using System.ComponentModel;
    using System.Windows.Forms;
    using Microsoft.DirectX;
    using Microsoft.DirectX.Direct3D;
      
    namespace AdapterView
    {
    ..................................
    }
  • Откройте файл Form1.cs в режиме View Designer и поместите на форму двойным щелчком из вкладки Widows Forms панели Toolbox компонент TreeView
  • Выделите компонент TreeView и через панель Properties установите его свойство Dock в значение Fill
  • Теперь необходимо добавить функцию, которая сканирует все адаптеры в системе и выдает некоторую информацию относительно поддерживаемых режимов каждого из них.

  • Добавьте в конец класса Form1 после функции Main() следующий код
  • public void LoadGraphics()
        {
          foreach(AdapterInformation ai in Manager.Adapters)
          {
            // Создать неотображаемый древовидный список
            TreeNode root = new TreeNode(ai.Information.Description);
            // Создать неотображаемый древовидный список
            TreeNode driverInfo = new TreeNode(
              string.Format("Driver information: {0} - {1}",
                            ai.Information.DriverName,
                            ai.Information.DriverVersion));
            // Добавить информацию о драйверах в главное дерево
            root.Nodes.Add(driverInfo);
            // Создать неотображаемый древовидный список
            // и получить в него для каждого дисплея режим поддержки
            TreeNode displayMode = new TreeNode(
              string.Format("Current Display Mode: {0}x{1}x{2}",
                            ai.CurrentDisplayMode.Width,
                            ai.CurrentDisplayMode.Height,
                            ai.CurrentDisplayMode.Format));
            // Перебрать все режимы для найденного адаптера
            foreach(DisplayMode dm in ai.SupportedDisplayModes)
            {
              // Создать неотображаемый древовидный список
              TreeNode supportedNode = new TreeNode(
                string.Format("Supported: {0}x{1}x{2}",
                              dm.Width, dm.Height, dm.Format));
              displayMode.Nodes.Add(supportedNode);
            }
            // Добавить информацию о поддерживаемых режимах
            root.Nodes.Add(displayMode);
            // Добавить в компонент для отображения
            treeView1.Nodes.Add(root);
          }
        }

    Функция LoadGraphics() во внешнем цикле ведет поиск всех адаптеров в системе, заполняя для каждого найденного адаптера экземпляр ai класса AdapterInformation

    Значение свойства Adapter относится к номеру адаптера, который используется при создании устройства. Порядковые номера адаптеров в системе отсчитываются с нуля. Функция GetWhqlInformation() возвращает дополнительную информацию о WHQL (Лаборатория по сертификации аппаратных средств для работы в среде Windows). Извлечение информации о WHQL может быть долгим, поэтому в приложении для Direct3D лучше эту возможность не использовать.

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

    Вначале мы создаем корневую папку древовидного списка root в качестве нулевого уровня дерева списка. Затем мы добавляем в качестве первого уровня дерева папку, которая будет включать имя драйвера и номер версии. На следующем уровне мы добавляем папку, в которую сохраняем текущие параметры режима визуального отображения адаптера. В дочерних узлах сохраняем данные о поддерживаемом формате и режимах найденного адаптера.

  • Измените функцию Main() так, как показано ниже, чтобы обеспечить вызов функции LoadGraphics()
  • static void Main() 
        {
          using(Form1 frm = new Form1())
          {
            frm.LoadGraphics();
            Application.Run(frm);
          }
        }
  • Постройте приложение и получите информацию о графических фозможностях вашей системы. Результат должен быть примерно таким
  • В окне приложения отображается список режимов и форматов, поддерживаемых устройством. Перечисляемые форматы описываются с помощью буквенно-цифрового кода. Символ представляет тип данных, номер - число битов поддерживаемых данных. Символы расшифровываются так:

  • A (alpha) - альфа-канал (прозрачность)
  • X (unused) - неиспользуемый
  • R (red) - красный
  • G (green) - зеленый
  • B (blue) - синий
  • L (luminance) - яркость
  • P (palette) - палитра
  • Сумма всех битов в формате определяет полный размер формата. Например, X8R8G8B9 означает 32-разрядный формат с 8 битами для каждого цвета экранной модели цветов RGB и с неиспользованными 8 битами.

    Свопинг-связки и рендеры

    Существуют несколько неявных функций и процедур обработки в устройстве (класс Microsoft.DirectX.Direct3D.Device ), которые определяют, где и как нарисовать объект. Каждое устройство имеет неявные цепочки подкачки (или свопинг-связки), использующиеся для рендеринга объекта.

    Свопинг-связка представляет собой ряд буферов, управляющих рендерингом. Есть вторичный буфер, определяющий окончательный результат рисования. Когда свопинг-связка, определяемая перечислением Microsoft.DirectX.Direct3D.SwapEffect.Flip, готова, данные вторичных буферов передаются на первичный буфер, с которого их считывает графическая плата. Сразу после этого третичный буфер становится вторичным, вторичный - первичным, а первичный - третичным, т.е. смена буферов происходит по кругу.

    При необходимости DirectX может создавать большее количество скрытых буферов для оперативной подготовки графической информации. Иногда программист сам должен следить за своевременной очисткой вторичного буфера перед запуском новых операций рисования.

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

    Форматы вторичных буферов и дисплеев

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

    A2R10G10B10 X8R8G8B8 X1R5G5B5
    A8R8G8B8 A1R5G5B5 R5G6B5

    Чаще всего встречаются форматы, выделенные в таблице. Если мы жестко ориентируемся на использование какого-то формата, то проверить его поддержку в системе можно с помощью следующей функции класса Manager

    public static System.Boolean CheckDeviceType( 
      System.Int32 adapter, 
      Microsoft.DirectX.Direct3D.DeviceType checkType, 
      Microsoft.DirectX.Direct3D.Format displayFormat, 
      Microsoft.DirectX.Direct3D.Format backBufferFormat, 
      System.Boolean windowed, 
      System.Int32 result)

    где

  • adapter - номер тестируемого адаптера
  • checkType - тип проверяемого устройства (обычно это DeviceType.Hardvare )
  • displayFormat - выбранный формат устройства
  • backBufferFormat - выбранный формат вторичного буфера
  • windowed - режим работы (оконный или полноэкранный)
  • result - дополнительный параметр, возвращающий целочисленный код функции ( HRESULT и COM )
  • Функция возвратит значение true, если проверяемый тип устройства поддерживается системой.

    Важно отметить, что в оконном режиме формат вторичного буфера не должен соответствовать формату режима визуального отображения, если аппаратные средства способны поддерживать соответствующее цветовое преобразование. Возможность преобразования можно проверить функцией CheckDeviceFormatConversion() класса Manager.

    Проверка возможностей устройства

    Различные возможности аппаратных средств описываются термином "capability" - возможность. В Direct3D имеется опция, которая перечисляет все имеющиеся возможности используемого устройства. Как только устройство создано, ее можно использовать для определения имеющихся возможностей. Для несозданного устройства также можно узнать возможные поддерживаемые характеристики устройства с помощью определенного метода класса Manager.

    Теперь можно добавить к нашему приложению код, который выдаст описание свойств и возможностей каждого найденного адаптера в системе. Из-за большого объема информации будем ее выводить не в древовидный список, а в текстовое поле.

  • Выделите на форме компонент TreeView и измените его свойство Dock на значение Left.
  • Расширьте форму и поместите на освободившееся место справа от списка TreeView компонент TextBox из вкладки Windows Forms панели Toolbox.
  • Установите для компонента TextBox свойства: Multiline=true, Dock=Fill, ScrollBars=Both, Text= пусто
  • Выделите компонент TreeView и через панель свойств, установленную в режим Events, создайте двойным щелчком для события AfterSelect обработчик, который заполните так
  • private void treeView1_AfterSelect(object sender, System.Windows.Forms.TreeViewEventArgs e)
        {
          if(e.Node.Parent == null) // Только для корня дерева
          {
            textBox1.Text = e.Node.Text 
              + " Capabilities: \r\n\r\n"
              + Manager.GetDeviceCaps(e.Node.Index, DeviceType.Hardware)
                .ToString().Replace("\n", "\r\n");
          }
        }

    Для корневых папок, которые отображают названия адаптеров, при их выборе мы вызываем функцию Manager.GetDeviceCaps() для соответствующего номера адаптера.

  • Запустите приложение и должен получиться примерно такой результат
  • Многие возможности, перечисленные в списке, используются только в непрограммируемом конвейере. Если использовать программируемый конвейер, многие возможности не понадобятся в сцене приложения. Полученный список возможностей устройства можно разделить на две группы. Первая группа - логичесие значения, которые определяют, поддерживается ли данная аппаратная возможность или нет. Вторая группа отражает фактические значения соответствующих возможностей в данной системе. Например, MaxActiveLights определяет допустимое количество активных подсветок, реализуемых в сцене.

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

    Вернуться к учебному плану