• Announcements

    • khawk

      Download the Game Design and Indie Game Marketing Freebook   07/19/17

      GameDev.net and CRC Press have teamed up to bring a free ebook of content curated from top titles published by CRC Press. The freebook, Practices of Game Design & Indie Game Marketing, includes chapters from The Art of Game Design: A Book of Lenses, A Practical Guide to Indie Game Marketing, and An Architectural Approach to Level Design. The GameDev.net FreeBook is relevant to game designers, developers, and those interested in learning more about the challenges in game development. We know game development can be a tough discipline and business, so we picked several chapters from CRC Press titles that we thought would be of interest to you, the GameDev.net audience, in your journey to design, develop, and market your next game. The free ebook is available through CRC Press by clicking here. The Curated Books The Art of Game Design: A Book of Lenses, Second Edition, by Jesse Schell Presents 100+ sets of questions, or different lenses, for viewing a game’s design, encompassing diverse fields such as psychology, architecture, music, film, software engineering, theme park design, mathematics, anthropology, and more. Written by one of the world's top game designers, this book describes the deepest and most fundamental principles of game design, demonstrating how tactics used in board, card, and athletic games also work in video games. It provides practical instruction on creating world-class games that will be played again and again. View it here. A Practical Guide to Indie Game Marketing, by Joel Dreskin Marketing is an essential but too frequently overlooked or minimized component of the release plan for indie games. A Practical Guide to Indie Game Marketing provides you with the tools needed to build visibility and sell your indie games. With special focus on those developers with small budgets and limited staff and resources, this book is packed with tangible recommendations and techniques that you can put to use immediately. As a seasoned professional of the indie game arena, author Joel Dreskin gives you insight into practical, real-world experiences of marketing numerous successful games and also provides stories of the failures. View it here. An Architectural Approach to Level Design This is one of the first books to integrate architectural and spatial design theory with the field of level design. The book presents architectural techniques and theories for level designers to use in their own work. It connects architecture and level design in different ways that address the practical elements of how designers construct space and the experiential elements of how and why humans interact with this space. Throughout the text, readers learn skills for spatial layout, evoking emotion through gamespaces, and creating better levels through architectural theory. View it here. Learn more and download the ebook by clicking here. Did you know? GameDev.net and CRC Press also recently teamed up to bring GDNet+ Members up to a 20% discount on all CRC Press books. Learn more about this and other benefits here.
Sign in to follow this  
Followers 0
knatterton

Problems going fullscreen

4 posts in this topic

Hey,

My application starts up successfully in windowed mode and now I'm trying to switch to fullscreen mode without any changes in display mode. In other words, I want to keep the desktop resolution and refresh rate. I expected this to be a fairly easy thing to accomplish, but I've run into a problem that I can't seem to solve. I've set up my application so that the Enter key switches between windowed and fullscreen modes. I've also disabled Alt-Enter from doing the same, but I'm fairly certain that has nothing to do with this particular problem. This is what happens after I press Enter:

1. Key press is correctly detected.
2. DXGISwapChain::SetFullscreenState(true, nullptr) is called.
3. Immediately after SetFullscreenState() the application goes fullscreen and a WM_SIZE message is received.

This is when the problems start. The application does go to fullscreen mode successfully, but the display mode is also changed. Also the width and height received with the WM_SIZE message seem to be incorrect. When running the application on my TV the display mode changes from 1920x1080@60Hz to 1920x1080i@60Hz and the size received with WM_SIZE is 1768x992. When running the application on my monitor the display mode changes from 1920x1200@60Hz to 1600x1200@60Hz and WM_SIZE delivers 1008x730.

4. After getting the WM_SIZE message, IDXGISwapChain::ResizeBuffers() is called with the new width and height values, but it doesn't matter really, because something has already gone wrong before this step.

This behavior seems strange to me, because I've created the swap chain without the DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH flag. I also never call IDXGISwapChain::ResizeTarget(). So what's changing the display mode anyway? I thought that calling SetFullscreenState() was supposed to keep the current desktop resolution, but I must have misunderstood something. Any obvious things I might have missed? Could my dual monitor setup have something to do with this? I can also post some code samples if that would be helpful.

Any help would be appreciated!
0

Share this post


Link to post
Share on other sites
I don't seem to be getting anywhere with this problem, so I'll post some code snippets and hope that someone can help me.

Here's the function I use to create the device and the swap chain:
[source lang="plain"]bool D3D::initialize(HWND window_handle, bool vsync_enabled)
{
assert(m_device == nullptr);

m_window_handle = window_handle;
m_vsync_enabled = vsync_enabled;

// Creates device
UINT device_flags = 0;
#if defined(DEBUG) || defined(_DEBUG)
device_flags = D3D11_CREATE_DEVICE_DEBUG;
#endif

D3D_FEATURE_LEVEL features[] = { D3D_FEATURE_LEVEL_11_0 };
int num_features = 1;
D3D_FEATURE_LEVEL feature_level;

HRESULT hr = D3D11CreateDevice(nullptr, D3D_DRIVER_TYPE_HARDWARE, nullptr, device_flags, features, num_features, D3D11_SDK_VERSION, &m_device, &feature_level, &m_immediate_context);

if (FAILED(hr))
{
LOG(kLogError) << "Failed to create Direct3D device.";
return false;
}

if (feature_level != D3D_FEATURE_LEVEL_11_0)
{
LOG(kLogError) << "Direct3D 11 not supported.";
return false;
}

// Creates swap chain description
DXGI_SWAP_CHAIN_DESC swap_chain_desc;
memset(&swap_chain_desc, 0, sizeof(swap_chain_desc));
swap_chain_desc.BufferDesc.Width = 0;
swap_chain_desc.BufferDesc.Height = 0;
swap_chain_desc.BufferDesc.RefreshRate.Numerator = 0;
swap_chain_desc.BufferDesc.RefreshRate.Denominator = 0;
swap_chain_desc.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
swap_chain_desc.BufferDesc.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED;
swap_chain_desc.BufferDesc.Scaling = DXGI_MODE_SCALING_CENTERED;
swap_chain_desc.SampleDesc.Count = 1;
swap_chain_desc.SampleDesc.Quality = 0;
swap_chain_desc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
swap_chain_desc.BufferCount = 1;
swap_chain_desc.OutputWindow = m_window_handle;
swap_chain_desc.Windowed = true;
swap_chain_desc.SwapEffect = DXGI_SWAP_EFFECT_DISCARD;
swap_chain_desc.Flags = 0;

IDXGIDevice1* pDXGIDevice;
m_device->QueryInterface(__uuidof(IDXGIDevice1), (void **)&pDXGIDevice);

IDXGIAdapter1* pDXGIAdapter;
pDXGIDevice->GetParent(__uuidof(IDXGIAdapter1), (void **)&pDXGIAdapter);

IDXGIFactory1* pIDXGIFactory;
pDXGIAdapter->GetParent(__uuidof(IDXGIFactory1), (void **)&pIDXGIFactory);

// Creates swap chain
hr = pIDXGIFactory->CreateSwapChain(m_device, &swap_chain_desc, &m_swap_chain);

// Disables Alt-Enter
if (FAILED(pIDXGIFactory->MakeWindowAssociation(m_window_handle, DXGI_MWA_NO_ALT_ENTER | DXGI_MWA_NO_WINDOW_CHANGES | DXGI_MWA_NO_PRINT_SCREEN)))
{
LOG(kLogError) << "MakeWindowAssociation failed.";
}

SAFE_RELEASE(pIDXGIFactory);
SAFE_RELEASE(pDXGIAdapter);
SAFE_RELEASE(pDXGIDevice);

if (FAILED(hr))
{
LOG(kLogError) << "Failed to create swap chain.";
return false;
}

m_initialized = true;

return true;
}[/source]

Here's the function that's called after the application receives a WM_SIZE message. Well, actually it's not called until the whole event queue has been processed, because I see no point in resizing the buffers while the window is being resized.
[source lang="plain"]bool D3D::resize_window( int width, int height )
{
assert(m_initialized == true);

LOG(kLogInfo) << "Changing window size to: " << width << " " << height;

m_immediate_context->ClearState();

SAFE_RELEASE(m_back_buffer_view);
SAFE_RELEASE(m_depth_stencil_view);

if (FAILED(m_swap_chain->ResizeBuffers(0, width, height, DXGI_FORMAT_UNKNOWN, 0)))
{
LOG(kLogError) << "Failed to resize swap chain's back buffer.";

return false;
}

ID3D11Texture2D* back_buffer_texture;
if (FAILED(m_swap_chain->GetBuffer(0, __uuidof(ID3D11Texture2D), (void**)&back_buffer_texture)))
{
LOG(kLogError) << "Failed to get swap chain buffer.";
return false;
}

if (FAILED (m_device->CreateRenderTargetView(back_buffer_texture, 0, &m_back_buffer_view)))
{
LOG(kLogError) << "Failed to create render target view.";

return false;
}

// Not needed anymore
SAFE_RELEASE(back_buffer_texture);

D3D11_TEXTURE2D_DESC desc;
memset(&desc, 0, sizeof(desc));
desc.Width = width;
desc.Height = height;
desc.MipLevels = 1;
desc.ArraySize = 1;
desc.Format = DXGI_FORMAT_D32_FLOAT;
desc.SampleDesc.Count = 1;
desc.SampleDesc.Quality = 0;
desc.Usage = D3D11_USAGE_DEFAULT;
desc.BindFlags = D3D11_BIND_DEPTH_STENCIL;
desc.CPUAccessFlags = 0;
desc.MiscFlags = 0;

ID3D11Texture2D* depth_stencil_texture;
if (FAILED(m_device->CreateTexture2D(&desc, 0, &depth_stencil_texture)))
{
LOG(kLogError) << "Failed to create depth stencil buffer.";

return false;
}

if (FAILED(m_device->CreateDepthStencilView(depth_stencil_texture, 0, &m_depth_stencil_view)))
{
LOG(kLogError) << "Failed to create depth stencil view.";

return false;
}

// Not needed anymore
SAFE_RELEASE(depth_stencil_texture);

// Initializes viewport
memset(&m_viewport, 0, sizeof(m_viewport));
m_viewport.Width = (float)width;
m_viewport.Height = (float)height;
m_viewport.MinDepth = 0.0f;
m_viewport.MaxDepth = 1.0f;

return true;
}[/source]

And here's the function that's called when switching between windowed and fullscreen modes. I'm hoping that it would someday switch to fullscreen mode without changing the display mode, but so far I've been unsuccessful.
[source lang="plain"]void D3D::set_fullscreen( bool fullscreen )
{
assert(m_initialized == true);

if (fullscreen != m_full_screen)
{
m_full_screen = fullscreen;

LOG(kLogInfo) << "Setting fullscreen to " << (m_full_screen ? "TRUE" : "FALSE");

HRESULT result = m_swap_chain->SetFullscreenState(m_full_screen, nullptr);

if (FAILED(result))
{
LOG(kLogError) << "Failed to set fullscreen state.";
}
}
}[/source]

So... Any ideas? I've read the page about DXGI best practices ([url="http://msdn.microsoft.com/en-us/library/windows/desktop/ee417025%28v=vs.85%29.aspx"]http://msdn.microsof...5(v=vs.85).aspx[/url]) and I feel that I've more or less followed the instructions that it provides.

I'll include my main loop as well, so you can see how the functions are actually called. Note that I'm not actually drawing anything at the moment. Just creating an empty window and trying to go fullscreen.
[source lang="plain"]int Game::run(HINSTANCE hInstance)
{
MSG msg;

// Game loop
while (true)
{
// Windows messages
while (PeekMessage(&msg, nullptr, 0, 0, PM_REMOVE) != 0)
{
// Quitting
if (msg.message == WM_QUIT)
{
return (int)msg.wParam;
}

TranslateMessage(&msg);
DispatchMessage(&msg);
}

if (m_keyboard.key_state(kKeyEsc) != kKeyNotPressed)
{
PostQuitMessage(0);
}
else if (m_keyboard.key_state(kKeyEnter) != kKeyNotPressed)
{
m_fullscreen = !m_fullscreen;
m_keyboard.reset_key_state(kKeyEnter);

// Sets fullscreen state
m_d3d.set_fullscreen(m_fullscreen);
}

// If the window has been resized
if (m_window_resized)
{
m_d3d.resize_window(m_client_width, m_client_height);

m_window_resized = false;
}
}
}[/source]

Any other pointers are welcome as well, if you notice something that seems to make no sense.
0

Share this post


Link to post
Share on other sites
Try skipping DXGI_MWA_NO_WINDOW_CHANGES in your MakeWindowAssociation flags. Edited by Erik Rufelt
1

Share this post


Link to post
Share on other sites
I actually added that flag to see if it would solve this problem. I'm not sure what it's supposed to do, but at least it doesn't seem change the fullscreen behavior in any way.
0

Share this post


Link to post
Share on other sites
Problem solved!

It was really something that I should have figured out sooner, but I was blinded by the examples in books and tutorials. I hadn't previously used the IDXGIOutput::GetDisplayModeList() function to check what display modes are actually available on my monitor. I just assumed that 1920x1200 would be there and that's it. However, apparently my monitor only supports one display mode with that resolution and DXGI_FORMAT_R8G8B8A8_UNORM and to use it, I have to set scanline ordering to DXGI_MODE_SCANLINE_ORDER_PROGRESSIVE and scaling to DXGI_MODE_SCALING_UNSPECIFIED. I didn't realize the importance of these two parameters. I just used whatever values I had seen in books and tutorials. Does anyone know if these values are what most monitors support? At least they work with my primary monitor and my TV. I guess that the best practice would be to check what's the highest resolution that the primary monitor supports and get the values for scanline ordering and scaling by calling GetDisplayModeList() and use those when creating the swap chain.
0

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  
Followers 0