Устройство DirectX 12 приостановлено сразу после создания
Я получаю странную ошибку при создании очереди команд DirectX 12. Другие приложения DX12 могут успешно запускаться на той же машине.
Мой компьютер использует D3D_FEATURE_LEVEL_11_0
if
блок. Для тестирования использовалась видеокарта NVIDIA GT 740 с драйверами 361,75.
Этот код используется (свернуто):
#include <Windows.h>
#include <d3d12.h>
#include <dxgi1_4.h>
#include <comdef.h>
#include <D3d12sdklayers.h>
#include <string>
#pragma comment(lib,"d3d12.lib")
#pragma comment(lib,"dxgi.lib")
#pragma comment(lib,"d3dcompiler.lib")
using namespace std;
LRESULT WINAPI WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) {
switch (msg)
{
case WM_DESTROY:
PostQuitMessage(0);
return 0;
default:
return DefWindowProc(hwnd, msg, wParam, lParam);
}
}
int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
LPTSTR lpCmdLine, int nCmdShow) {
UNREFERENCED_PARAMETER(hPrevInstance);
UNREFERENCED_PARAMETER(nCmdShow);
UNREFERENCED_PARAMETER(lpCmdLine);
wchar_t* WindowClass = L"Papergate";
WNDCLASSEX wc;
ZeroMemory(&wc, sizeof(WNDCLASSEX));
wc.cbSize = sizeof(WNDCLASSEX);
wc.style = CS_HREDRAW | CS_VREDRAW;
wc.lpfnWndProc = WndProc;
wc.hInstance = hInstance;
wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 2);
wc.lpszClassName = WindowClass;
if (!RegisterClassEx(&wc))
{
return 1;
}
HWND hwnd = CreateWindowEx(NULL, wc.lpszClassName, WindowClass,
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, CW_USEDEFAULT,
CW_USEDEFAULT, CW_USEDEFAULT,
NULL, NULL, hInstance, NULL);
if (!hwnd)
{
UnregisterClass(WindowClass, hInstance);
return 1;
}
ShowWindow(hwnd, SW_SHOWDEFAULT);
UpdateWindow(hwnd);
ID3D12Device* device;
HRESULT result = D3D12CreateDevice(NULL, D3D_FEATURE_LEVEL_12_1,
__uuidof(ID3D12Device), (void**)&device);
if (FAILED(result))
{
result = D3D12CreateDevice(NULL, D3D_FEATURE_LEVEL_12_0,
__uuidof(ID3D12Device), (void**)&device);
if (FAILED(result))
{
result = D3D12CreateDevice(NULL, D3D_FEATURE_LEVEL_11_0,
__uuidof(ID3D12Device), (void**)&device);
if (FAILED(result)) {
_com_error error(result);
MessageBox(hwnd, error.ErrorMessage(),
(wstring(L"Error: ") + to_wstring(__LINE__)).c_str(),
MB_OK);
return 2;
}
}
}
ID3D12Debug* debugInterface;
if (SUCCEEDED(D3D12GetDebugInterface(IID_PPV_ARGS(&debugInterface))))
{
debugInterface->EnableDebugLayer();
}
D3D12_COMMAND_QUEUE_DESC commandQueueDesc;
commandQueueDesc.Flags = D3D12_COMMAND_QUEUE_FLAG_NONE;
commandQueueDesc.NodeMask = 0;
commandQueueDesc.Priority = D3D12_COMMAND_QUEUE_PRIORITY_NORMAL;
commandQueueDesc.Type = D3D12_COMMAND_LIST_TYPE_DIRECT;
ID3D12CommandQueue* commandQueue;
result = device->CreateCommandQueue(&commandQueueDesc, __uuidof(ID3D12CommandQueue), (void**)&commandQueue);
if (FAILED(result)) {
_com_error error(result);
MessageBox(hwnd, error.ErrorMessage(),
(wstring(L"Error: ") + to_wstring(__LINE__)).c_str(), MB_OK);
result = device->GetDeviceRemovedReason();
error = _com_error(result);
MessageBox(hwnd, error.ErrorMessage(),
(wstring(L"Error: ") + to_wstring(__LINE__)).c_str(), MB_OK);
debugInterface->Release(); device->Release(); return 2;
}
MSG msg;
ZeroMemory(&msg, sizeof(MSG));
while (GetMessage(&msg, NULL, 0, 0) && msg.message != WM_QUIT)
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
commandQueue->Release();
device->Release();
UnregisterClass(WindowClass, hInstance);
return 0;
}
Я получаю следующие ошибки в строках 97 и 102 соответственно:
The GPU device instance has been suspended. Use GetDeviceRemovedReason to determine the appropriate action.
Вторая ошибка:
The GPU will not respond to more commands, most likely because some other application submitted invalid commands.
The calling application should re-create the device and continue.
1 ответ
Похоже, что это какая-то ошибка в драйвере. Проверьте, есть ли обновленные драйверы для вашего оборудования. Вам следует попробовать использовать игровые шаблоны Direct3D12 в этой VSIX и посмотреть, сталкиваются ли они с такой же проблемой (более подробную информацию о шаблонах см. В этом сообщении в блоге).
Ваш каскадный образец звонка D3D12CreateDevice
для разных уровней возможностей это необычно и не нужно. Если ваше приложение может работать на Direct3D Feature Level 11.0 или выше, просто используйте D3D_FEATURE_LEVEL_11_0
один раз. Вы должны передать любой минимальный поддерживаемый уровень функции для этой функции.
Если устройство Direct3D 12 поддерживает более высокий уровень функций, вы можете обнаружить это с помощью CheckFeatureSupport, либо проверив отдельные функции, либо используя D3D12_FEATURE_FEATURE_LEVELS
:
// Create the DX12 API device object.
DX::ThrowIfFailed(D3D12CreateDevice(
adapter.Get(),
m_d3dMinFeatureLevel,
IID_PPV_ARGS(&m_d3dDevice)
));
// Determine maximum supported feature level for this device
static const D3D_FEATURE_LEVEL s_featureLevels[] =
{
D3D_FEATURE_LEVEL_12_1,
D3D_FEATURE_LEVEL_12_0,
D3D_FEATURE_LEVEL_11_1,
D3D_FEATURE_LEVEL_11_0,
};
D3D12_FEATURE_DATA_FEATURE_LEVELS featLevels =
{
_countof(s_featureLevels), s_featureLevels, D3D_FEATURE_LEVEL_11_0
};
HRESULT hr = m_d3dDevice->CheckFeatureSupport(D3D12_FEATURE_FEATURE_LEVELS,
&featLevels, sizeof(featLevels));
if (SUCCEEDED(hr))
{
m_d3dFeatureLevel = featLevels.MaxSupportedFeatureLevel;
}
else
{
m_d3dFeatureLevel = m_d3dMinFeatureLevel;
}
Имейте в виду, что D3D_FEATURE_LEVEL_12_0
а также D3D_FEATURE_LEVEL_12_1
по сути просто D3D_FEATURE_LEVEL_11_1
с несколькими дополнительными функциями, сделанными обязательными. Если ваше приложение уже проверяет их на 11.x, то нет причин "требовать" 12.0 или 12.1. Смотрите MSDN.
Для подавляющего большинства игр и приложений Direct3D 12 D3D_FEATURE_LEVEL_11_0
или же D3D_FEATURE_LEVEL_11_1
хороший выбор. Имейте в виду, что, хотя AMD/ATI довольно рано поддерживали Feature Level 11.1, части NVIDIA DirectX 11 поддерживали только 11.0 с некоторыми дополнительными функциями в течение некоторого времени.