Поделиться через


Инициализация Direct3D 11

Сводка

Показано, как преобразовать код инициализации Direct3D 9 в Direct3D 11, включая получение дескрипторов к устройству Direct3D и контексту устройства и настройке цепочки буферов с помощью DXGI. Часть 1 из простого приложения Direct3D 9 в DirectX 11 и универсальная платформа Windows (UWP).

Инициализация устройства Direct3D

В Direct3D 9 мы создали дескриптор на устройстве Direct3D, вызвав IDirect3D9::CreateDevice. Мы начали с получения указателя на интерфейс IDirect3D9, и мы указали ряд параметров для управления конфигурацией устройства Direct3D и цепочкой буферов. Прежде чем делать это, мы назвали GetDeviceCaps , чтобы убедиться, что мы не просили устройство сделать что-то, что он не мог сделать.

Direct3D 9

UINT32 AdapterOrdinal = 0;
D3DDEVTYPE DeviceType = D3DDEVTYPE_HAL;
D3DCAPS9 caps;
m_pD3D->GetDeviceCaps(AdapterOrdinal, DeviceType, &caps); // caps bits

D3DPRESENT_PARAMETERS params;
ZeroMemory(&params, sizeof(D3DPRESENT_PARAMETERS));

// Swap chain parameters:
params.hDeviceWindow = m_hWnd;
params.AutoDepthStencilFormat = D3DFMT_D24X8;
params.BackBufferFormat = D3DFMT_X8R8G8B8;
params.MultiSampleQuality = D3DMULTISAMPLE_NONE;
params.MultiSampleType = D3DMULTISAMPLE_NONE;
params.SwapEffect = D3DSWAPEFFECT_DISCARD;
params.Windowed = true;
params.PresentationInterval = 0;
params.BackBufferCount = 2;
params.BackBufferWidth = 0;
params.BackBufferHeight = 0;
params.EnableAutoDepthStencil = true;
params.Flags = 2;

m_pD3D->CreateDevice(
    0,
    D3DDEVTYPE_HAL,
    m_hWnd,
    64,
    &params,
    &m_pd3dDevice
    );

В Direct3D 11 контекст устройства и графической инфраструктуры считаются отдельными от самого устройства. Инициализация делится на несколько шагов.

Сначала мы создадим устройство. Мы получаем список уровней функций, поддерживаемых устройством, — это сообщает больше всего о том, что нам нужно знать о GPU. Кроме того, нам не нужно создавать интерфейс только для доступа к Direct3D. Вместо этого мы используем основной API D3D11CreateDevice . Это дает нам дескриптор для устройства и непосредственного контекста устройства. Контекст устройства используется для задания состояния конвейера и создания команд отрисовки.

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

Обратите внимание , D3D_FEATURE_LEVEL_9_1 (который соответствует модели шейдера 2.0) является минимальным уровнем, который требуется для поддержки игры в Microsoft Store. (Пакеты Arm вашей игры завершаются ошибкой сертификации, если вы не поддерживаете 9_1.) Если ваша игра также включает путь отрисовки для функций модели 3 шейдера, то в массив следует включить D3D_FEATURE_LEVEL_9_3.

 

Direct3D 11

// This flag adds support for surfaces with a different color channel 
// ordering than the API default. It is required for compatibility with
// Direct2D.
UINT creationFlags = D3D11_CREATE_DEVICE_BGRA_SUPPORT;

#if defined(_DEBUG)
// If the project is in a debug build, enable debugging via SDK Layers.
creationFlags |= D3D11_CREATE_DEVICE_DEBUG;
#endif

// This example only uses feature level 9.1.
D3D_FEATURE_LEVEL featureLevels[] = 
{
    D3D_FEATURE_LEVEL_9_1
};

// Create the Direct3D 11 API device object and a corresponding context.
ComPtr<ID3D11Device> device;
ComPtr<ID3D11DeviceContext> context;
D3D11CreateDevice(
    nullptr, // Specify nullptr to use the default adapter.
    D3D_DRIVER_TYPE_HARDWARE,
    nullptr,
    creationFlags,
    featureLevels,
    ARRAYSIZE(featureLevels),
    D3D11_SDK_VERSION, // UWP apps must set this to D3D11_SDK_VERSION.
    &device, // Returns the Direct3D device created.
    nullptr,
    &context // Returns the device immediate context.
    );

// Store pointers to the Direct3D 11.2 API device and immediate context.
device.As(&m_d3dDevice);

context.As(&m_d3dContext);

Создание цепочки буферов

Direct3D 11 включает API устройств с именем инфраструктуры графики DirectX (DXGI). Интерфейс DXGI позволяет (например) управлять настройкой цепочки буферов и настройкой общих устройств. На этом шаге при инициализации Direct3D мы будем использовать DXGI для создания цепочки буферов. Так как мы создали устройство, мы можем следовать цепочке интерфейсов обратно к адаптеру DXGI.

Устройство Direct3D реализует COM-интерфейс для DXGI. Сначала необходимо получить этот интерфейс и использовать его для запроса адаптера DXGI, на котором размещено устройство. Затем мы используем адаптер DXGI для создания фабрики DXGI.

Обратите внимание , что это COM-интерфейсы, поэтому первый ответ может использоваться queryInterface. Вместо этого следует использовать смарт-указатели Microsoft::WRL::ComPtr. Затем просто вызовите метод As(), указав пустой указатель COM правильного типа интерфейса.

 

Direct3D 11

ComPtr<IDXGIDevice2> dxgiDevice;
m_d3dDevice.As(&dxgiDevice);

// Then, the adapter hosting the device;
ComPtr<IDXGIAdapter> dxgiAdapter;
dxgiDevice->GetAdapter(&dxgiAdapter);

// Then, the factory that created the adapter interface:
ComPtr<IDXGIFactory2> dxgiFactory;
dxgiAdapter->GetParent(
    __uuidof(IDXGIFactory2),
    &dxgiFactory
    );

Теперь, когда у нас есть фабрика DXGI, мы можем использовать ее для создания цепочки буферов. Определим параметры цепочки буферов. Нам нужно указать формат поверхности; Мы будем выбирать DXGI_FORMAT_B8G8R8A8_UNORM , так как он совместим с Direct2D. Мы отключим масштабирование отображения, многосамплинг и стереорисовку, так как они не используются в этом примере. Так как мы запущены непосредственно в CoreWindow, мы можем оставить ширину и высоту 0 и автоматически получать полноэкранные значения.

Обратите внимание, что параметр SDKVersion установлен для D3D11_SDK_VERSION для приложений UWP.

 

Direct3D 11

ComPtr<IDXGISwapChain1> swapChain;
dxgiFactory->CreateSwapChainForCoreWindow(
    m_d3dDevice.Get(),
    reinterpret_cast<IUnknown*>(window),
    &swapChainDesc,
    nullptr,
    &swapChain
    );
swapChain.As(&m_swapChain);

Чтобы не отображаться чаще, чем на экране, мы устанавливаем задержку кадров на 1 и используем DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL. Это экономит мощность и является требованием сертификации хранилища; Дополнительные сведения о презентации на экране см. в части 2 этого пошагового руководства.

Примечание. Вы можете использовать многопоточность (например, рабочие элементы ThreadPool ) для продолжения другой работы во время блокировки потока отрисовки.

 

Direct3D 11

dxgiDevice->SetMaximumFrameLatency(1);

Теперь можно настроить буфер резервной копии для отрисовки.

Настройка обратного буфера в качестве целевого объекта отрисовки

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

Direct3D 11

ComPtr<ID3D11Texture2D> backBuffer;
m_swapChain->GetBuffer(
    0,
    __uuidof(ID3D11Texture2D),
    &backBuffer
    );

// Create a render target view on the back buffer.
m_d3dDevice->CreateRenderTargetView(
    backBuffer.Get(),
    nullptr,
    &m_renderTargetView
    );

Теперь контекст устройства вступает в игру. Мы сообщаем Direct3D использовать только что созданное представление целевого представления отрисовки с помощью интерфейса контекста устройства. Мы получим ширину и высоту заднего буфера, чтобы мы могли нацелить весь окно в качестве окна просмотра. Обратите внимание, что задний буфер подключен к цепочке буферов, поэтому если размер окна изменяется (например, пользователь перетаскивает окно игры в другой монитор), необходимо изменить размер обратного буфера, а некоторые параметры потребуется повторно изменить.

Direct3D 11

D3D11_TEXTURE2D_DESC backBufferDesc = {0};
backBuffer->GetDesc(&backBufferDesc);

CD3D11_VIEWPORT viewport(
    0.0f,
    0.0f,
    static_cast<float>(backBufferDesc.Width),
    static_cast<float>(backBufferDesc.Height)
    );

m_d3dContext->RSSetViewports(1, &viewport);

Теперь, когда у нас есть дескриптор устройства и цель полноэкранной отрисовки, мы готовы загрузить и нарисовать геометрию. Перейдите к части 2. Отрисовка.