DXGI_MODE_DESC für Anfänger
Verfasst: 12.04.2012, 16:50
Hallo zusammen.
Ich kämpfe mich gerade durch verschiedene Tutorials zum Thema DirectX 11 und habe mittlerweile eine simple Fensteranwendung sammt Renderdevice implementiert.
Nun bin ich beim Vollbildmodus angelangt, werde aber aus der DX-API Dokumentation nicht ganz schlau.
Doch zuerst mal meine simple Anwendung (Zurzeit ist alles noch in Headerdateien)
Window.h/cpp
Und hier noch Application.h/cpp
Nun zum "Problem".
Um einen korrekten Wechsel in den Vollbildmodus zu gewährleisten, muss man neinen gültigen Displaymodus setzen.
Eigentlich sollte das mittels IDXGISwapChain::ResizeTarget() möglich sein, ist es aber nicht. Alles was ResizeTarget() macht, ist im Fensterstatus
die Fensterklientgrösse und im Vollbildstatus die Auflösung zu verändern. Also nur DXGI_MODE_DESC::Width und DXGI_MODE_DESC::Height, alle
anderen Werte werden komplett ignoriert. Die anderen Werte können nur gesetzt werden, wenn ich das Swapchain initialisiere. Die einzige Möglichkeit
um verschiedene Auflösungen zu setzen ohne eine IDXGISwapChain Performancewarnung zu bekommen, ist, wenn ich alle DXGI_MODE_DESC Werte "ausnulle"
und nur die Auflösung setze. Nun kann ich problemlos zuerst den Fensterrahmen entfernen, die Fensterklientgrösse und den Vollbildstatus setzen. Das selbe
wenn ich die Vollbildauflösung ändern möchte. Einfach nur ResizeTarget() mit der neuen Auflösung aufrufen und fertig. Funktioniert.
Nun habe ich mittels IDXGIOutput::GetDisplayModeList() eine Displaymodusliste erstellt. Mir ist aufgefallen, das praktisch alle Auflösungen unterschiedliche
Bildwiederholfrequenzen haben. Diese müsste ich ja auch setzen um einen korrekten Vollbildmodus zu haben und das wäre nur möglich wenn ich dazu jedesmal
das Swapchain neu initialisieren würde.
Was habe ich da missverstanden?
Besten Dank
Ich kämpfe mich gerade durch verschiedene Tutorials zum Thema DirectX 11 und habe mittlerweile eine simple Fensteranwendung sammt Renderdevice implementiert.
Nun bin ich beim Vollbildmodus angelangt, werde aber aus der DX-API Dokumentation nicht ganz schlau.
Doch zuerst mal meine simple Anwendung (Zurzeit ist alles noch in Headerdateien)
Window.h/cpp
Code: Alles auswählen
#pragma once
#define WIN32_LEAN_AND_MEAN
#define NOMINMAX
#include <string>
#include <Windows.h>
#include <XInput.h>
#include "../Include/Uncopyable.h"
#include "../Include/Exception.h"
#include "../Include/WindowIcon.h"
#include "../Include/KeyboardState.h"
namespace DirectX11Application
{
class Window : protected Uncopyable
{
public:
enum ShowCommand
{
ShowDefault,
ShowMinimized,
ShowMaximized
};
private:
bool mActivated;
bool mMinimized;
bool mMaximized;
bool mBorderless;
bool mDisplayed;
size_t mClientWidth;
size_t mClientHeight;
HINSTANCE mInstanceHandle;
HWND mWindowHandle;
WINDOWPLACEMENT mWindowPlacement;
KeyboardState mKeyboardState;
public:
Window() :
mActivated(false),
mMinimized(false),
mMaximized(false),
mBorderless(false),
mDisplayed(false)
{
mInstanceHandle = reinterpret_cast<HINSTANCE>(GetModuleHandleW(nullptr));
mWindowPlacement.length = sizeof(mWindowPlacement);
const auto windowIconHandle = LoadIconW(mInstanceHandle, MAKEINTRESOURCE(DIRECTX_11_APPLICATION_WINDOW_ICON));
WNDCLASSEXW windowClassDescription;
windowClassDescription.cbSize = sizeof(windowClassDescription);
windowClassDescription.cbClsExtra = 0;
windowClassDescription.cbWndExtra = 0;
windowClassDescription.hbrBackground = reinterpret_cast<HBRUSH>(GetStockObject(BLACK_BRUSH));
windowClassDescription.hCursor = LoadCursorW(nullptr, IDC_ARROW);
windowClassDescription.hIcon = windowIconHandle;
windowClassDescription.hIconSm = windowIconHandle;
windowClassDescription.hInstance = mInstanceHandle;
windowClassDescription.lpfnWndProc = &Window::MessageProcedure;
windowClassDescription.lpszClassName = L"DirectX11ApplicationWindow";
windowClassDescription.lpszMenuName = nullptr;
windowClassDescription.style = CS_VREDRAW | CS_HREDRAW;
if (!RegisterClassExW(&windowClassDescription))
{
throw WindowsError("RegisterClassExW() failed.");
}
mWindowHandle = CreateWindowExW(
WS_EX_APPWINDOW,
L"DirectX11ApplicationWindow",
nullptr,
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
nullptr,
nullptr,
mInstanceHandle,
reinterpret_cast<void*>(this));
if (mWindowHandle == nullptr)
{
UnregisterClassW(L"DirectX11ApplicationWindow", mInstanceHandle);
throw WindowsError("CreateWindowExW() failed.");
}
RECT clientRectangle;
GetClientRect(mWindowHandle, &clientRectangle);
mClientWidth = static_cast<size_t>(clientRectangle.right);
mClientHeight = static_cast<size_t>(clientRectangle.bottom);
}
~Window()
{
DestroyWindow(mWindowHandle);
UnregisterClassW(L"DirectX11ApplicationWindow", mInstanceHandle);
}
bool IsActivated() const
{
return mActivated;
}
bool IsMinimized() const
{
return mMinimized;
}
bool IsMaximized() const
{
return mMaximized;
}
bool IsBorderless() const
{
return mBorderless;
}
bool IsDisplayed() const
{
return mDisplayed;
}
size_t GetClientWidth() const
{
return mClientWidth;
}
size_t GetClientHeight() const
{
return mClientHeight;
}
HINSTANCE GetInstanceHandle() const
{
return mInstanceHandle;
}
HWND GetWindowHandle() const
{
return mWindowHandle;
}
const KeyboardState& GetKeyboardState() const
{
return mKeyboardState;
}
void SetTitle(const std::wstring& title) const
{
SetWindowTextW(mWindowHandle, title.c_str());
}
void SetClientSize(size_t clientWidth, size_t clientHeight) const
{
auto windowWidth = static_cast<int>(clientWidth);
auto windowHeight = static_cast<int>(clientHeight);
if (mBorderless)
{
if (windowWidth < 640)
{
windowWidth = 640;
}
if (windowHeight < 480)
{
windowHeight = 480;
}
}
else
{
RECT windowRectangle;
GetWindowRect(mWindowHandle, &windowRectangle);
MONITORINFO monitorInfo;
monitorInfo.cbSize = sizeof(monitorInfo);
GetMonitorInfoW(MonitorFromRect(&windowRectangle, MONITOR_DEFAULTTONEAREST), &monitorInfo);
const auto targetWidth = static_cast<unsigned int>(monitorInfo.rcWork.right);
const auto targetHeight = static_cast<unsigned int>(monitorInfo.rcWork.bottom);
windowRectangle.left = 0;
windowRectangle.top = 0;
windowRectangle.right = static_cast<LONG>(clientWidth);
windowRectangle.bottom = static_cast<LONG>(clientHeight);
AdjustWindowRectEx(
&windowRectangle,
static_cast<DWORD>(GetWindowLongPtrW(mWindowHandle, GWL_STYLE)),
FALSE,
static_cast<DWORD>(GetWindowLongPtrW(mWindowHandle, GWL_EXSTYLE)));
if (clientWidth > targetWidth)
{
windowWidth = static_cast<int>(targetWidth);
}
else if (clientWidth == 0)
{
windowWidth = static_cast<int>(targetWidth) - 200;
}
else
{
windowWidth = static_cast<int>(windowRectangle.right - windowRectangle.left);
}
if (clientHeight > targetHeight)
{
windowHeight = static_cast<int>(targetHeight);
}
else if (windowHeight == 0)
{
windowHeight = static_cast<int>(targetHeight) - 200;
}
else
{
windowHeight = static_cast<int>(windowRectangle.bottom - windowRectangle.top);
}
}
SetWindowPos(
mWindowHandle,
nullptr,
0,
0,
windowWidth,
windowHeight,
SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE);
}
void SetBorderlessState(bool borderless)
{
if (mBorderless != borderless)
{
if (borderless)
{
GetWindowPlacement(mWindowHandle, &mWindowPlacement);
SetWindowLongPtrW(mWindowHandle, GWL_STYLE, WS_POPUP);
SetWindowLongPtrW(mWindowHandle, GWL_EXSTYLE, 0);
}
else
{
SetWindowLongPtrW(mWindowHandle, GWL_STYLE, WS_OVERLAPPEDWINDOW);
SetWindowLongPtrW(mWindowHandle, GWL_EXSTYLE, WS_EX_APPWINDOW);
}
SetWindowPos(
mWindowHandle,
HWND_TOP,
0,
0,
0,
0,
SWP_NOMOVE |
SWP_NOSIZE |
SWP_NOZORDER |
SWP_SHOWWINDOW |
SWP_FRAMECHANGED);
if (!borderless)
{
SetWindowPlacement(mWindowHandle, &mWindowPlacement);
}
mBorderless = borderless;
}
}
void CenterAtNearestWorkArea() const
{
RECT windowRectangle;
GetWindowRect(mWindowHandle, &windowRectangle);
const auto windowWidth = windowRectangle.right - windowRectangle.left;
const auto windowHeight = windowRectangle.bottom - windowRectangle.top;
MONITORINFO monitorInfo;
monitorInfo.cbSize = sizeof(monitorInfo);
GetMonitorInfoW(MonitorFromRect(&windowRectangle, MONITOR_DEFAULTTONEAREST), &monitorInfo);
SetWindowPos(
mWindowHandle,
nullptr,
static_cast<int>((monitorInfo.rcWork.right - windowWidth) / 2),
static_cast<int>((monitorInfo.rcWork.bottom - windowHeight) / 2),
0,
0,
SWP_NOSIZE |
SWP_NOZORDER |
SWP_NOACTIVATE);
}
void Show(ShowCommand showCommand)
{
switch (showCommand)
{
case ShowDefault:
{
ShowWindow(mWindowHandle, (mMinimized || mMaximized) ? SW_RESTORE : SW_SHOWDEFAULT);
break;
}
case ShowMinimized:
{
ShowWindow(mWindowHandle, mDisplayed ? SW_MINIMIZE : SW_SHOWMINIMIZED);
break;
}
case ShowMaximized:
{
ShowWindow(mWindowHandle, mDisplayed ? SW_MAXIMIZE : SW_SHOWMAXIMIZED);
break;
}
default:
{
return;
}
}
if (!mDisplayed)
{
mDisplayed = true;
if (mMinimized)
{
ShowWindow(mWindowHandle, SW_RESTORE);
}
SetForegroundWindow(mWindowHandle);
SetFocus(mWindowHandle);
}
}
void PostCloseMessage() const
{
PostMessageW(mWindowHandle, WM_CLOSE, 0, 0);
}
private:
static LRESULT CALLBACK Window::MessageProcedure(HWND windowHandle, UINT message, WPARAM wordParameter, LPARAM longParameter)
{
if (message == WM_NCCREATE)
{
SetWindowLongPtrW(
windowHandle,
GWL_USERDATA,
reinterpret_cast<LONG_PTR>(
reinterpret_cast<LPCREATESTRUCTW>(longParameter)->lpCreateParams));
}
else
{
const auto window = reinterpret_cast<Window*>(GetWindowLongPtrW(windowHandle, GWL_USERDATA));
if (window)
{
switch (message)
{
case WM_ACTIVATE:
{
if (wordParameter == WA_INACTIVE)
{
window->mActivated = false;
XInputEnable(FALSE);
}
else
{
window->mActivated = true;
XInputEnable(TRUE);
}
break;
}
case WM_SIZE:
{
if (wordParameter == SIZE_MINIMIZED)
{
window->mMinimized = true;
}
else
{
window->mMinimized = false;
window->mMaximized = wordParameter == SIZE_MAXIMIZED;
window->mClientWidth = static_cast<size_t>(LOWORD(longParameter));
window->mClientHeight = static_cast<size_t>(HIWORD(longParameter));
}
break;
}
case WM_GETMINMAXINFO:
{
reinterpret_cast<MINMAXINFO*>(longParameter)->ptMinTrackSize.x = 400;
reinterpret_cast<MINMAXINFO*>(longParameter)->ptMinTrackSize.y = 400;
break;
}
case WM_CLOSE:
{
PostQuitMessage(0);
return false;
}
case WM_KEYDOWN:
case WM_SYSKEYDOWN:
{
window->mKeyboardState[wordParameter & 0xFF] = true;
window->mKeyboardState.Alt = (longParameter & (1 << 29)) != 0;
break;
}
case WM_KEYUP:
case WM_SYSKEYUP:
{
window->mKeyboardState[wordParameter & 0xFF] = false;
window->mKeyboardState.Alt = (longParameter & (1 << 29)) != 0;
break;
}
case WM_SYSCOMMAND:
{
switch (wordParameter & 0xFFF0)
{
case SC_KEYMENU:
{
return 0;
}
case SC_MONITORPOWER:
case SC_SCREENSAVE:
{
if (window->mBorderless)
{
return 0;
}
break;
}
}
break;
}
}
}
}
return DefWindowProcW(windowHandle, message, wordParameter, longParameter);
}
};
}
Code: Alles auswählen
#pragma once
#define WIN32_LEAN_AND_MEAN
#define NOMINMAX
#include <string>
#include <vector>
#include <Windows.h>
#include <DXGI.h>
#include <D3D11.h>
#include "../Include/Uncopyable.h"
#include "../Include/Utility.h"
#include "../Include/Timer.h"
#include "../Include/Window.h"
#include "../Include/Keyboard.h"
#include "../Include/Gamepad.h"
#include "../Include/ComPointer.h"
#include "../Include/Exception.h"
namespace DirectX11Application
{
class Application : protected Uncopyable
{
private:
struct Finalizer
{
ComPointer<IDXGISwapChain> SwapChain;
ComPointer<ID3D11DeviceContext> DeviceContext;
~Finalizer()
{
if (SwapChain.Get())
{
SwapChain->SetFullscreenState(FALSE, nullptr);
}
if (DeviceContext.Get())
{
DeviceContext->ClearState();
DeviceContext->Flush();
}
}
};
struct HiddenCursor
{
HiddenCursor()
{
ShowCursor(FALSE);
}
~HiddenCursor()
{
ShowCursor(TRUE);
}
};
private:
bool mStatusOccluded;
bool mRestoreFullscreen;
Finalizer mFinalizer;
Timer mTimer;
Window mWindow;
Keyboard mKeyboard;
Gamepad mGamepad;
std::vector<DXGI_MODE_DESC> mDisplayModeList;
D3D_FEATURE_LEVEL mFeatureLevel;
ComPointer<IDXGIFactory1> mFactory;
ComPointer<IDXGIAdapter1> mAdapter;
ComPointer<IDXGIOutput> mOutput;
ComPointer<IDXGISwapChain> mSwapChain;
ComPointer<ID3D11Device> mDevice;
ComPointer<ID3D11DeviceContext> mImmediateContext;
ComPointer<ID3D11Texture2D> mBackBuffer;
ComPointer<ID3D11RenderTargetView> mBackBufferView;
ComPointer<ID3D11Texture2D> mDepthStencil;
ComPointer<ID3D11DepthStencilView> mDepthStencilView;
public:
explicit Application(const std::wstring& commandLine) :
mStatusOccluded(false),
mRestoreFullscreen(false)
{
Utility::LimitThreadToSingleCore();
InitializeDevice();
InitializeDisplayModeList();
DXGI_ADAPTER_DESC1 adapterDescription;
mAdapter->GetDesc1(&adapterDescription);
mWindow.SetTitle(L"DirectX 11 Application - " + std::wstring(adapterDescription.Description));
mWindow.SetClientSize(0, 0);
mWindow.CenterAtNearestWorkArea();
mWindow.Show(Window::ShowDefault);
InitializeSwapChain();
if (commandLine == L"fullscreen")
{
SetFullscreenMode();
}
InitializeSwapChainDepencies();
}
void Update()
{
mTimer.Update();
BOOL fullscreen;
mSwapChain->GetFullscreenState(&fullscreen, nullptr);
if (!fullscreen && mWindow.IsBorderless() && !mRestoreFullscreen)
{
mRestoreFullscreen = true;
mWindow.Show(Window::ShowMinimized);
}
if (mWindow.IsMinimized())
{
return;
}
DXGI_SWAP_CHAIN_DESC swapChainDescription;
mSwapChain->GetDesc(&swapChainDescription);
if (mRestoreFullscreen ||
swapChainDescription.BufferDesc.Width != mWindow.GetClientWidth() ||
swapChainDescription.BufferDesc.Height != mWindow.GetClientHeight())
{
ReleaseSwapChainDepencies();
if (mRestoreFullscreen)
{
mRestoreFullscreen = false;
SetFullscreenMode();
}
else
{
ResizeBackBuffers();
}
InitializeSwapChainDepencies();
}
if (!mStatusOccluded)
{
if (mWindow.IsActivated())
{
while (mTimer.ExecuteTick())
{
Tick();
}
}
Render();
}
Present();
}
private:
void InitializeDevice()
{
auto result = CreateDXGIFactory1(mFactory.GetInterfaceID(), reinterpret_cast<void**>(mFactory.GetAdress()));
if (FAILED(result))
{
throw DirectXError("CreateDXGIFactory1() failed.", result);
}
result = mFactory->EnumAdapters1(0, mAdapter.GetAdress());
if (FAILED(result))
{
throw DirectXError("IDXGIFactory1::EnumAdapters1() failed.", result);
}
result = mAdapter->EnumOutputs(0, mOutput.GetAdress());
if (FAILED(result))
{
throw DirectXError("IDXGIAdapter1::EnumOutputs() failed.", result);
}
UINT deviceCreateFlags = 0;
#if defined(DEBUG) || defined(_DEBUG)
deviceCreateFlags |= D3D11_CREATE_DEVICE_DEBUG;
#endif
result = D3D11CreateDevice(
mAdapter.Get(),
D3D_DRIVER_TYPE_UNKNOWN,
nullptr,
deviceCreateFlags,
nullptr,
0,
D3D11_SDK_VERSION,
mDevice.GetAdress(),
&mFeatureLevel,
mImmediateContext.GetAdress());
if (FAILED(result))
{
throw DirectXError("D3D11CreateDevice() failed.", result);
}
mFinalizer.DeviceContext = mImmediateContext;
}
void InitializeDisplayModeList(DXGI_FORMAT format = DXGI_FORMAT_R8G8B8A8_UNORM)
{
UINT displayModeCount;
auto result = mOutput->GetDisplayModeList(format, 0, &displayModeCount, nullptr);
if (FAILED(result))
{
throw DirectXError("IDXGIOutput::GetDisplayModeList() failed.", result);
}
mDisplayModeList.resize(displayModeCount);
result = mOutput->GetDisplayModeList(format, 0, &displayModeCount, &mDisplayModeList[0]);
if (FAILED(result))
{
throw DirectXError("IDXGIOutput::GetDisplayModeList() failed.", result);
}
}
void InitializeSwapChain()
{
DXGI_MODE_DESC displayMode;
displayMode.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
displayMode.Width = 0;
displayMode.Height = 0;
displayMode.RefreshRate.Numerator = 0;
displayMode.RefreshRate.Denominator = 0;
displayMode.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED;
displayMode.Scaling = DXGI_MODE_SCALING_UNSPECIFIED;
const auto windowHandle = mWindow.GetWindowHandle();
DXGI_SWAP_CHAIN_DESC swapChainDescription;
swapChainDescription.BufferDesc = displayMode;
swapChainDescription.BufferCount = 2;
swapChainDescription.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
swapChainDescription.Flags = DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH;
swapChainDescription.OutputWindow = windowHandle;
swapChainDescription.SwapEffect = DXGI_SWAP_EFFECT_DISCARD;
swapChainDescription.Windowed = TRUE;
swapChainDescription.SampleDesc.Count = 1;
swapChainDescription.SampleDesc.Quality = 0;
auto result = mFactory->CreateSwapChain(mDevice.Get(), &swapChainDescription, mSwapChain.GetAdress());
if (FAILED(result))
{
throw DirectXError("IDXGIFactory1::CreateSwapChain() failed.", result);
}
result = mFactory->MakeWindowAssociation(windowHandle, DXGI_MWA_NO_ALT_ENTER | DXGI_MWA_NO_WINDOW_CHANGES);
if (FAILED(result))
{
throw DirectXError("IDXGIFactory1::MakeWindowAssociation() failed.", result);
}
mFinalizer.SwapChain = mSwapChain;
}
void InitializeSwapChainDepencies()
{
auto result = mSwapChain->GetBuffer(0, mBackBuffer.GetInterfaceID(), reinterpret_cast<void**>(mBackBuffer.GetAdress()));
if (FAILED(result))
{
throw DirectXError("IDXGISwapChain::GetBuffer() failed.", result);
}
result = mDevice->CreateRenderTargetView(mBackBuffer.Get(), nullptr, mBackBufferView.GetAdress());
if (FAILED(result))
{
throw DirectXError("ID3D11Device::CreateRenderTargetView() failed.", result);
}
D3D11_TEXTURE2D_DESC backBufferDescription;
mBackBuffer->GetDesc(&backBufferDescription);
D3D11_TEXTURE2D_DESC depthStencilDescription;
depthStencilDescription.Width = backBufferDescription.Width;
depthStencilDescription.Height = backBufferDescription.Height;
depthStencilDescription.MipLevels = 1;
depthStencilDescription.ArraySize = 1;
depthStencilDescription.Format = DXGI_FORMAT_D24_UNORM_S8_UINT;
depthStencilDescription.SampleDesc = backBufferDescription.SampleDesc;
depthStencilDescription.BindFlags = D3D11_BIND_DEPTH_STENCIL;
depthStencilDescription.Usage = D3D11_USAGE_DEFAULT;
depthStencilDescription.CPUAccessFlags = 0;
depthStencilDescription.MiscFlags = 0;
result = mDevice->CreateTexture2D(&depthStencilDescription, nullptr, mDepthStencil.GetAdress());
if (FAILED(result))
{
throw DirectXError("ID3D11Device::CreateTexture2D() failed.", result);
}
D3D11_DEPTH_STENCIL_VIEW_DESC depthStencilViewDescription;
depthStencilViewDescription.Flags = 0;
depthStencilViewDescription.Format = depthStencilDescription.Format;
depthStencilViewDescription.Texture2D.MipSlice = 0;
if (depthStencilDescription.SampleDesc.Count > 1)
{
depthStencilViewDescription.ViewDimension = D3D11_DSV_DIMENSION_TEXTURE2DMS;
}
else
{
depthStencilViewDescription.ViewDimension = D3D11_DSV_DIMENSION_TEXTURE2D;
}
mDevice->CreateDepthStencilView(mDepthStencil.Get(), &depthStencilViewDescription, mDepthStencilView.GetAdress());
if (FAILED(result))
{
throw DirectXError("ID3D11Device::CreateDepthStencilView() failed.", result);
}
D3D11_VIEWPORT viewport;
viewport.Width = static_cast<FLOAT>(mWindow.GetClientWidth());
viewport.Height = static_cast<FLOAT>(mWindow.GetClientHeight());
viewport.MinDepth = 0.0f;
viewport.MaxDepth = 1.0f;
viewport.TopLeftX = 0.0f;
viewport.TopLeftY = 0.0f;
mImmediateContext->RSSetViewports(1, &viewport);
}
void ReleaseSwapChainDepencies()
{
mImmediateContext->OMSetRenderTargets(0, nullptr, nullptr);
mBackBuffer = nullptr;
mBackBufferView = nullptr;
mDepthStencil = nullptr;
mDepthStencilView = nullptr;
}
void ResizeBackBuffers()
{
DXGI_SWAP_CHAIN_DESC swapChainDescription;
mSwapChain->GetDesc(&swapChainDescription);
const auto result = mSwapChain->ResizeBuffers(
swapChainDescription.BufferCount,
0,
0,
swapChainDescription.BufferDesc.Format,
swapChainDescription.Flags);
if (FAILED(result))
{
throw DirectXError("IDXGISwapChain::ResizeBuffers()", result);
}
}
void SetWindowedMode()
{
const HiddenCursor hiddenCursor;
mSwapChain->SetFullscreenState(FALSE, nullptr);
mWindow.SetBorderlessState(false);
ResizeBackBuffers();
}
void SetFullscreenMode(size_t width = 0, size_t height = 0)
{
const HiddenCursor hiddenCursor;
BOOL fullscreen;
mSwapChain->GetFullscreenState(&fullscreen, nullptr);
if (fullscreen)
{
DXGI_SWAP_CHAIN_DESC swapChainDescription;
mSwapChain->GetDesc(&swapChainDescription);
swapChainDescription.BufferDesc.Width = width;
swapChainDescription.BufferDesc.Height = height;
const auto result = mSwapChain->ResizeTarget(&swapChainDescription.BufferDesc);
if (FAILED(result))
{
throw DirectXError("IDXGISwapChain::ResizeTarget() failed.", result);
}
ResizeBackBuffers();
}
else
{
if (width == 0 && height == 0)
{
DXGI_OUTPUT_DESC outputDescription;
mOutput->GetDesc(&outputDescription);
width = static_cast<size_t>(outputDescription.DesktopCoordinates.right);
height = static_cast<size_t>(outputDescription.DesktopCoordinates.bottom);
}
mWindow.SetBorderlessState(true);
mWindow.SetClientSize(width, height);
mWindow.CenterAtNearestWorkArea();
ResizeBackBuffers();
const auto result = mSwapChain->SetFullscreenState(TRUE, mOutput.Get());
if (FAILED(result))
{
throw DirectXError("IDXGISwapChain::SetFullscreenState() failed.", result);
}
ResizeBackBuffers();
}
}
void ToggleScreen()
{
BOOL fullscreen;
mSwapChain->GetFullscreenState(&fullscreen, nullptr);
ReleaseSwapChainDepencies();
if (fullscreen)
{
SetWindowedMode();
}
else
{
SetFullscreenMode();
}
InitializeSwapChainDepencies();
}
void ResetSwapChain()
{
const HiddenCursor hiddenCursor;
BOOL fullscreen;
mSwapChain->GetFullscreenState(&fullscreen, nullptr);
ReleaseSwapChainDepencies();
mSwapChain->SetFullscreenState(FALSE, nullptr);
mSwapChain = nullptr;
InitializeSwapChain();
if (fullscreen)
{
Sleep(250);
SetFullscreenMode();
}
InitializeSwapChainDepencies();
}
void Tick()
{
mKeyboard.Update(mWindow.GetKeyboardState());
mGamepad.Update();
if (mKeyboard.IsToggled(Keyboard::KeyEscape) || mGamepad.IsToggled(Gamepad::ButtonBack))
{
mWindow.PostCloseMessage();
}
if (mGamepad.CheckForStateChange())
{
mGamepad.SetVibration(mGamepad.GetLeftTrigger(), mGamepad.GetRightTrigger());
}
if (mKeyboard.IsDown(Keyboard::KeyAlt) && mKeyboard.IsToggled(Keyboard::KeyEnter))
{
ToggleScreen();
}
if (mKeyboard.IsDown(Keyboard::KeyAlt) && mKeyboard.IsToggled(Keyboard::KeyBack))
{
ResetSwapChain();
}
}
void Render()
{
const FLOAT clearColor[4] = { 0.0f, 0.125f, 0.3f, 0.0f };
mImmediateContext->OMSetRenderTargets(1, mBackBufferView.GetAdress(), mDepthStencilView.Get());
mImmediateContext->ClearRenderTargetView(mBackBufferView.Get(), clearColor);
mImmediateContext->ClearDepthStencilView(mDepthStencilView.Get(), D3D11_CLEAR_DEPTH | D3D11_CLEAR_STENCIL, 1.0f, 0);
}
void Present()
{
const auto result = mSwapChain->Present(1, mStatusOccluded ? DXGI_PRESENT_TEST : 0);
switch (result)
{
case S_OK:
{
mStatusOccluded = false;
break;
}
case DXGI_STATUS_OCCLUDED:
{
mStatusOccluded = true;
break;
}
default:
{
throw DirectXError("IDXGISwapChain::Present() failed.", result);
}
}
}
};
}
Um einen korrekten Wechsel in den Vollbildmodus zu gewährleisten, muss man neinen gültigen Displaymodus setzen.
Eigentlich sollte das mittels IDXGISwapChain::ResizeTarget() möglich sein, ist es aber nicht. Alles was ResizeTarget() macht, ist im Fensterstatus
die Fensterklientgrösse und im Vollbildstatus die Auflösung zu verändern. Also nur DXGI_MODE_DESC::Width und DXGI_MODE_DESC::Height, alle
anderen Werte werden komplett ignoriert. Die anderen Werte können nur gesetzt werden, wenn ich das Swapchain initialisiere. Die einzige Möglichkeit
um verschiedene Auflösungen zu setzen ohne eine IDXGISwapChain Performancewarnung zu bekommen, ist, wenn ich alle DXGI_MODE_DESC Werte "ausnulle"
und nur die Auflösung setze. Nun kann ich problemlos zuerst den Fensterrahmen entfernen, die Fensterklientgrösse und den Vollbildstatus setzen. Das selbe
wenn ich die Vollbildauflösung ändern möchte. Einfach nur ResizeTarget() mit der neuen Auflösung aufrufen und fertig. Funktioniert.
Nun habe ich mittels IDXGIOutput::GetDisplayModeList() eine Displaymodusliste erstellt. Mir ist aufgefallen, das praktisch alle Auflösungen unterschiedliche
Bildwiederholfrequenzen haben. Diese müsste ich ja auch setzen um einen korrekten Vollbildmodus zu haben und das wäre nur möglich wenn ich dazu jedesmal
das Swapchain neu initialisieren würde.
Was habe ich da missverstanden?
Besten Dank