2016-12-15 4 views
1

Я изучаю DirectX, следуя некоторым учебным пособиям, но каждый раз, когда я что-то вводил, DirectX не работает. Вот пример последней ошибки, что я не могу исправить после нескольких часов исследования:Отладка DirectX-кода

 //Header.h 
    static HWND hWnd; 
    static IDXGISwapChain* swapChain; 
    static ID3D11Device* dev; 
    static ID3D11DeviceContext* devCon; 
    static ID3D11RenderTargetView* renderTarget; 

    //DirectX.cpp 
    bool InitD3D11(HINSTANCE hInst) 
{ 
    HRESULT hr; 
    DXGI_MODE_DESC bufferDesc; 
    ZeroMemory(&bufferDesc, sizeof(DXGI_MODE_DESC)); 
    bufferDesc.Width = 800; 
    bufferDesc.Height = 600; 
    bufferDesc.RefreshRate.Numerator = 60; 
    bufferDesc.RefreshRate.Denominator = 1; 
    bufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; 
    bufferDesc.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED; 
    bufferDesc.Scaling = DXGI_MODE_SCALING_UNSPECIFIED; 

    DXGI_SWAP_CHAIN_DESC swapChainDesc; 
    ZeroMemory(&swapChainDesc, sizeof(DXGI_SWAP_CHAIN_DESC)); 
    swapChainDesc.BufferDesc = bufferDesc; 
    swapChainDesc.SampleDesc.Count = 1; 
    swapChainDesc.SampleDesc.Quality = 0; 
    swapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; 
    swapChainDesc.BufferCount = 1; 
    swapChainDesc.OutputWindow = hWnd; 
    swapChainDesc.Windowed = true; 
    swapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_DISCARD; 

    hr = D3D11CreateDeviceAndSwapChain(NULL, D3D_DRIVER_TYPE_HARDWARE, NULL, NULL, NULL, NULL, D3D11_SDK_VERSION, &swapChainDesc, &swapChain, &dev, NULL, &devCon); 

    ID3D11Texture2D* backBuffer; 
    hr = swapChain->GetBuffer(0, __uuidof(ID3D11Texture2D), (void**)&backBuffer); 
    hr = dev->CreateRenderTargetView(backBuffer, NULL, &renderTarget); 
    backBuffer->Release(); 
    devCon->OMSetRenderTargets(1, &renderTarget, NULL); 
    return true; 
} 
//This is not the full code - I linked directx and lib files and stuff like that. 
//If I copy and paste code from tutorials, everything runs fine 

Всякий раз, когда я называю InitD3d11, я получаю ошибку о том, что swapChain является указателем NULL. Я предполагаю, что bufferDesc и/или swapChainDesc имеют некоторые недопустимые данные, но компилятор не может дать мне подсказки, что несет ответственность за ошибку. Может кто-нибудь, пожалуйста, покажите мне, как отслеживать и исправлять ошибки, подобные этому? Благодарю.

ответ

3

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

Оценка HRESULT значений в программах старой школы C/C++ выполняется либо с помощью макросов FAILED, либо SUCCEEDED.

hr = D3D11CreateDeviceAndSwapChain(/* ... */ *); 
if (FAILED(hr)) 
    return false; 

В большинстве случаев неудачная HRESULT трактуется как «быстро обанкротиться» или фатальной ошибки. Другими словами, программа не может работать, если вызов завершается с ошибкой.

В других случаях может потребоваться специальная обработка случая, чтобы исправить ошибку, используя различные параметры. Подробный пример этого см. В разделе Anatomy of Direct3D 11 Create Device.

В старых образцах Microsoft на основе структуры устаревших DXUT, обработка ошибок была сделана с помощью макросов, как V или V_RETURN который сделал некоторую трассировку или трассировку & фатального выхода.

В современных образцах C++, мы на самом деле использовать помощник DX::ThrowIfFailed, который генерирует исключение ++ C на неудачную HRESULT для fast-fail сценария. Это делает код более обтекаемым и читаемым:

DX::ThrowIfFailed(
    D3D11CreateDeviceAndSwapChain(/* ... */ *) 
); 

Сама функция определяется как:

#include <exception> 

namespace DX 
{ 
    inline void ThrowIfFailed(HRESULT hr) 
    { 
     if (FAILED(hr)) 
     { 
      // Set a breakpoint on this line to catch DirectX API errors 
      throw std::exception(); 
     } 
    } 
} 

Ваша программа должна быть составлена ​​с /EHsc, который уже по умолчанию шаблонах Visual Studio. См. this topic page для более подробной информации.

Из вашего фрагмента кода, приведенного выше, вы следуете за учебником довольно старой школы. Многое изменилось даже для разработки DirectX 11, и большинство из этих старых учебников приведут к путанице. Поскольку вы новичок в DirectX, я рекомендую вам сначала взглянуть на DirectX Tool Kit и tutorials. Затем вы можете вернуться к старым учебным пособиям с лучшим пониманием «современного» Direct3D и иметь возможность извлекать более релевантную информацию из старого материала.

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

DWORD createDeviceFlags = 0; 
#ifdef _DEBUG 
    createDeviceFlags |= D3D11_CREATE_DEVICE_DEBUG; 
#endif 

hr = D3D11CreateDeviceAndSwapChain(
    nullptr, D3D_DRIVER_TYPE_HARDWARE, 
    nullptr, createDeviceFlags, nullptr, 
    0, D3D11_SDK_VERSION, 
    &swapChainDesc, &swapChain, &dev, nullptr, &devCon); 

Вы заметите, я использую C++ 11 nullptr, который поддерживается на Visual C++ 2010 или более поздней версии вместо старой школы NULL. Это потому, что он напечатан. Вы использовали NULL в двух местах в своей версии, где параметр не был на самом деле указателем, это число.

При этом вы получите много отзывов об основных ошибках, которые помогут диагностировать, почему в вашем конкретном случае swapchain не удается создать. Я подозреваю, что это потому, что вы предоставляете некоторые значения, которые имеют смысл только для «эксклюзивного полноэкранного режима», а не для оконного режима (bufferDesc.RefreshRate). Вместо этого попробуйте:

DXGI_SWAP_CHAIN_DESC swapChainDesc = {}; 
swapChainDesc.BufferDesc.Width = 800; 
swapChainDesc.BufferDesc.Height = 600; 
swapChainDesc.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; 
swapChainDesc.SampleDesc.Count = 1; 
swapChainDesc.SampleDesc.Quality = 0; 
swapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; 
swapChainDesc.BufferCount = 1; 
swapChainDesc.OutputWindow = hWnd; 
swapChainDesc.Windowed = TRUE; 
swapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_DISCARD; 

Это работает на VS 2013 или VS 2015, который будет инициализировать структуру 0 с синтаксисом ={};. В старых компиляторах вам нужно будет использовать ZeroMemory, как в предыдущем коде.

Отметьте, что с помощью D3D11_CREATE_DEVICE_DEBUG произойдет сбой в системе, в которой отсутствует устройство для отладки, предназначенное только для разработчиков. Сведения о том, где вы получаете уровень отладочного устройства, различаются в зависимости от используемой вами версии Windows. См. Direct3D SDK Debug Layer Tricks, в нижней части которого есть сводная таблица.

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

static HWND hWnd = nullptr; 
static IDXGISwapChain* swapChain = nullptr; 
static ID3D11Device* dev = nullptr; 
static ID3D11DeviceContext* devCon = nullptr; 
static ID3D11RenderTargetView* renderTarget = nullptr; 

Еще лучше, если вместо того, чтобы использовать сырые указатели для COM-объектов, вы должны использовать C++ смарт-указатель, как Microsoft::WRL::ComPtr. См. this topic page. Наши современные образцы используют его, и он работает для классических настольных приложений Win32, а также для приложений Windows Store, UWP и Xbox One, поскольку это всего лишь шаблон C++.