Seite 1 von 1

[D3D10] DXGI_ERROR_DEVICE_REMOVED

Verfasst: 02.06.2009, 09:19
von AlinghiFan
Einen wunderschönenen guten Morgen

Ich habe hier an der Uni einen Windows 7 RC Rechner stehen und wollte mal ein bischen mit DirectX 10 (Direct3D10) rumspielen und habe mich mal durch die Samples im SDK geschlagen. Ich wollte es einfach angehen und erstellte ein Fenster das man mittels alt+enter zwischen Vollbild- und Fenstermodus umschalten konnte. DXGI sollte das ja übernehmen. Ich habe die WM_SIZE Nachricht abgefangen und ResizeBuffers aufgerufen. Doch immer wenn ich aus dem Vollbild- in den Fenstermodus
zurückgewechselt bin, ist die Anwendung so nach c.a. 10 Sekunden mit folgender Fehlermeldung abgestürzt: DXGI_ERROR_DEVICE_REMOVED! Tja, früher unter Direct3D 9 musste ich ja noch vor einem Reset alle Default Ressourcen freigeben doch das müsste unter D3D10 ja nicht mehr notwendig sein. Jetzt bin ich mir nicht sicher ob ich ein Fehler in meinem Programm habe oder aber ob es einfach noch an dem RC Status von Windows 7 liegt. Ich hoffe ihr könnt mir weiterhelfen.

Vielen Dank schon mal im Voraus

Code: Alles auswählen

//-----------------------------------------------------------------------------
// D3D10Tutorial.cpp
//
// Erstellt ein einfaches Fenster das mittels alt+enter zwischen Vollbild-
// und Fenstermodus umgeschaltet werden kann.
//-----------------------------------------------------------------------------

#include <windows.h>
#include <strsafe.h>
#include <dxerr.h>
#include <d3d10.h>
#include <d3dx10.h>

#pragma comment(lib, "dxerr.lib")
#pragma comment(lib, "d3d10.lib")
#pragma comment(lib, "d3dx10.lib")

//-----------------------------------------------------------------------------
// Makros und Konstanten.
//-----------------------------------------------------------------------------

#define SAVERELEASE(p) if (p) {p->Release(); p = NULL;}
#define MSG_SIZE 512

//-----------------------------------------------------------------------------
// Globale Variablen.
//-----------------------------------------------------------------------------

wchar_t g_errorMsg[MSG_SIZE];
bool g_bFailed = false;
HWND g_hWnd = NULL;
UINT g_width = 800;
UINT g_height = 600;
ID3D10Device* g_pD3DDevice = NULL;
IDXGISwapChain* g_pDXGISwapChain = NULL;
ID3D10RenderTargetView* g_pD3DRenderTV = NULL;
ID3DX10Font* g_pD3DFont = NULL;

//-----------------------------------------------------------------------------
// Forwärtsdeklarationen.
//-----------------------------------------------------------------------------

LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
void Error(const wchar_t *pMsg, HRESULT hr, bool bWin32Error);
bool InitWindow(HINSTANCE hInstance);
bool InitD3D10();
bool InitResources();
bool AdjustSwapChain();
bool CreateRenderTargetView();
bool Render();
void Cleanup();

//-----------------------------------------------------------------------------
// Der Haupteinsteigspunkt initialisiert und startet die Anwendung.
//-----------------------------------------------------------------------------

int WINAPI wWinMain(HINSTANCE hInstance, 
                    HINSTANCE hPrevInstance, 
                    LPWSTR lpCmdLine, 
                    int nShowCmd)
{
    if (InitWindow(hInstance) && InitD3D10() && InitResources())
    {
        ShowWindow(g_hWnd, nShowCmd);

        MSG msg;
        ZeroMemory(&msg, sizeof(msg));

        while (WM_QUIT != msg.message)
        {
            if (PeekMessage(&msg, NULL, 0U, 0U, PM_REMOVE))
            {
                TranslateMessage(&msg);
                DispatchMessage(&msg);
            }
            else
            {
                if (!Render())
                    DestroyWindow(g_hWnd);
            }
        }
    }

    Cleanup();

    if (g_bFailed)
        MessageBox(NULL, g_errorMsg, L"Failed", MB_ICONERROR);

    return 0;
}

//-----------------------------------------------------------------------------
// Verarbeitet Windows Nachrichten.
//-----------------------------------------------------------------------------

LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
    if (WM_DESTROY == msg)    
        PostQuitMessage(0);

    else if (WM_KEYDOWN == msg && VK_ESCAPE == wParam)
        SendMessage(g_hWnd, WM_CLOSE, 0, 0);
    
    else if (WM_SIZE == msg)
    {
        if (!AdjustSwapChain())
            DestroyWindow(g_hWnd);
    }

    return DefWindowProc(hWnd, msg, wParam, lParam);
}

//-----------------------------------------------------------------------------
// Formatiert eine Fehlermeldung und zeigt eine genaue Beschreibung des
// aufgetretenen Fehlers.
//
// Parameter pMsg
// Die Fehlermeldung (Normalerweise der Name der aufgerufenen Funktion).
//
// Parameter hr
// Der Fehlercode.
//
// bWin32Error
// Wenn gesetzt, wird der HRESULT Parameter ignoriert und mittels GetLastError
// die letzte Fehlermeldung von Windows verwendet.
//-----------------------------------------------------------------------------

void Error(const wchar_t *pMsg, HRESULT hr, bool bWin32Error = false)
{
    if (bWin32Error)
    {
        DWORD dwError = GetLastError();
        hr = HRESULT_FROM_WIN32(static_cast<unsigned long>(dwError));
    }

    g_bFailed = true;

    StringCbPrintf(
        g_errorMsg, 
        MSG_SIZE, 
        L"%s\n\nHRESULT = %s\n\n%s",
        pMsg,
        DXGetErrorString(hr),
        DXGetErrorDescription(hr));
}

//-----------------------------------------------------------------------------
// Initialisiert und erstellt ein Fenster.
//-----------------------------------------------------------------------------

bool InitWindow(HINSTANCE hInstance)
{
    WNDCLASSEX wcex;

    wcex.cbClsExtra = 0;
    wcex.cbSize = sizeof(wcex);
    wcex.cbWndExtra = 0;
    wcex.hbrBackground = static_cast<HBRUSH>(GetStockObject(BLACK_BRUSH));
    wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
    wcex.hIcon = NULL;
    wcex.hIconSm = NULL;
    wcex.hInstance = hInstance;
    wcex.lpfnWndProc = WndProc;
    wcex.lpszClassName = L"D3D10Tutorial";
    wcex.lpszMenuName = NULL;
    wcex.style = CS_VREDRAW | CS_HREDRAW;

    if (!RegisterClassEx(&wcex))
    {
        Error(L"RegisterClassEx", NULL, true);
        return false;
    }

    RECT rect = { 0, 0, g_width, g_height };
    AdjustWindowRect(&rect, WS_OVERLAPPEDWINDOW, FALSE);

    g_hWnd = CreateWindow(
        L"D3D10Tutorial", 
        L"D3D10 Tutorial", 
        WS_OVERLAPPEDWINDOW, 
        CW_USEDEFAULT, 
        CW_USEDEFAULT, 
        rect.right - rect.left, 
        rect.bottom - rect.top, 
        NULL, NULL, 
        hInstance,
        NULL);

    if (NULL == g_hWnd)
    {
        Error(L"CreateWindow", NULL, true);
        return false;
    }

    return true;
}

//-----------------------------------------------------------------------------
// Erstellt das Device und ein SwapChain.
//-----------------------------------------------------------------------------

bool InitD3D10()
{
    DXGI_SWAP_CHAIN_DESC sd;
    ZeroMemory(&sd, sizeof(sd));

    sd.BufferCount = 1;
    sd.BufferDesc.Width = g_width;
    sd.BufferDesc.Height = g_height;
    sd.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
    sd.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
    sd.OutputWindow = g_hWnd;
    sd.SampleDesc.Count = 1;
    sd.SampleDesc.Quality = 0;
    sd.Windowed = TRUE;
    sd.BufferDesc.RefreshRate.Numerator = 60;
    sd.BufferDesc.RefreshRate.Denominator = 1;

    HRESULT hr = D3D10CreateDeviceAndSwapChain(
        NULL, 
        D3D10_DRIVER_TYPE_HARDWARE,
        NULL, 
        NULL, 
        D3D10_SDK_VERSION, 
        &sd, 
        &g_pDXGISwapChain, 
        &g_pD3DDevice);

    if (FAILED(hr))
    {
        Error(L"D3D10CreateDeviceAndSwapChain", hr);
        return false;
    }

    return true;
}

//-----------------------------------------------------------------------------
// Erstellt ein Font Objekt.
//-----------------------------------------------------------------------------

bool InitResources()
{
    HRESULT hr = D3DX10CreateFont(
        g_pD3DDevice, 
        16, 
        0, 
        FW_NORMAL, 
        1, 
        FALSE, 
        DEFAULT_CHARSET, 
        OUT_DEFAULT_PRECIS, 
        DEFAULT_QUALITY,
        DEFAULT_PITCH | 
        FF_DONTCARE, 
        L"Arial",
        &g_pD3DFont);

    if (FAILED(hr))
    {
        Error(L"D3DX10CreateFont", hr);
        return false;
    }

    return true;
}

//-----------------------------------------------------------------------------
// Passt die SwapChain Buffer der neuen Fenstergrösse an.
//-----------------------------------------------------------------------------

bool AdjustSwapChain()
{
    RECT rect;
    GetClientRect(g_hWnd, &rect);

    g_width = static_cast<UINT>(rect.right);
    g_height = static_cast<UINT>(rect.bottom);

    SAVERELEASE(g_pD3DRenderTV);

    DXGI_SWAP_CHAIN_DESC sd;
    g_pDXGISwapChain->GetDesc(&sd);

    HRESULT hr = g_pDXGISwapChain->ResizeBuffers(
        sd.BufferCount,
        g_width, 
        g_height, 
        sd.BufferDesc.Format,
        NULL); 

    if (FAILED(hr))
    {
        Error(L"IDXGISwapChain::ResizeBuffers", hr);      
        return false;
    }

    if (!CreateRenderTargetView())
        return false;   

    g_pD3DDevice->OMSetRenderTargets(1, &g_pD3DRenderTV, NULL);

    D3D10_VIEWPORT vp;

    vp.Width = g_width;
    vp.Height = g_height;
    vp.MinDepth = 0.0f;
    vp.MaxDepth = 1.0f;
    vp.TopLeftX = 0;
    vp.TopLeftY = 0;

    g_pD3DDevice->RSSetViewports(1, &vp);

    return true;
}

//-----------------------------------------------------------------------------
// Erstellt einen BackBuffer.
//-----------------------------------------------------------------------------

bool CreateRenderTargetView()
{
    ID3D10Texture2D* pBackBuffer = NULL;

    HRESULT hr = g_pDXGISwapChain->GetBuffer(
        0, 
        __uuidof(ID3D10Texture2D), 
        reinterpret_cast<void**>(&pBackBuffer));
 
    if (FAILED(hr))
    {
        Error(L"IDXGISwapChain::GetBuffer", hr);
        return false;
    }

    hr = g_pD3DDevice->CreateRenderTargetView(
        pBackBuffer, 
        NULL, 
        &g_pD3DRenderTV);
    
    SAVERELEASE(pBackBuffer);

    if (FAILED(hr))
    {
        Error(L"ID3D10Device::CreateRenderTargetView", hr);
        return false;
    }

    return true;
}

//-----------------------------------------------------------------------------
// Rendert die Szene.
//-----------------------------------------------------------------------------

bool Render()
{
    float clearColor[4] = {0.0f, 0.0f, 1.0f, 1.0f};
    D3DXCOLOR fontColor(1.0f, 1.0f, 0.0f, 1.0f);
    RECT rect = {12, 10, g_width - 12, g_height - 10};

    wchar_t text[40];
    StringCbPrintf(text, 40, L"%d x %d", g_width, g_height);

    g_pD3DDevice->ClearRenderTargetView(g_pD3DRenderTV, clearColor);  
    g_pD3DFont->DrawText(NULL, text, -1, &rect, 0, fontColor);    
    
    HRESULT hr = g_pDXGISwapChain->Present(0, 0);

    if (FAILED(hr))
    {
        Error(L"IDXGISwapChain::Present", hr);
        return false;
    }

    return true;
}

//-----------------------------------------------------------------------------
// Räumt alles auf.
//-----------------------------------------------------------------------------

void Cleanup()
{
    if (g_pDXGISwapChain)
        g_pDXGISwapChain->SetFullscreenState(FALSE, 0);

    SAVERELEASE(g_pD3DFont);
    SAVERELEASE(g_pD3DRenderTV);
    SAVERELEASE(g_pDXGISwapChain);
    SAVERELEASE(g_pD3DDevice);
}

Re: [D3D10] DXGI_ERROR_DEVICE_REMOVED

Verfasst: 02.06.2009, 13:47
von Krishty
Hi,

Erzeuge das Device mit aktiviertem Debug-Layer (übergib D3D10CreateDeviceAndSwapChain() D3D10_CREATE_DEVICE_DEBUG), starte das Programm im Debugger (F5) und provoziere die Situation. Dann sollte im Output-Fenster (wo zigfach steht „'foo.exe': 'bar.dll' geladen“) der Grund stehen, warum das Device als removed gemeldet wird :)

P.S.: Sonst gibt es auch noch ID3D10Device::GetDeviceRemovedReason().

Achja, benutz für den Code bitte das Tag {code=c} (mit eckigen Klammern), dann bleibt die Formatierung erhalten (ohne Tabs ist der schwer zu überblicken).

Gruß, Ky

Re: [D3D10] DXGI_ERROR_DEVICE_REMOVED

Verfasst: 02.06.2009, 15:52
von AlinghiFan
Danke für die Anwort.

Den Code habe ich geändert

Code: Alles auswählen

  :oops:

Nun mit dem DEBUG flag kommt die Fehlermeldung:

Removing Device.
D3D10: ERROR: : Device removal has been triggered for the following reason (DXGI_ERROR_DEVICE_HUNG: The Device took an unreasonable amount of time to execute its commands, or the hardware crashed/hung. As a result, the TDR (Timeout Detection and Recovery) mechanism has been triggered. The current Device Context was executing commands when the hang occurred. The application may want to respawn and fallback to less aggressive use of the display hardware). [ EXECUTION ERROR #378: DEVICE_REMOVAL_PROCESS_AT_FAULT ]

Nur, interessanterweise tritt dieser Fehler nur auf, wenn die Visual Styles aktiviert sind (Aero). In der Classic Umgebung funktioniert das Programm wunderbar.
Liegt wohl am RC Status von Windows 7 denke ich.

PS: Ansonsten rennt Windows 7 wunderbar, ich bin positiv überrascht.  :geek: 

Schönen Tag noch

Re: [D3D10] DXGI_ERROR_DEVICE_REMOVED

Verfasst: 02.06.2009, 16:07
von Krishty
Normalerweise passiert das, wenn die GPU überfordert wird …
Wieviele FPS hast du denn im Fenstermodus?

Re: [D3D10] DXGI_ERROR_DEVICE_REMOVED

Verfasst: 02.06.2009, 17:23
von AlinghiFan
Hi

Ich habe einen QueryPerformanceTimer implementiert und siehe da, nach dem Swtich vom Vollbild- in den Fenstermodus bleibt die Framerate so um die 1 bis 0 hängen! Normalerweise steht sie bei 6000! Aber wie gesagt, sobald ich Aero ausschalte, klappt das ganze wunderbar. Ich habe echt keine Ahnung was da schieft läuft :|

Grüsse

Re: [D3D10] DXGI_ERROR_DEVICE_REMOVED

Verfasst: 02.06.2009, 17:44
von Krishty
Wirklich sonderlich, denn dein Code scheint fehlerfrei zu sein (sogar SetFullscreenState() vor der Freigabe, das sieht man selten) … das mit den FPS kommt hin – braucht eine Anweisung länger als drei Sekunden, um vollendet zu werden, bricht der Treiber ab und meldet das als Removed-Device. Ich würde darauf tippen, dass das Font-Rendering buggy ist und unter Win7 irgendwie nicht klarkommt …

… noch etwas zu den 6000 fps: Das ist viel zuviel. Lasse ich hier auf Vista eine Anwendung mehr als zehn Sekunden bei 2000 fps laufen, knickt der Treiber ein. Viele Grafikkarten fangen bei >500fps an zu fiepen. Wir hatten hier auch schon Fälle, in denen bei >2000fps Grafikfehler aufgetreten sind.
Bau, wenn du nicht gerade Performance-Messungen durchführst, am besten eine Bremse ein, die die Framerate bei <100 stabilisiert. Wer weiß, vielleicht hilft das auch mit dem Removed-Device.

Gruß, Ky

Re: [D3D10] DXGI_ERROR_DEVICE_REMOVED

Verfasst: 02.06.2009, 18:03
von AlinghiFan
Hi

Ich habe jetzt mal Vsync aktiviert doch der Fehler bleibt noch immer. Ist wohl wirklich ein Problem von Win7. Tja, benutz ich halt den Classic Modus.

Grüsse

Re: [D3D10] DXGI_ERROR_DEVICE_REMOVED

Verfasst: 02.06.2009, 19:44
von Krishty
Ja, sieht so aus. Hier unter Vista zumindest funktioniert dein Code absturzfrei. Btw: Falls du den „Ping“ beim Umschalten vom Vollbild- in den Fenstermodus loswerden willst, musst du WM_SYSCOMMAND verarbeiten.

Und falls das Fenster minimiert wird, bekommst du 0×0 Pixel als neue Fenstergröße, dann kannst du dir die Swap-Chain auch gleich sparen :)

Re: [D3D10] DXGI_ERROR_DEVICE_REMOVED

Verfasst: 02.06.2009, 22:13
von AlinghiFan
Hi

Hey, dieser Ping hat mich aber sowas von tierisch genervt :mrgreen: Vielen Dank!
Ich werde nun auch noch SIZE_MINIMIZED verarbeiten so dass nur gerendert wird, wenn das Fenster auch wirklich sichtbar ist.

Nun, solange der Code under Vista funktioniert, sollte es dann auch mit dem fertigen Windows 7 klappen.
Ich danke euch allen noch mal und wünsche einen schönen Abend.