diff --git a/backends/imgui_impl_dx11.cpp b/backends/imgui_impl_dx11.cpp index 6cc8f26ee..4d05a053d 100644 --- a/backends/imgui_impl_dx11.cpp +++ b/backends/imgui_impl_dx11.cpp @@ -51,6 +51,7 @@ // DirectX #include #include +#include #include #ifdef _MSC_VER #pragma comment(lib, "d3dcompiler") // Automatically link with d3dcompiler.lib as we are using D3DCompile() below. @@ -73,7 +74,8 @@ struct ImGui_ImplDX11_Data { ID3D11Device* pd3dDevice; ID3D11DeviceContext* pd3dDeviceContext; - IDXGIFactory* pFactory; + IDXGIFactory5* pFactory; + bool tearingSupport; ID3D11Buffer* pVB; ID3D11Buffer* pIB; ID3D11VertexShader* pVertexShader; @@ -86,7 +88,7 @@ struct ImGui_ImplDX11_Data ID3D11DepthStencilState* pDepthStencilState; int VertexBufferSize; int IndexBufferSize; - ImVector SwapChainDescsForViewports; + ImVector SwapChainDescsForViewports; ImGui_ImplDX11_Data() { memset((void*)this, 0, sizeof(*this)); VertexBufferSize = 5000; IndexBufferSize = 10000; } }; @@ -433,6 +435,10 @@ bool ImGui_ImplDX11_CreateDeviceObjects() return false; ImGui_ImplDX11_InvalidateDeviceObjects(); + BOOL allow_tearing = FALSE; + bd->pFactory->CheckFeatureSupport(DXGI_FEATURE_PRESENT_ALLOW_TEARING, &allow_tearing, sizeof(allow_tearing)); + bd->tearingSupport = (allow_tearing == TRUE); + // By using D3DCompile() from / d3dcompiler.lib, we introduce a dependency to a given version of d3dcompiler_XX.dll (see D3DCOMPILER_DLL_A) // If you would like to use this DX11 sample code but remove this dependency you can: // 1) compile once, save the compiled shader blobs into a file or source code and pass them to CreateVertexShader()/CreatePixelShader() [preferred solution] @@ -636,7 +642,7 @@ bool ImGui_ImplDX11_Init(ID3D11Device* device, ID3D11DeviceContext* device_co // Get factory from device IDXGIDevice* pDXGIDevice = nullptr; IDXGIAdapter* pDXGIAdapter = nullptr; - IDXGIFactory* pFactory = nullptr; + IDXGIFactory5* pFactory = nullptr; if (device->QueryInterface(IID_PPV_ARGS(&pDXGIDevice)) == S_OK) if (pDXGIDevice->GetParent(IID_PPV_ARGS(&pDXGIAdapter)) == S_OK) @@ -645,6 +651,7 @@ bool ImGui_ImplDX11_Init(ID3D11Device* device, ID3D11DeviceContext* device_co bd->pd3dDevice = device; bd->pd3dDeviceContext = device_context; bd->pFactory = pFactory; + bd->tearingSupport = false; } if (pDXGIDevice) pDXGIDevice->Release(); if (pDXGIAdapter) pDXGIAdapter->Release(); @@ -695,7 +702,7 @@ void ImGui_ImplDX11_NewFrame() // Helper structure we store in the void* RendererUserData field of each ImGuiViewport to easily retrieve our backend data. struct ImGui_ImplDX11_ViewportData { - IDXGISwapChain* SwapChain; + IDXGISwapChain1* SwapChain; ID3D11RenderTargetView* RTView; ImGui_ImplDX11_ViewportData() { SwapChain = nullptr; RTView = nullptr; } @@ -704,12 +711,12 @@ struct ImGui_ImplDX11_ViewportData // Multi-Viewports: configure templates used when creating swapchains for secondary viewports. Will try them in order. // This is intentionally not declared in the .h file yet, so you will need to copy this declaration: -void ImGui_ImplDX11_SetSwapChainDescs(const DXGI_SWAP_CHAIN_DESC* desc_templates, int desc_templates_count); -void ImGui_ImplDX11_SetSwapChainDescs(const DXGI_SWAP_CHAIN_DESC* desc_templates, int desc_templates_count) +void ImGui_ImplDX11_SetSwapChainDescs(const DXGI_SWAP_CHAIN_DESC1* desc_templates, int desc_templates_count); +void ImGui_ImplDX11_SetSwapChainDescs(const DXGI_SWAP_CHAIN_DESC1* desc_templates, int desc_templates_count) { ImGui_ImplDX11_Data* bd = ImGui_ImplDX11_GetBackendData(); bd->SwapChainDescsForViewports.resize(desc_templates_count); - memcpy(bd->SwapChainDescsForViewports.Data, desc_templates, sizeof(DXGI_SWAP_CHAIN_DESC)); + memcpy(bd->SwapChainDescsForViewports.Data, desc_templates, sizeof(DXGI_SWAP_CHAIN_DESC1)); } static void ImGui_ImplDX11_CreateWindow(ImGuiViewport* viewport) @@ -726,14 +733,17 @@ static void ImGui_ImplDX11_CreateWindow(ImGuiViewport* viewport) // Create swap chain HRESULT hr = DXGI_ERROR_UNSUPPORTED; - for (const DXGI_SWAP_CHAIN_DESC& sd_template : bd->SwapChainDescsForViewports) + for (const DXGI_SWAP_CHAIN_DESC1& sd_template : bd->SwapChainDescsForViewports) { - IM_ASSERT(sd_template.BufferDesc.Width == 0 && sd_template.BufferDesc.Height == 0 && sd_template.OutputWindow == nullptr); - DXGI_SWAP_CHAIN_DESC sd = sd_template; - sd.BufferDesc.Width = (UINT)viewport->Size.x; - sd.BufferDesc.Height = (UINT)viewport->Size.y; - sd.OutputWindow = hwnd; - hr = bd->pFactory->CreateSwapChain(bd->pd3dDevice, &sd, &vd->SwapChain); + IM_ASSERT(sd_template.Width == 0 && sd_template.Height == 0); + DXGI_SWAP_CHAIN_DESC1 sd = sd_template; + sd.Width = (UINT)viewport->Size.x; + sd.Height = (UINT)viewport->Size.y; + + if (bd->tearingSupport) + sd.Flags |= DXGI_SWAP_CHAIN_FLAG_ALLOW_TEARING; + + hr = bd->pFactory->CreateSwapChainForHwnd(bd->pd3dDevice, hwnd, &sd, nullptr, nullptr, &vd->SwapChain); if (SUCCEEDED(hr)) break; } @@ -778,7 +788,9 @@ static void ImGui_ImplDX11_SetWindowSize(ImGuiViewport* viewport, ImVec2 size) if (vd->SwapChain) { ID3D11Texture2D* pBackBuffer = nullptr; - vd->SwapChain->ResizeBuffers(0, (UINT)size.x, (UINT)size.y, DXGI_FORMAT_UNKNOWN, 0); + DXGI_SWAP_CHAIN_DESC1 desc = {}; + vd->SwapChain->GetDesc1(&desc); + vd->SwapChain->ResizeBuffers(0, (UINT)size.x, (UINT)size.y, DXGI_FORMAT_UNKNOWN, desc.Flags); vd->SwapChain->GetBuffer(0, IID_PPV_ARGS(&pBackBuffer)); if (pBackBuffer == nullptr) { fprintf(stderr, "ImGui_ImplDX11_SetWindowSize() failed creating buffers.\n"); return; } bd->pd3dDevice->CreateRenderTargetView(pBackBuffer, nullptr, &vd->RTView); @@ -799,9 +811,10 @@ static void ImGui_ImplDX11_RenderWindow(ImGuiViewport* viewport, void*) static void ImGui_ImplDX11_SwapBuffers(ImGuiViewport* viewport, void*) { + ImGui_ImplDX11_Data* bd = ImGui_ImplDX11_GetBackendData(); ImGui_ImplDX11_ViewportData* vd = (ImGui_ImplDX11_ViewportData*)viewport->RendererUserData; if (vd->SwapChain) - vd->SwapChain->Present(0, 0); // Present without vsync + vd->SwapChain->Present(0, bd->tearingSupport ? DXGI_PRESENT_ALLOW_TEARING : 0); // Present without vsync } static void ImGui_ImplDX11_InitMultiViewportSupport() @@ -814,14 +827,13 @@ static void ImGui_ImplDX11_InitMultiViewportSupport() platform_io.Renderer_SwapBuffers = ImGui_ImplDX11_SwapBuffers; // Default swapchain format - DXGI_SWAP_CHAIN_DESC sd; + DXGI_SWAP_CHAIN_DESC1 sd; ZeroMemory(&sd, sizeof(sd)); - sd.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; + sd.Format = DXGI_FORMAT_R8G8B8A8_UNORM; sd.SampleDesc.Count = 1; sd.SampleDesc.Quality = 0; sd.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; sd.BufferCount = 2; - sd.Windowed = TRUE; sd.SwapEffect = DXGI_SWAP_EFFECT_FLIP_DISCARD; sd.Flags = 0; ImGui_ImplDX11_SetSwapChainDescs(&sd, 1); diff --git a/examples/example_win32_directx11/main.cpp b/examples/example_win32_directx11/main.cpp index 95dd3a9f5..3578d84b1 100644 --- a/examples/example_win32_directx11/main.cpp +++ b/examples/example_win32_directx11/main.cpp @@ -10,12 +10,14 @@ #include "imgui_impl_win32.h" #include "imgui_impl_dx11.h" #include +#include #include // Data static ID3D11Device* g_pd3dDevice = nullptr; static ID3D11DeviceContext* g_pd3dDeviceContext = nullptr; -static IDXGISwapChain* g_pSwapChain = nullptr; +static IDXGISwapChain1* g_pSwapChain = nullptr; +static bool g_SwapChainTearingSupport = false; static bool g_SwapChainOccluded = false; static UINT g_ResizeWidth = 0, g_ResizeHeight = 0; static ID3D11RenderTargetView* g_mainRenderTargetView = nullptr; @@ -136,7 +138,9 @@ int main(int, char**) if (g_ResizeWidth != 0 && g_ResizeHeight != 0) { CleanupRenderTarget(); - g_pSwapChain->ResizeBuffers(0, g_ResizeWidth, g_ResizeHeight, DXGI_FORMAT_UNKNOWN, 0); + DXGI_SWAP_CHAIN_DESC1 desc = {}; + g_pSwapChain->GetDesc1(&desc); + g_pSwapChain->ResizeBuffers(0, g_ResizeWidth, g_ResizeHeight, DXGI_FORMAT_UNKNOWN, desc.Flags); g_ResizeWidth = g_ResizeHeight = 0; CreateRenderTarget(); } @@ -199,7 +203,7 @@ int main(int, char**) // Present HRESULT hr = g_pSwapChain->Present(1, 0); // Present with vsync - //HRESULT hr = g_pSwapChain->Present(0, 0); // Present without vsync + //HRESULT hr = g_pSwapChain->Present(0, g_SwapChainTearingSupport ? DXGI_PRESENT_ALLOW_TEARING : 0); // Present without vsync g_SwapChainOccluded = (hr == DXGI_STATUS_OCCLUDED); } @@ -218,42 +222,58 @@ int main(int, char**) // Helper functions bool CreateDeviceD3D(HWND hWnd) { - // Setup swap chain - DXGI_SWAP_CHAIN_DESC sd; - ZeroMemory(&sd, sizeof(sd)); - sd.BufferCount = 2; - sd.BufferDesc.Width = 0; - sd.BufferDesc.Height = 0; - sd.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; - sd.BufferDesc.RefreshRate.Numerator = 60; - sd.BufferDesc.RefreshRate.Denominator = 1; - sd.Flags = DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH; - sd.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; - sd.OutputWindow = hWnd; - sd.SampleDesc.Count = 1; - sd.SampleDesc.Quality = 0; - sd.Windowed = TRUE; - sd.SwapEffect = DXGI_SWAP_EFFECT_FLIP_DISCARD; - UINT createDeviceFlags = 0; //createDeviceFlags |= D3D11_CREATE_DEVICE_DEBUG; D3D_FEATURE_LEVEL featureLevel; const D3D_FEATURE_LEVEL featureLevelArray[2] = { D3D_FEATURE_LEVEL_11_0, D3D_FEATURE_LEVEL_10_0, }; - HRESULT res = D3D11CreateDeviceAndSwapChain(nullptr, D3D_DRIVER_TYPE_HARDWARE, nullptr, createDeviceFlags, featureLevelArray, 2, D3D11_SDK_VERSION, &sd, &g_pSwapChain, &g_pd3dDevice, &featureLevel, &g_pd3dDeviceContext); + HRESULT res = D3D11CreateDevice(nullptr, D3D_DRIVER_TYPE_HARDWARE, nullptr, createDeviceFlags, featureLevelArray, 2, D3D11_SDK_VERSION, &g_pd3dDevice, &featureLevel, &g_pd3dDeviceContext); if (res == DXGI_ERROR_UNSUPPORTED) // Try high-performance WARP software driver if hardware is not available. - res = D3D11CreateDeviceAndSwapChain(nullptr, D3D_DRIVER_TYPE_WARP, nullptr, createDeviceFlags, featureLevelArray, 2, D3D11_SDK_VERSION, &sd, &g_pSwapChain, &g_pd3dDevice, &featureLevel, &g_pd3dDeviceContext); + res = D3D11CreateDevice(nullptr, D3D_DRIVER_TYPE_HARDWARE, nullptr, createDeviceFlags, featureLevelArray, 2, D3D11_SDK_VERSION, &g_pd3dDevice, &featureLevel, &g_pd3dDeviceContext); + if (res != S_OK) + return false; + + IDXGIDevice* pDXGIDevice = nullptr; + IDXGIAdapter* pDXGIAdapter = nullptr; + IDXGIFactory5* pIDXGIFactory = nullptr; + + if (g_pd3dDevice->QueryInterface(IID_PPV_ARGS(&pDXGIDevice)) == S_OK) + if (pDXGIDevice->GetParent(IID_PPV_ARGS(&pDXGIAdapter)) == S_OK) + res = pDXGIAdapter->GetParent(IID_PPV_ARGS(&pIDXGIFactory)); + + if (pDXGIDevice) pDXGIDevice->Release(); + if (pDXGIAdapter) pDXGIAdapter->Release(); + + if (pIDXGIFactory == nullptr || res != S_OK) + return false; + + // Setup swap chain + DXGI_SWAP_CHAIN_DESC1 sd; + ZeroMemory(&sd, sizeof(sd)); + sd.BufferCount = 2; + sd.Width = 0; + sd.Height = 0; + sd.Format = DXGI_FORMAT_R8G8B8A8_UNORM; + sd.Flags = DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH; + sd.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; + sd.SampleDesc.Count = 1; + sd.SampleDesc.Quality = 0; + sd.SwapEffect = DXGI_SWAP_EFFECT_FLIP_DISCARD; + + BOOL allow_tearing = FALSE; + pIDXGIFactory->CheckFeatureSupport(DXGI_FEATURE_PRESENT_ALLOW_TEARING, &allow_tearing, sizeof(allow_tearing)); + g_SwapChainTearingSupport = (allow_tearing == TRUE); + if (g_SwapChainTearingSupport) + sd.Flags |= DXGI_SWAP_CHAIN_FLAG_ALLOW_TEARING; + + res = pIDXGIFactory->CreateSwapChainForHwnd(g_pd3dDevice, hWnd, &sd, nullptr, nullptr, &g_pSwapChain); if (res != S_OK) return false; // Disable DXGI's default Alt+Enter fullscreen behavior. // - You are free to leave this enabled, but it will not work properly with multiple viewports. // - This must be done for all windows associated to the device. Our DX11 backend does this automatically for secondary viewports that it creates. - IDXGIFactory* pSwapChainFactory; - if (SUCCEEDED(g_pSwapChain->GetParent(IID_PPV_ARGS(&pSwapChainFactory)))) - { - pSwapChainFactory->MakeWindowAssociation(hWnd, DXGI_MWA_NO_ALT_ENTER); - pSwapChainFactory->Release(); - } + pIDXGIFactory->MakeWindowAssociation(hWnd, DXGI_MWA_NO_ALT_ENTER); + pIDXGIFactory->Release(); CreateRenderTarget(); return true;