Sign in to follow this  
AlinghiFan

D3D10 application crashes after alt+enter

Recommended Posts

Hi all Well after two years of doing nothing with DirectX I finally returned to DirectX 10 just to try it out because i've installed the Windows 7 RC. My idea was to create a window with a font which shows me the resolution. But I have a problem with DXGI alt+enter. Everytime i return from fullscreen, the applications runs for 10 seconds or more and crashes with a Device Removed error! Then, my nvidia driver restarts! So I think there is a problem with IDXGISwapChain::ResizeBuffers() in my code. I hope, you can show me what I'm doing wrong. Thanks a lot
//-----------------------------------------------------------------------------
// D3D10Tutorial.cpp
//
// Creates an emtpy window which can be toggled from windowed to fullscreen
// mode and vice versa by pressing alt+enter.
//-----------------------------------------------------------------------------

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

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

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

//-----------------------------------------------------------------------------
// Globals.
//-----------------------------------------------------------------------------

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;

//-----------------------------------------------------------------------------
// Forward declarations.
//-----------------------------------------------------------------------------

LRESULT CALLBACK WndProc( HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam );
bool InitWindow( HINSTANCE hInstance );
bool InitD3D10();
bool InitResources();
bool CreateRenderTargetView();
void Render();
void Cleanup();

//-----------------------------------------------------------------------------
// The main entry point.
//-----------------------------------------------------------------------------

int WINAPI wWinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, 
                     LPWSTR lpCmdLine, int nShowCmd )
{
    if( !InitWindow( hInstance ) )
    {
        MessageBox( NULL, L"InitWindow()", L"Failed", MB_ICONERROR );
        return 0;
    }

    if( !InitD3D10() )
    {
        Cleanup();
        MessageBox( NULL, L"InitD3D10()", L"Failed", MB_ICONERROR );
        return 0;
    }

    if( !InitResources() )
    {
        Cleanup();
        MessageBox( NULL, L"InitResources()", L"Failed", MB_ICONERROR );
    }

    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
            Render();
    }

    Cleanup();
    return 0;
}

//-----------------------------------------------------------------------------
// Handles windows messages.
//-----------------------------------------------------------------------------

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 )
    {
        RECT rect;
        GetClientRect( g_hWnd, &rect );

        g_width = ( UINT )rect.right;
        g_height = ( 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 ) )
        {
            DestroyWindow( g_hWnd );
            return 0;
        }

        if( !CreateRenderTargetView() )
        {
            DestroyWindow( g_hWnd );
            return 0;
        }

        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 DefWindowProc( hWnd, msg, wParam, lParam );
}

//-----------------------------------------------------------------------------
// Creates the windowclass and the window.
//-----------------------------------------------------------------------------

bool InitWindow( HINSTANCE hInstance)
{
    WNDCLASSEX wcex;

    wcex.cbClsExtra = 0;
    wcex.cbSize = sizeof( wcex );
    wcex.cbWndExtra = 0;
    wcex.hbrBackground = ( 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 ) )
        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 );

    return ( g_hWnd ) ? true : false;
}

//-----------------------------------------------------------------------------
// Creates the device and 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 );

    return ( SUCCEEDED( hr ) ) ? true : false;
}

//-----------------------------------------------------------------------------
// Creates the font.
//-----------------------------------------------------------------------------

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 );

    return ( SUCCEEDED( hr ) ) ? true : false;
}

//-----------------------------------------------------------------------------
// Creates the backbuffer.
//-----------------------------------------------------------------------------

bool CreateRenderTargetView()
{
    ID3D10Texture2D* pBackBuffer = NULL;

    HRESULT hr = g_pDXGISwapChain->GetBuffer( 
        0, 
        __uuidof( ID3D10Texture2D ), 
        ( void** )( &pBackBuffer ) );
 
    if( FAILED( hr ) )
        return false;

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

    if( FAILED( hr ) )
        return false;

    return true;
}

//-----------------------------------------------------------------------------
// Renders the frame.
//-----------------------------------------------------------------------------

void 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 text[50];
    StringCbPrintf( text, 50, 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 ) )
        DestroyWindow( g_hWnd );
}

//-----------------------------------------------------------------------------
// Cleans everything up.
//-----------------------------------------------------------------------------

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

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


Share this post


Link to post
Share on other sites
I never remember the exact way to handle these events and tend to rely on DXUT's implementation to do it properly.

Not that i'm suggesting you adopt DXUT, just that you can use it as a point of reference. Run up one of the SDK samples and double-check it works okay there (Win7+drivers still being pre-release) and then step through the code to figure out how it handles the various windows events and interacts with D3D/DXGI.


hth
Jack

Share this post


Link to post
Share on other sites
I think DXGI was about 50% of the work getting my engine running.
It is one heck of a pian in the butt. It is supposed to make things easier, but in fact makes things 10x harder. DXUT can take you a month to even begin to figure out what they are doing with all that poorly written code mixed with DX9 handling.

Anyway:

1) I found the November SDK consistantly crashes the Nvidia driver, so make sure you got the March or later.

2) Make sure you release _everything_ that came from the swap chain. Including depth buffer, viewport, rendertarget, etc.

3) Recreate them all when a resize comes along. Make sure your resize doesn't cause another size message and recursive resizes. I used a boolean flag to tell me if I was in the middle of resizing.

4) Figure out the nuiances of the messages that get sent as a result of DXGI and in what order. I did this, but never wrote it down (foolish). All I can say is I remember a few nuiances came from using DXGI.

5) It is easier and more bug free to start the app in windowed mode and then tell it to switch to fullscreen programatically.

6) Make certain you are setting the swap chain _exactly_ according to enumerations obtained from the device. 60hz refresh rate is no longer sufficient when it isn't exactly 60hz. You will find the numerator and denominator may vary by as much as a 1000th and make a difference now.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this