При создании устройства IDirect3DDevice9, автоматически создаются две поверхности: основной буфер и фоновый буфер (front/back buffer; встречаются и другие переводы: передний буфер и задний буфер). Для указания свойств этих поверхностей нужно заполнить структуру D3DPRESENT_PARAMETERS

Буфер - зарезервированный участок памяти для обмена данными. В данном конкретном случае буфер реализуается в виде поверхности. Мы будем использовать эти слова как синонимы.

Основной буфер (front buffer) - картинка, которую пользователь видит на экране. Запомните, что Direct3D никогда не "рисует" на основной поверхности.

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

Смена поверхности осуществляется посредством указателей.

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

Смена поверхностей происходит при вызове метода IDirect3DDevice9::Present (present - представлять). То есть, когда происходит вызов данного метода, то фоновый буфер представляется (present) - становится основным, а основной - становится фоновым. Другими словами, метод Present выводит кадр на экран.

Поверхности в памяти

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

В памяти поверхность представлена в виде массива точек (пикселей). Каждый пиксель - это маленький кусочек изображения. Например, у монитора может быть разрешение в 1024x768 пикселей - это значит, что изображение на экране состоит из 1024 пикселей в ширину и 768-и пикселей в высоту, а всего на эран выводится 786432 (1028*768) пикселя каждый кадр.

Каждый пиксель представляет собой точку определённого цвета.

Пусть пиксель состоит из 32 битов (на данный момент - самый распространённый формат). Самый старший байт не используется. Второй байт - красный канал. Т.е. этот байт представляет собой красный цвет в пикселе. Третий байт - зелёный канал. И четвёртый байт - синий канал. Каждый канал может принимать 256 значений. Представление цвета в виде трёх каналов: красного, зелёного и синего называется RGB-моделью (Red - красный, Green - зелёный, Blue - синий).

Помните, что я всё упрощаю и заодно совмещаю с DirectX. На самом деле оно немножко не так. Но пока считайте, что точки на экране (и точки в поверхностях) состоят из 4 байтов: пустой, красный канал, зелёный канал, синий канал.

Начало поверхности - левый верхний угол.

Рассмотрим первые три пикселя какой-нибудь поверхности. У пикселей следущие цвета: белый, чёрный, синий.

0 255 255 255, 0 0 0 0, 0 0 0 255 // десятичные числа

0x00ffffff 0x00000000 0x000000ff // шестнадцатиричные числа

Вот так вот в памяти выглядит поверхность (изображение) - всего-лишь массив чисел.

Двойная и тройная буферизация (double and triple buffering)

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

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

Структура D3DPRESENT_PARAMETERS

Структура D3DPRESENT_PARAMETERS хранит свойства основной и фоновой поверхности. Данную структуру нужно заполнять до создания устройства.

При создании поверхностей нужно указывать формат пикселей. Форматы пикселей поверхностей хранятся в перечислении (enum) D3DFORMAT. Напомню, что мы будем использовать четыре байта для хранения каждой точки: первый байт - пустой, второй - красный канал, третий - зелёный канал, четвёртый - синий канал. В перечислении D3DFORMAT, этот формат выглядит как D3DFMT_X8R8G8B8.

Перечисление D3DFORMAT хранит не только форматы пикселей основной и фоновой поверхности, но и многие другие форматы: форматы буферов, форматы чисел с плавающей точкой (вещественные числа) и др.

Вот как выглядит определение структуры:

код на языке c++
typedef struct D3DPRESENT_PARAMETERS {
  UINT BackBufferWidth        // ширина и
  UINT BackBufferHeight;      // высота фонового буфера
  D3DFORMAT BackBufferFormat; // формат пикселей фонового буфера
  UINT BackBufferCount;       // количество фоновых буферов
  D3DMULTISAMPLE_TYPE MultiSampleType;
  DWORD MultiSampleQuality;
  D3DSWAPEFFECT SwapEffect;
  HWND hDeviceWindow;       // описатель окна
  BOOL Windowed;            // оконный режим
  BOOL EnableAutoDepthStencil; 
  D3DFORMAT AutoDepthStencilFormat;
  DWORD Flags;
  UINT FullScreen_RefreshRateInHz;
  UINT PresentationInterval;
} D3DPRESENT_PARAMETERS, *LPD3DPRESENT_PARAMETERS;

А вот как будет выглядеть заполненная структурная переменная типа D3DPRESENT_PARAMETERS:

код на языке c++
D3DPRESENT_PARAMETERS pp;
ZeroMemory(&pp,sizeof(pp));

pp.BackBufferWidth = 400;
pp.BackBufferHeight = 400;
pp.BackBufferFormat = D3DFMT_X8R8G8B8;
pp.BackBufferCount = 1;
pp.MultiSampleType = D3DMULTISAMPLE_NONE;
pp.MultiSampleQuality = 0;
pp.SwapEffect = D3DSWAPEFFECT_DISCARD;
pp.hDeviceWindow = hWnd;
pp.Windowed = true;
pp.EnableAutoDepthStencil = false;
pp.AutoDepthStencilFormat = D3DFMT_UNKNOWN;
pp.Flags = 0;
pp.FullScreen_RefreshRateInHz = 0;
pp.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE;

В данном коде мы заполняем структурную переменную pp, при этом задаём размер основной и фоновой поверхности в 400*400 точек. Назначение большинства полей данной структуры станет понятно позднее.

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

Пока что по поверхностям всё. Надеюсь вы поняли предназначение основной и фоновой поверхности. В скором времени мы научимся заполнять фоновую поверхность данными.

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