Verständnisprobleme der DirectX 11 API

Für Fragen zu Grafik APIs wie DirectX und OpenGL sowie Shaderprogrammierung.
Antworten
David Glauser
Beiträge: 2
Registriert: 17.02.2011, 12:17
Echter Name: David Glauser

Verständnisprobleme der DirectX 11 API

Beitrag von David Glauser »

Hallo zusammen.

Da ich schon immer mal wissen wollte, wie ein Computerspiel funktioniert, habe ich mich entschlossen, ein simples Spiel zu programmieren. Dazu muss gesagt werden, dass meine Programmierkenntnisse doch eher bescheiden ausfallen.
Für mein Spiel verwende ich C++ und die DirectX 11 Api. Mein Programm funktioniert soweit auch ganz gut, nun wollte ich noch einen Vollbildmodus einbauen. Dazu habe ich mich auf folgende Informationen bezogen:

DirectX Graphics Infrastructure (DXGI): Best Practices
http://msdn.microsoft.com/en-us/library ... s.85).aspx

Nur leider bekomme ich eine "DXGI Warning: IDXGISwapChain::Present: Fullscreen presentation inefficiencies incurred..." Warnung sobald ich nach Alt+Enter die IDXGISwapChain::Present Methode aufrufe. Ich glaube zu Wissen, woran es liegen könnte doch das würde der API-Dokumentation widersprechen. Folgendes Problem besteht: Ich verwende das DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH Flag und möchte im Fenster sowie im Vollbildmodus die selbe Auflösung verwenden. Wenn nun DXGI intern die IDXGISwapChain::SetFullscreenState Methode aufruft, wird keine WM_SIZE Nachricht ausgelöst da ja keine Fensterklientgrössenmanipulation vorgenommen werden muss. Es wird also KEINE WM_SIZE Nachricht gesendet. Somit wird auch die IDXGISwapChain::ResizeBuffers Methode nicht ausgeführt. Soweit so logisch. Nur, irgendwie scheint DXGI nicht zu merken, dass die Fensterklientgrösse sowie die Swapchainbuffergrösse übereinstimmen.

Tja, die Lösung wäre, direkt nach der SetFullscreenState die ResizeBuffers Methode selber aufzurufen. Aber dies wäre nur möglich, wenn ich eine eigene Alt+Enter Implementation verwenden würde. Da kann doch was nicht stimmen oder?
Ich habe zu Testzwecken eine simple Anwendung erstellt, die keinerlei Fehlerabfragen verwendet, um mein Problem zu schildern.

Update:
Habe soeben noch festgestellt, dass die WM_SIZE manchmal gesendet wird, auch wenn die beiden Grössen übereinstimmen!

Code: Alles auswählen

#define WIN32_LEAN_AND_MEAN

#include <Windows.h>
#include <DXGI.h>
#include <D3D11.h>

#pragma comment(lib, "DXGI.lib")
#pragma comment(lib, "D3D11.lib")

/////////////////////////////////////////////////////////////////////////////////////////

class Application
{
public:
    static void Execute(HINSTANCE instanceHandle);

private:
    Application();
    ~Application();
    void Initialize(HINSTANCE instanceHandle);
    void MessageLoop();
    void HandleClientSizeChange();
    void HandleSizeMessage(WPARAM wordParameter);
    void HandleKeydownMessage(WPARAM wordParameter);
    static LRESULT CALLBACK WindowProcedure(HWND windowHandle, UINT message, WPARAM wordParameter, LPARAM longParameter);
	
private:
    HWND mWindowHandle;
    IDXGIFactory1 *mFactory;
    IDXGIAdapter1 *mAdapter;
    IDXGIOutput* mOutput;
    IDXGISwapChain* mSwapChain;
    ID3D11Device* mRenderDevice;
    ID3D11DeviceContext* mRenderContext;
    ID3D11RenderTargetView* mRenderTargetView;
    bool mWindowMinimized;
    bool mIgnoreSizeMessage;
};

/////////////////////////////////////////////////////////////////////////////////////////

int WINAPI WinMain(HINSTANCE instanceHandle, HINSTANCE, char*, int)
{
    Application::Execute(instanceHandle);
    return 0;
}

/////////////////////////////////////////////////////////////////////////////////////////

void Application::Execute(HINSTANCE instanceHandle)
{
    Application application;
    application.Initialize(instanceHandle);
    application.MessageLoop();
}

/////////////////////////////////////////////////////////////////////////////////////////

Application::Application() :
    mWindowHandle(NULL),
    mFactory(NULL),
    mAdapter(NULL),
    mOutput(NULL),
    mSwapChain(NULL),
    mRenderDevice(NULL),
    mRenderContext(NULL),
    mRenderTargetView(NULL),
    mWindowMinimized(false),
    mIgnoreSizeMessage(false)
{
}

/////////////////////////////////////////////////////////////////////////////////////////

Application::~Application()
{
    BOOL fullscreenState;
    mSwapChain->GetFullscreenState(&fullscreenState, NULL);

    if (fullscreenState)
    {
        mIgnoreSizeMessage = true;
        mSwapChain->SetFullscreenState(FALSE, NULL);
    }

    mRenderTargetView->Release();
    mSwapChain->Release();
    mRenderDevice->Release();
    mRenderContext->Release();
    mOutput->Release();
    mAdapter->Release();
    mFactory->Release();
}

/////////////////////////////////////////////////////////////////////////////////////////

void Application::Initialize(HINSTANCE instanceHandle)
{
    ::CreateDXGIFactory1(__uuidof(IDXGIFactory1), reinterpret_cast<void**>(&mFactory));

    mFactory->EnumAdapters1(0, &mAdapter);
    mAdapter->EnumOutputs(0, &mOutput);

    ::D3D11CreateDevice(
        mAdapter,
        D3D_DRIVER_TYPE_UNKNOWN,
        NULL,
        0,
        NULL,
        0,
        D3D11_SDK_VERSION,
        &mRenderDevice,
        NULL,
        &mRenderContext);

    DXGI_MODE_DESC modeToMatch;
    modeToMatch.Width = 800;
    modeToMatch.Height = 600;
    modeToMatch.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
    modeToMatch.RefreshRate.Numerator = 0;
    modeToMatch.RefreshRate.Denominator = 0;
    modeToMatch.Scaling = DXGI_MODE_SCALING_UNSPECIFIED;
    modeToMatch.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED;

    DXGI_MODE_DESC closestMatch;
    mOutput->FindClosestMatchingMode(&modeToMatch, &closestMatch, mRenderDevice);

    WNDCLASSEX windowClass;
    windowClass.cbSize = sizeof(windowClass);
    windowClass.cbClsExtra = 0;
    windowClass.cbWndExtra = 0;
    windowClass.hbrBackground = reinterpret_cast<HBRUSH>(::GetStockObject(BLACK_BRUSH));
    windowClass.hCursor = ::LoadCursorW(NULL, IDC_ARROW);
    windowClass.hIcon = ::LoadIconW(NULL, IDI_APPLICATION);
    windowClass.hIconSm = windowClass.hIcon;
    windowClass.hInstance = instanceHandle;
    windowClass.lpfnWndProc = &WindowProcedure;
    windowClass.lpszClassName = L"Application";
    windowClass.lpszMenuName = NULL;
    windowClass.style = CS_DBLCLKS;

    ::RegisterClassExW(&windowClass);

    DWORD extendedWindowStyle = WS_EX_APPWINDOW | WS_EX_WINDOWEDGE; 
    DWORD windowStyle = WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU;

    RECT windowRectangle;
    windowRectangle.left = 0;
    windowRectangle.top = 0;
    windowRectangle.right = static_cast<LONG>(closestMatch.Width);
    windowRectangle.bottom = static_cast<LONG>(closestMatch.Height);

    ::AdjustWindowRectEx(&windowRectangle, windowStyle, FALSE, extendedWindowStyle);

    int windowWidth = static_cast<int>(windowRectangle.right - windowRectangle.left);
    int windowHeight = static_cast<int>(windowRectangle.bottom - windowRectangle.top);
    int windowPositionX = static_cast<int>((::GetSystemMetrics(SM_CXSCREEN) - windowWidth) / 2);
    int windowPositionY = static_cast<int>((::GetSystemMetrics(SM_CYSCREEN) - windowHeight) / 2);

    mWindowHandle = ::CreateWindowExW(
        extendedWindowStyle,
        L"Application",
        L"Fullscreen Test",
        windowStyle,
        windowPositionX,
        windowPositionY,
        windowWidth,
        windowHeight,
        NULL,
        NULL,
        instanceHandle,
        this);

    ::ShowWindow(mWindowHandle, SW_SHOWNORMAL);
    ::SetForegroundWindow(mWindowHandle);

    DXGI_SWAP_CHAIN_DESC swapChainDescription;
    swapChainDescription.BufferCount = 1;
    swapChainDescription.BufferDesc = closestMatch;
    swapChainDescription.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
    swapChainDescription.Flags = DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH;
    swapChainDescription.OutputWindow = mWindowHandle;
    swapChainDescription.SampleDesc.Count = 1;
    swapChainDescription.SampleDesc.Quality = 0;
    swapChainDescription.SwapEffect = DXGI_SWAP_EFFECT_DISCARD;
    swapChainDescription.Windowed = TRUE;

    mFactory->CreateSwapChain(mRenderDevice, &swapChainDescription, &mSwapChain);

    ID3D11Texture2D* renderTargetBuffer;

    mSwapChain->GetBuffer(0, __uuidof(ID3D11Texture2D), reinterpret_cast<void**>(&renderTargetBuffer));	
    mRenderDevice->CreateRenderTargetView(renderTargetBuffer, NULL, &mRenderTargetView);
    mRenderContext->OMSetRenderTargets(1, &mRenderTargetView, NULL);

    renderTargetBuffer->Release();
}

/////////////////////////////////////////////////////////////////////////////////////////

void Application::MessageLoop()
{
    bool renderTargetReady = true;

    MSG message;
    FLOAT clearColor[4] = {0.0f, 0.125f, 0.3f, 1.0f};

    while (true)
    {
        if (::PeekMessageW(&message, NULL, 0, 0, PM_REMOVE))
        {
            if (message.message == WM_QUIT)
                break;

            ::TranslateMessage(&message);
            ::DispatchMessageW(&message);
        }
        else if (!mWindowMinimized)
        {
            if (renderTargetReady)			
                mRenderContext->ClearRenderTargetView(mRenderTargetView, clearColor);

            switch (mSwapChain->Present(1, renderTargetReady ? 0 : DXGI_PRESENT_TEST))
            {
            case S_OK:
                renderTargetReady = true;
                break;

            case DXGI_STATUS_OCCLUDED:
                renderTargetReady = false;
                break;
            }
        }
    }
}

/////////////////////////////////////////////////////////////////////////////////////////

void Application::HandleClientSizeChange()
{
    mRenderContext->OMSetRenderTargets(0, NULL, NULL);
    mRenderTargetView->Release();

    RECT clientRectangle;
    ::GetClientRect(mWindowHandle, &clientRectangle); 

    UINT clientWidth = static_cast<UINT>(clientRectangle.right);
    UINT clientHeight = static_cast<UINT>(clientRectangle.bottom);

    DXGI_SWAP_CHAIN_DESC swapChainDescription;
    mSwapChain->GetDesc(&swapChainDescription);

    mSwapChain->ResizeBuffers(
        swapChainDescription.BufferCount,
        clientWidth,
        clientHeight,
        swapChainDescription.BufferDesc.Format,
        swapChainDescription.Flags);

    ID3D11Texture2D* renderTargetBuffer;

    mSwapChain->GetBuffer(0, __uuidof(ID3D11Texture2D), reinterpret_cast<void**>(&renderTargetBuffer));	
    mRenderDevice->CreateRenderTargetView(renderTargetBuffer, NULL, &mRenderTargetView);
    mRenderContext->OMSetRenderTargets(1, &mRenderTargetView, NULL);

    renderTargetBuffer->Release();
}

/////////////////////////////////////////////////////////////////////////////////////////

void Application::HandleSizeMessage(WPARAM wordParameter)
{
    mWindowMinimized = (wordParameter == SIZE_MINIMIZED) ? true : false;

    if (!mSwapChain || mIgnoreSizeMessage)
        return;
    
    ::OutputDebugStringW(L"AUTO::WM_SIZE\n");
    HandleClientSizeChange();
}

/////////////////////////////////////////////////////////////////////////////////////////

void Application::HandleKeydownMessage(WPARAM wordParameter)
{
    if (wordParameter == VK_ESCAPE)
    {
        ::DestroyWindow(mWindowHandle);
        return;
    }

    if (!mSwapChain)
        return;

    BOOL fullscreenState;
    mSwapChain->GetFullscreenState(&fullscreenState, NULL);

    if (fullscreenState && wordParameter == VK_DOWN)
    {
        mIgnoreSizeMessage = true;
        mSwapChain->SetFullscreenState(FALSE, NULL);
        mIgnoreSizeMessage = false;

        ::OutputDebugStringW(L"MANUAL::WM_SIZE\n");
        HandleClientSizeChange();
    }
    else if (!fullscreenState && wordParameter == VK_UP)
    {
        mIgnoreSizeMessage = true;
        mSwapChain->SetFullscreenState(TRUE, mOutput);
        mIgnoreSizeMessage = false;

        ::OutputDebugStringW(L"MANUAL::WM_SIZE\n");
        HandleClientSizeChange();
    }
}

/////////////////////////////////////////////////////////////////////////////////////////

LRESULT CALLBACK Application::WindowProcedure(HWND windowHandle, UINT message, WPARAM wordParameter, LPARAM longParameter)
{
    if (message == WM_NCCREATE)
    {       
        Application* application = reinterpret_cast<Application*>(
            reinterpret_cast<LPCREATESTRUCT>(longParameter)->lpCreateParams);

        ::SetWindowLongPtrW(windowHandle, GWLP_USERDATA, reinterpret_cast<LONG_PTR>(application));
    }
    else
    {    
        Application* application = reinterpret_cast<Application*>(
            ::GetWindowLongPtrW(windowHandle, GWLP_USERDATA));

        switch (message)
        {
        case WM_DESTROY:
            ::PostQuitMessage(0);
            return 0;

        case WM_SIZE:
            application->HandleSizeMessage(wordParameter);
            break;

        case WM_KEYDOWN:
            application->HandleKeydownMessage(wordParameter);
            break;
        }
    }

    return ::DefWindowProcW(windowHandle, message, wordParameter, longParameter);
}
Ich hoffe, ihr könnt mir weiterhelfen.
Besten Dank
Benutzeravatar
Krishty
Establishment
Beiträge: 8350
Registriert: 26.02.2009, 11:18
Benutzertext: state is the enemy
Kontaktdaten:

Re: Verständnisprobleme der DirectX 11 API

Beitrag von Krishty »

msdn hat geschrieben:DXGI set the full-screen resolution to the desktop resolution by default. Many applications, however, switch to a preferred full-screen resolution. In such a case, DXGI provides IDXGISwapChain::ResizeTarget. This should be called before calling SetFullscreenState.
Das könnte es sein – DXGI hat intern immernoch einen Front-Buffer in Desktopauflösung reserviert und soll nun in Fensterauflösung reinrendern. (Der Rest des Abschnitts sieht auch wichtig aus.)

Gruß, Ky
seziert Ace Combat, Driver, und S.T.A.L.K.E.R.   —   rendert Sterne
David Glauser
Beiträge: 2
Registriert: 17.02.2011, 12:17
Echter Name: David Glauser

Re: Verständnisprobleme der DirectX 11 API

Beitrag von David Glauser »

So, mittlerweile habe ich die IDXGISwapChain::ResizeTarget Methode eingebaut und habe endlich keine Fehlermeldungen mehr 8-)

Das ganze sieht nun so aus:

Code: Alles auswählen

#define WIN32_LEAN_AND_MEAN

#include <Windows.h>
#include <DXGI.h>
#include <D3D11.h>

#pragma comment(lib, "DXGI.lib")
#pragma comment(lib, "D3D11.lib")

/////////////////////////////////////////////////////////////////////////////////////////

class Application
{
public:
    static void Execute(HINSTANCE instanceHandle);

private:
    Application();
    ~Application();
    void Initialize(HINSTANCE instanceHandle);
    void MessageLoop();
    void ResizeSwapChainBuffers();
    void SetWindowedState();
    void SetFullscreenState();    
    void HandleSizeMessage(WPARAM wordParameter);
    void HandleKeydownMessage(WPARAM wordParameter);
    static LRESULT CALLBACK WindowProcedure(HWND windowHandle, UINT message, WPARAM wordParameter, LPARAM longParameter);
	
private:
    HWND mWindowHandle;
    IDXGIFactory1 *mFactory;
    IDXGIAdapter1 *mAdapter;
    IDXGIOutput* mOutput;
    IDXGISwapChain* mSwapChain;
    ID3D11Device* mRenderDevice;
    ID3D11DeviceContext* mRenderContext;
    ID3D11RenderTargetView* mRenderTargetView;
    bool mWindowMinimized;
    bool mIgnoreSizeMessage;
};

/////////////////////////////////////////////////////////////////////////////////////////

int WINAPI WinMain(HINSTANCE instanceHandle, HINSTANCE, char*, int)
{
    Application::Execute(instanceHandle);
    return 0;
}

/////////////////////////////////////////////////////////////////////////////////////////

void Application::Execute(HINSTANCE instanceHandle)
{
    Application application;
    application.Initialize(instanceHandle);
    application.MessageLoop();
}

/////////////////////////////////////////////////////////////////////////////////////////

Application::Application() :
    mWindowHandle(NULL),
    mFactory(NULL),
    mAdapter(NULL),
    mOutput(NULL),
    mSwapChain(NULL),
    mRenderDevice(NULL),
    mRenderContext(NULL),
    mRenderTargetView(NULL),
    mWindowMinimized(false),
    mIgnoreSizeMessage(false)
{
}

/////////////////////////////////////////////////////////////////////////////////////////

Application::~Application()
{
    BOOL fullscreenState;
    mSwapChain->GetFullscreenState(&fullscreenState, NULL);

    if (fullscreenState)
    {
        mIgnoreSizeMessage = true;
        mSwapChain->SetFullscreenState(FALSE, NULL);
    }

    mRenderTargetView->Release();
    mSwapChain->Release();
    mRenderDevice->Release();
    mRenderContext->Release();
    mOutput->Release();
    mAdapter->Release();
    mFactory->Release();
}

/////////////////////////////////////////////////////////////////////////////////////////

void Application::Initialize(HINSTANCE instanceHandle)
{
    ::CreateDXGIFactory1(__uuidof(IDXGIFactory1), reinterpret_cast<void**>(&mFactory));

    mFactory->EnumAdapters1(0, &mAdapter);
    mAdapter->EnumOutputs(0, &mOutput);

    ::D3D11CreateDevice(
        mAdapter,
        D3D_DRIVER_TYPE_UNKNOWN,
        NULL,
        0,
        NULL,
        0,
        D3D11_SDK_VERSION,
        &mRenderDevice,
        NULL,
        &mRenderContext);

    WNDCLASSEX windowClass;
    windowClass.cbSize = sizeof(windowClass);
    windowClass.cbClsExtra = 0;
    windowClass.cbWndExtra = 0;
    windowClass.hbrBackground = reinterpret_cast<HBRUSH>(::GetStockObject(BLACK_BRUSH));
    windowClass.hCursor = ::LoadCursorW(NULL, IDC_ARROW);
    windowClass.hIcon = ::LoadIconW(NULL, IDI_APPLICATION);
    windowClass.hIconSm = windowClass.hIcon;
    windowClass.hInstance = instanceHandle;
    windowClass.lpfnWndProc = &WindowProcedure;
    windowClass.lpszClassName = L"Application";
    windowClass.lpszMenuName = NULL;
    windowClass.style = CS_DBLCLKS;

    ::RegisterClassExW(&windowClass);

    DWORD extendedWindowStyle = WS_EX_APPWINDOW | WS_EX_WINDOWEDGE; 
    DWORD windowStyle = WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU;

    RECT windowRectangle;
    windowRectangle.left = 0;
    windowRectangle.top = 0;
    windowRectangle.right = 1920;
    windowRectangle.bottom = 1080;

    ::AdjustWindowRectEx(&windowRectangle, windowStyle, FALSE, extendedWindowStyle);

    int windowWidth = static_cast<int>(windowRectangle.right - windowRectangle.left);
    int windowHeight = static_cast<int>(windowRectangle.bottom - windowRectangle.top);
    int windowPositionX = static_cast<int>((::GetSystemMetrics(SM_CXSCREEN) - windowWidth) / 2);
    int windowPositionY = static_cast<int>((::GetSystemMetrics(SM_CYSCREEN) - windowHeight) / 2);

    mWindowHandle = ::CreateWindowExW(
        extendedWindowStyle,
        L"Application",
        L"Fullscreen Test",
        windowStyle,
        windowPositionX,
        windowPositionY,
        windowWidth,
        windowHeight,
        NULL,
        NULL,
        instanceHandle,
        this);

    ::ShowWindow(mWindowHandle, SW_SHOWNORMAL);
    ::SetForegroundWindow(mWindowHandle);

    RECT clientRectangle;
    ::GetClientRect(mWindowHandle, &clientRectangle);

    UINT clientWidth = static_cast<UINT>(clientRectangle.right);
    UINT clientHeight = static_cast<UINT>(clientRectangle.bottom);

    DXGI_SWAP_CHAIN_DESC swapChainDescription;
    swapChainDescription.BufferCount = 1;
    swapChainDescription.BufferDesc.Width = clientWidth;
    swapChainDescription.BufferDesc.Height = clientHeight;
    swapChainDescription.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
    swapChainDescription.BufferDesc.RefreshRate.Numerator = 0;
    swapChainDescription.BufferDesc.RefreshRate.Denominator = 0;
    swapChainDescription.BufferDesc.Scaling = DXGI_MODE_SCALING_UNSPECIFIED;
    swapChainDescription.BufferDesc.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED;
    swapChainDescription.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
    swapChainDescription.Flags = DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH;
    swapChainDescription.OutputWindow = mWindowHandle;
    swapChainDescription.SampleDesc.Count = 1;
    swapChainDescription.SampleDesc.Quality = 0;
    swapChainDescription.SwapEffect = DXGI_SWAP_EFFECT_DISCARD;
    swapChainDescription.Windowed = TRUE;

    mFactory->CreateSwapChain(mRenderDevice, &swapChainDescription, &mSwapChain);

    mFactory->MakeWindowAssociation(
        mWindowHandle,
        DXGI_MWA_NO_WINDOW_CHANGES |
        DXGI_MWA_NO_ALT_ENTER |
        DXGI_MWA_NO_PRINT_SCREEN);

    ID3D11Texture2D* renderTargetBuffer;

    mSwapChain->GetBuffer(0, __uuidof(ID3D11Texture2D), reinterpret_cast<void**>(&renderTargetBuffer));	
    mRenderDevice->CreateRenderTargetView(renderTargetBuffer, NULL, &mRenderTargetView);
    mRenderContext->OMSetRenderTargets(1, &mRenderTargetView, NULL);

    renderTargetBuffer->Release();
}

/////////////////////////////////////////////////////////////////////////////////////////

void Application::MessageLoop()
{
    bool renderTargetReady = true;

    MSG message;
    FLOAT clearColor[4] = {0.0f, 0.125f, 0.3f, 1.0f};

    while (true)
    {
        if (::PeekMessageW(&message, NULL, 0, 0, PM_REMOVE))
        {
            if (message.message == WM_QUIT)
                break;

            ::TranslateMessage(&message);
            ::DispatchMessageW(&message);
        }
        else if (!mWindowMinimized)
        {
            if (renderTargetReady)			
                mRenderContext->ClearRenderTargetView(mRenderTargetView, clearColor);

            switch (mSwapChain->Present(1, renderTargetReady ? 0 : DXGI_PRESENT_TEST))
            {
            case S_OK:
                renderTargetReady = true;
                break;

            case DXGI_STATUS_OCCLUDED:
                renderTargetReady = false;
                break;
            }
        }
    }
}

/////////////////////////////////////////////////////////////////////////////////////////

void Application::ResizeSwapChainBuffers()
{
    RECT clientRectangle;
    ::GetClientRect(mWindowHandle, &clientRectangle); 

    UINT clientWidth = static_cast<UINT>(clientRectangle.right);
    UINT clientHeight = static_cast<UINT>(clientRectangle.bottom);

    DXGI_SWAP_CHAIN_DESC swapChainDescription;
    mSwapChain->GetDesc(&swapChainDescription);

    mSwapChain->ResizeBuffers(
        swapChainDescription.BufferCount,
        clientWidth,
        clientHeight,
        swapChainDescription.BufferDesc.Format,
        swapChainDescription.Flags);
}

/////////////////////////////////////////////////////////////////////////////////////////

void Application::SetWindowedState()
{
    mIgnoreSizeMessage = true;

    mRenderContext->OMSetRenderTargets(0, NULL, NULL);
    mRenderTargetView->Release();

    DXGI_SWAP_CHAIN_DESC swapChainDescription;
    mSwapChain->GetDesc(&swapChainDescription);

    mSwapChain->SetFullscreenState(FALSE, NULL);

    mSwapChain->ResizeTarget(&swapChainDescription.BufferDesc);
    ResizeSwapChainBuffers();

    ID3D11Texture2D* renderTargetBuffer;

    mSwapChain->GetBuffer(0, __uuidof(ID3D11Texture2D), reinterpret_cast<void**>(&renderTargetBuffer));	
    mRenderDevice->CreateRenderTargetView(renderTargetBuffer, NULL, &mRenderTargetView);
    mRenderContext->OMSetRenderTargets(1, &mRenderTargetView, NULL);

    renderTargetBuffer->Release();

    mIgnoreSizeMessage = false;
}

/////////////////////////////////////////////////////////////////////////////////////////

void Application::SetFullscreenState()
{
    mIgnoreSizeMessage = true;

    mRenderContext->OMSetRenderTargets(0, NULL, NULL);
    mRenderTargetView->Release();

    DXGI_SWAP_CHAIN_DESC swapChainDescription;
    mSwapChain->GetDesc(&swapChainDescription);

    DXGI_MODE_DESC closestMatch;
    mOutput->FindClosestMatchingMode(&swapChainDescription.BufferDesc, &closestMatch, mRenderDevice);

    mSwapChain->ResizeTarget(&closestMatch);
    ResizeSwapChainBuffers();

    mSwapChain->SetFullscreenState(TRUE, mOutput);

    closestMatch.RefreshRate.Numerator = 0;
    closestMatch.RefreshRate.Denominator = 0;

    mSwapChain->ResizeTarget(&closestMatch);
    ResizeSwapChainBuffers();
        
    ID3D11Texture2D* renderTargetBuffer;

    mSwapChain->GetBuffer(0, __uuidof(ID3D11Texture2D), reinterpret_cast<void**>(&renderTargetBuffer));	
    mRenderDevice->CreateRenderTargetView(renderTargetBuffer, NULL, &mRenderTargetView);
    mRenderContext->OMSetRenderTargets(1, &mRenderTargetView, NULL);

    renderTargetBuffer->Release();

    mIgnoreSizeMessage = false;
}

/////////////////////////////////////////////////////////////////////////////////////////

void Application::HandleSizeMessage(WPARAM wordParameter)
{
    mWindowMinimized = (wordParameter == SIZE_MINIMIZED) ? true : false;

    if (!mSwapChain || mIgnoreSizeMessage)
        return;
    
    mRenderContext->OMSetRenderTargets(0, NULL, NULL);
    mRenderTargetView->Release();

    ResizeSwapChainBuffers();

    ID3D11Texture2D* renderTargetBuffer;

    mSwapChain->GetBuffer(0, __uuidof(ID3D11Texture2D), reinterpret_cast<void**>(&renderTargetBuffer));	
    mRenderDevice->CreateRenderTargetView(renderTargetBuffer, NULL, &mRenderTargetView);
    mRenderContext->OMSetRenderTargets(1, &mRenderTargetView, NULL);

    renderTargetBuffer->Release();
}

/////////////////////////////////////////////////////////////////////////////////////////

void Application::HandleKeydownMessage(WPARAM wordParameter)
{
    if (wordParameter == VK_ESCAPE)
    {
        ::DestroyWindow(mWindowHandle);
        return;
    }

    if (!mSwapChain)
        return;

    BOOL fullscreenState;
    mSwapChain->GetFullscreenState(&fullscreenState, NULL);

    if (fullscreenState && wordParameter == VK_DOWN)
        SetWindowedState();
    else if (!fullscreenState && wordParameter == VK_UP)
        SetFullscreenState();
}

/////////////////////////////////////////////////////////////////////////////////////////

LRESULT CALLBACK Application::WindowProcedure(HWND windowHandle, UINT message, WPARAM wordParameter, LPARAM longParameter)
{
    if (message == WM_NCCREATE)
    {       
        Application* application = reinterpret_cast<Application*>(
            reinterpret_cast<LPCREATESTRUCT>(longParameter)->lpCreateParams);

        ::SetWindowLongPtrW(windowHandle, GWLP_USERDATA, reinterpret_cast<LONG_PTR>(application));
    }
    else
    {    
        Application* application = reinterpret_cast<Application*>(
            ::GetWindowLongPtrW(windowHandle, GWLP_USERDATA));

        switch (message)
        {
        case WM_DESTROY:
            ::PostQuitMessage(0);
            return 0;

        case WM_SIZE:
            application->HandleSizeMessage(wordParameter);
            break;

        case WM_KEYDOWN:
            application->HandleKeydownMessage(wordParameter);
            break;
        }
    }

    return ::DefWindowProcW(windowHandle, message, wordParameter, longParameter);
}
Etwas kompliziert aber es funktioniert.
Besten Dank.
Antworten