Use DComp surface handle for Swap Chain management (#10023)

## Summary of the Pull Request

This PR changes the DxEngine to create a swapchain HANDLE, then have the TermControl attach _that_ handle to the SwapChainPanel, rather than returning the swapchain via a `IDXGISwapChain1`.

I didn't write this code originally, @miniksa helped me out. The original commit was so succinct that I didn't think there was anything else to add or take away.

I'm going to need this for tear-out (#1256), so that I can have the content process create swap chain handles, then duplicate those handles out to the window process that will end up embedding the content.

## References

* [`DCompositionCreateSurfaceHandle`](https://docs.microsoft.com/en-us/windows/win32/api/dcomp/nf-dcomp-dcompositioncreatesurfacehandle)
* [`CreateSwapChainForCompositionSurfaceHandle`](https://docs.microsoft.com/en-us/windows/win32/api/dxgi1_3/nf-dxgi1_3-idxgifactorymedia-createswapchainforcompositionsurfacehandle)
* [`CreateSwapChainForComposition`](https://docs.microsoft.com/en-us/windows/win32/api/dxgi1_2/nf-dxgi1_2-idxgifactory2-createswapchainforcomposition)
* Tear-out: #1256
* Megathread: #5000
* Project: https://github.com/microsoft/terminal/projects/5

## PR Checklist
* [x] Closes https://github.com/microsoft/terminal/projects/5#card-50760249
* [x] I work here
* [ ] Tests added/passed
* [n/a] Requires documentation to be updated

## Detailed Description of the Pull Request / Additional comments

This reverts commit c113b65d9b.

That commit reverted 30b8335479

## Validation Steps Performed

* [x] Built and ran the Terminal, it still seems to work
* [x] Does a TDR still work? or do we need to recreate the handle, or something.
* [x] Does this work on Win7? I honestly have no idea how DX compatibility works. Presumably, the WPF version uses the `ForHwnd` path, so this will still work, but I don't know if this will suddenly fail to launch on Win7 or something. Tagging in @miniksa.
This commit is contained in:
Mike Griese 2021-05-12 11:54:17 -05:00 committed by GitHub
parent e0bd76b30d
commit 9f45963e73
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 57 additions and 20 deletions

View file

@ -1172,7 +1172,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
}
}
IDXGISwapChain1* ControlCore::GetSwapChain() const
HANDLE ControlCore::GetSwapChainHandle() const
{
// This is called by:
// * TermControl::RenderEngineSwapChainChanged, who is only registered
@ -1180,7 +1180,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
// * TermControl::_InitializeTerminal, after the call to Initialize, for
// _AttachDxgiSwapChainToXaml.
// In both cases, we'll have a _renderEngine by then.
return _renderEngine->GetSwapChain().Get();
return _renderEngine->GetSwapChainHandle();
}
void ControlCore::_rendererWarning(const HRESULT hr)

View file

@ -49,7 +49,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
void UpdateAppearance(const IControlAppearance& newAppearance);
void SizeChanged(const double width, const double height);
void ScaleChanged(const double scale);
IDXGISwapChain1* GetSwapChain() const;
HANDLE GetSwapChainHandle() const;
void AdjustFontSize(int fontSizeDelta);
void ResetFontSize();

View file

@ -578,8 +578,8 @@ namespace winrt::Microsoft::Terminal::Control::implementation
if (auto control{ weakThis.get() })
{
const auto chain = control->_core->GetSwapChain();
_AttachDxgiSwapChainToXaml(chain);
const auto chainHandle = _core->GetSwapChainHandle();
_AttachDxgiSwapChainToXaml(chainHandle);
}
}
@ -625,10 +625,10 @@ namespace winrt::Microsoft::Terminal::Control::implementation
}
}
void TermControl::_AttachDxgiSwapChainToXaml(IDXGISwapChain1* swapChain)
void TermControl::_AttachDxgiSwapChainToXaml(HANDLE swapChainHandle)
{
auto nativePanel = SwapChainPanel().as<ISwapChainPanelNative>();
nativePanel->SetSwapChain(swapChain);
auto nativePanel = SwapChainPanel().as<ISwapChainPanelNative2>();
nativePanel->SetSwapChainHandle(swapChainHandle);
}
bool TermControl::_InitializeTerminal()
@ -666,7 +666,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
}
_interactivity->Initialize();
_AttachDxgiSwapChainToXaml(_core->GetSwapChain());
_AttachDxgiSwapChainToXaml(_core->GetSwapChainHandle());
// Tell the DX Engine to notify us when the swap chain changes. We do
// this after we initially set the swapchain so as to avoid unnecessary

View file

@ -66,7 +66,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
void ToggleShaderEffects();
winrt::fire_and_forget RenderEngineSwapChainChanged(IInspectable sender, IInspectable args);
void _AttachDxgiSwapChainToXaml(IDXGISwapChain1* swapChain);
void _AttachDxgiSwapChainToXaml(HANDLE swapChainHandle);
winrt::fire_and_forget _RendererEnteredErrorState(IInspectable sender, IInspectable args);
void _RenderRetryButton_Click(IInspectable const& button, IInspectable const& args);

View file

@ -79,6 +79,7 @@ DxEngine::DxEngine() :
_backgroundColor{ 0 },
_selectionBackground{},
_haveDeviceResources{ false },
_swapChainHandle{ INVALID_HANDLE_VALUE },
_swapChainDesc{ 0 },
_swapChainFrameLatencyWaitableObject{ INVALID_HANDLE_VALUE },
_recreateDeviceRequested{ false },
@ -478,6 +479,29 @@ void DxEngine::_ComputePixelShaderSettings() noexcept
}
}
// Method Description:
// - Use DCompositionCreateSurfaceHandle to create a swapchain handle. This API
// is only present in Windows 8.1+, so we need to delay-load it to make sure
// we can still load on Windows 7.
// - We can't actually hit this on Windows 7, because only the WPF control uses
// us on Windows 7, and they're using the ForHwnd path, which doesn't hit this
// at all.
// Arguments:
// - <none>
// Return Value:
// - An HRESULT for failing to load dcomp.dll, or failing to find the API, or an
// actual failure from the API itself.
[[nodiscard]] HRESULT DxEngine::_CreateSurfaceHandle() noexcept
{
wil::unique_hmodule hDComp{ LoadLibraryEx(L"Dcomp.dll", nullptr, LOAD_LIBRARY_SEARCH_SYSTEM32) };
RETURN_LAST_ERROR_IF(hDComp.get() == nullptr);
auto fn = GetProcAddressByFunctionDeclaration(hDComp.get(), DCompositionCreateSurfaceHandle);
RETURN_LAST_ERROR_IF(fn == nullptr);
return fn(GENERIC_ALL, nullptr, &_swapChainHandle);
}
// Routine Description;
// - Creates device-specific resources required for drawing
// which generally means those that are represented on the GPU and can
@ -618,6 +642,13 @@ try
}
case SwapChainMode::ForComposition:
{
if (!_swapChainHandle)
{
RETURN_IF_FAILED(_CreateSurfaceHandle());
}
RETURN_IF_FAILED(_dxgiFactory2.As(&_dxgiFactoryMedia));
// Use the given target size for compositions.
_swapChainDesc.Width = _displaySizePixels.width<UINT>();
_swapChainDesc.Height = _displaySizePixels.height<UINT>();
@ -627,10 +658,11 @@ try
// It's 100% required to use scaling mode stretch for composition. There is no other choice.
_swapChainDesc.Scaling = DXGI_SCALING_STRETCH;
RETURN_IF_FAILED(_dxgiFactory2->CreateSwapChainForComposition(_d3dDevice.Get(),
&_swapChainDesc,
nullptr,
&_dxgiSwapChain));
RETURN_IF_FAILED(_dxgiFactoryMedia->CreateSwapChainForCompositionSurfaceHandle(_d3dDevice.Get(),
_swapChainHandle.get(),
&_swapChainDesc,
nullptr,
&_dxgiSwapChain));
break;
}
default:
@ -1003,14 +1035,14 @@ try
}
CATCH_LOG()
Microsoft::WRL::ComPtr<IDXGISwapChain1> DxEngine::GetSwapChain()
HANDLE DxEngine::GetSwapChainHandle()
{
if (_dxgiSwapChain.Get() == nullptr)
if (!_swapChainHandle)
{
THROW_IF_FAILED(_CreateDeviceResources(true));
}
return _dxgiSwapChain;
return _swapChainHandle.get();
}
void DxEngine::_InvalidateRectangle(const til::rectangle& rc)

View file

@ -70,7 +70,7 @@ namespace Microsoft::Console::Render
void SetSoftwareRendering(bool enable) noexcept;
::Microsoft::WRL::ComPtr<IDXGISwapChain1> GetSwapChain();
HANDLE GetSwapChainHandle();
// IRenderEngine Members
[[nodiscard]] HRESULT Invalidate(const SMALL_RECT* const psrRegion) noexcept override;
@ -128,8 +128,6 @@ namespace Microsoft::Console::Render
void SetAntialiasingMode(const D2D1_TEXT_ANTIALIAS_MODE antialiasingMode) noexcept;
void SetDefaultTextBackgroundOpacity(const float opacity) noexcept;
wil::unique_handle _swapChainHandle;
void UpdateHyperlinkHoveredId(const uint16_t hoveredId) noexcept;
protected:
@ -184,6 +182,8 @@ namespace Microsoft::Console::Render
static std::atomic<size_t> _tracelogCount;
wil::unique_handle _swapChainHandle;
// Device-Independent Resources
::Microsoft::WRL::ComPtr<ID2D1Factory1> _d2dFactory;
@ -212,6 +212,7 @@ namespace Microsoft::Console::Render
::Microsoft::WRL::ComPtr<ID2D1SolidColorBrush> _d2dBrushBackground;
::Microsoft::WRL::ComPtr<IDXGIFactory2> _dxgiFactory2;
::Microsoft::WRL::ComPtr<IDXGIFactoryMedia> _dxgiFactoryMedia;
::Microsoft::WRL::ComPtr<IDXGIDevice> _dxgiDevice;
::Microsoft::WRL::ComPtr<IDXGISurface> _dxgiSurface;
@ -270,6 +271,8 @@ namespace Microsoft::Console::Render
} _pixelShaderSettings;
[[nodiscard]] HRESULT _CreateDeviceResources(const bool createSwapChain) noexcept;
[[nodiscard]] HRESULT _CreateSurfaceHandle() noexcept;
bool _HasTerminalEffects() const noexcept;
std::string _LoadPixelShaderFile() const;
HRESULT _SetupTerminalEffects();

View file

@ -21,6 +21,8 @@
#include <typeinfo>
#include <stdexcept>
#include <dcomp.h>
#include <dxgi.h>
#include <dxgi1_2.h>
#include <dxgi1_3.h>