xref: /aosp_15_r20/external/angle/src/libANGLE/renderer/d3d/d3d11/winrt/CoreWindowNativeWindow.cpp (revision 8975f5c5ed3d1c378011245431ada316dfb6f244)
1 //
2 // Copyright 2014 The ANGLE Project Authors. All rights reserved.
3 // Use of this source code is governed by a BSD-style license that can be
4 // found in the LICENSE file.
5 //
6 
7 // CoreWindowNativeWindow.cpp: NativeWindow for managing ICoreWindow native window types.
8 
9 #include "libANGLE/renderer/d3d/d3d11/winrt/CoreWindowNativeWindow.h"
10 
11 #include <windows.graphics.display.h>
12 
13 using namespace ABI::Windows::Foundation::Collections;
14 
15 namespace rx
16 {
~CoreWindowNativeWindow()17 CoreWindowNativeWindow::~CoreWindowNativeWindow()
18 {
19     unregisterForSizeChangeEvents();
20 }
21 
initialize(EGLNativeWindowType window,IPropertySet * propertySet)22 bool CoreWindowNativeWindow::initialize(EGLNativeWindowType window, IPropertySet *propertySet)
23 {
24     ComPtr<IPropertySet> props = propertySet;
25     ComPtr<IInspectable> win   = reinterpret_cast<IInspectable *>(window);
26     SIZE swapChainSize         = {};
27     HRESULT result             = S_OK;
28 
29     // IPropertySet is an optional parameter and can be null.
30     // If one is specified, cache as an IMap and read the properties
31     // used for initial host initialization.
32     if (propertySet)
33     {
34         result = props.As(&mPropertyMap);
35         if (FAILED(result))
36         {
37             return false;
38         }
39 
40         // The EGLRenderSurfaceSizeProperty is optional and may be missing. The IPropertySet
41         // was prevalidated to contain the EGLNativeWindowType before being passed to
42         // this host.
43         result = GetOptionalSizePropertyValue(mPropertyMap, EGLRenderSurfaceSizeProperty,
44                                               &swapChainSize, &mSwapChainSizeSpecified);
45         if (FAILED(result))
46         {
47             return false;
48         }
49 
50         // The EGLRenderResolutionScaleProperty is optional and may be missing. The IPropertySet
51         // was prevalidated to contain the EGLNativeWindowType before being passed to
52         // this host.
53         result = GetOptionalSinglePropertyValue(mPropertyMap, EGLRenderResolutionScaleProperty,
54                                                 &mSwapChainScale, &mSwapChainScaleSpecified);
55         if (FAILED(result))
56         {
57             return false;
58         }
59 
60         if (!mSwapChainScaleSpecified)
61         {
62             // Default value for the scale is 1.0f
63             mSwapChainScale = 1.0f;
64         }
65 
66         // A EGLRenderSurfaceSizeProperty and a EGLRenderResolutionScaleProperty can't both be
67         // specified
68         if (mSwapChainScaleSpecified && mSwapChainSizeSpecified)
69         {
70             ERR() << "It is invalid to specify both an EGLRenderSurfaceSizeProperty and a "
71                      "EGLRenderResolutionScaleProperty.";
72             return false;
73         }
74     }
75 
76     if (SUCCEEDED(result))
77     {
78         result = win.As(&mCoreWindow);
79     }
80 
81     if (SUCCEEDED(result))
82     {
83         // If a swapchain size is specfied, then the automatic resize
84         // behaviors implemented by the host should be disabled.  The swapchain
85         // will be still be scaled when being rendered to fit the bounds
86         // of the host.
87         // Scaling of the swapchain output occurs automatically because if
88         // the scaling mode setting DXGI_SCALING_STRETCH on the swapchain.
89         if (mSwapChainSizeSpecified)
90         {
91             mClientRect = {0, 0, swapChainSize.cx, swapChainSize.cy};
92         }
93         else
94         {
95             Size coreWindowSize;
96             result = GetCoreWindowSizeInPixels(mCoreWindow, &coreWindowSize);
97 
98             if (SUCCEEDED(result))
99             {
100                 mClientRect = clientRect(coreWindowSize);
101             }
102         }
103     }
104 
105     if (SUCCEEDED(result))
106     {
107         mNewClientRect     = mClientRect;
108         mClientRectChanged = false;
109         return registerForSizeChangeEvents();
110     }
111 
112     return false;
113 }
114 
registerForSizeChangeEvents()115 bool CoreWindowNativeWindow::registerForSizeChangeEvents()
116 {
117     ComPtr<IWindowSizeChangedEventHandler> sizeChangedHandler;
118     HRESULT result = Microsoft::WRL::MakeAndInitialize<CoreWindowSizeChangedHandler>(
119         sizeChangedHandler.ReleaseAndGetAddressOf(), this->shared_from_this());
120     if (SUCCEEDED(result))
121     {
122         result = mCoreWindow->add_SizeChanged(sizeChangedHandler.Get(), &mSizeChangedEventToken);
123     }
124 
125     if (SUCCEEDED(result))
126     {
127         return true;
128     }
129 
130     return false;
131 }
132 
unregisterForSizeChangeEvents()133 void CoreWindowNativeWindow::unregisterForSizeChangeEvents()
134 {
135     if (mCoreWindow)
136     {
137         (void)mCoreWindow->remove_SizeChanged(mSizeChangedEventToken);
138     }
139     mSizeChangedEventToken.value = 0;
140 }
141 
createSwapChain(ID3D11Device * device,IDXGIFactory2 * factory,DXGI_FORMAT format,unsigned int width,unsigned int height,bool containsAlpha,IDXGISwapChain1 ** swapChain)142 HRESULT CoreWindowNativeWindow::createSwapChain(ID3D11Device *device,
143                                                 IDXGIFactory2 *factory,
144                                                 DXGI_FORMAT format,
145                                                 unsigned int width,
146                                                 unsigned int height,
147                                                 bool containsAlpha,
148                                                 IDXGISwapChain1 **swapChain)
149 {
150     if (device == nullptr || factory == nullptr || swapChain == nullptr || width == 0 ||
151         height == 0)
152     {
153         return E_INVALIDARG;
154     }
155 
156     DXGI_SWAP_CHAIN_DESC1 swapChainDesc = {0};
157     swapChainDesc.Width                 = width;
158     swapChainDesc.Height                = height;
159     swapChainDesc.Format                = format;
160     swapChainDesc.Stereo                = FALSE;
161     swapChainDesc.SampleDesc.Count      = 1;
162     swapChainDesc.SampleDesc.Quality    = 0;
163     swapChainDesc.BufferUsage =
164         DXGI_USAGE_SHADER_INPUT | DXGI_USAGE_RENDER_TARGET_OUTPUT | DXGI_USAGE_BACK_BUFFER;
165     swapChainDesc.BufferCount = 2;
166     swapChainDesc.SwapEffect  = DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL;
167     swapChainDesc.Scaling     = DXGI_SCALING_STRETCH;
168     swapChainDesc.AlphaMode   = DXGI_ALPHA_MODE_UNSPECIFIED;
169 
170     *swapChain = nullptr;
171 
172     ComPtr<IDXGISwapChain1> newSwapChain;
173     HRESULT result = factory->CreateSwapChainForCoreWindow(
174         device, mCoreWindow.Get(), &swapChainDesc, nullptr, newSwapChain.ReleaseAndGetAddressOf());
175     if (SUCCEEDED(result))
176     {
177         result = newSwapChain.CopyTo(swapChain);
178     }
179 
180     if (SUCCEEDED(result))
181     {
182         // If automatic swapchain resize behaviors have been disabled, then
183         // unregister for the resize change events.
184         if (mSupportsSwapChainResize == false)
185         {
186             unregisterForSizeChangeEvents();
187         }
188     }
189 
190     return result;
191 }
192 
scaleSwapChain(const Size & windowSize,const RECT & clientRect)193 inline HRESULT CoreWindowNativeWindow::scaleSwapChain(const Size &windowSize,
194                                                       const RECT &clientRect)
195 {
196     // We don't need to do any additional work to scale CoreWindow swapchains.
197     // Using DXGI_SCALING_STRETCH to create the swapchain above does all the necessary work.
198     return S_OK;
199 }
200 
GetCoreWindowSizeInPixels(const ComPtr<ABI::Windows::UI::Core::ICoreWindow> & coreWindow,Size * windowSize)201 HRESULT GetCoreWindowSizeInPixels(const ComPtr<ABI::Windows::UI::Core::ICoreWindow> &coreWindow,
202                                   Size *windowSize)
203 {
204     ABI::Windows::Foundation::Rect bounds;
205     HRESULT result = coreWindow->get_Bounds(&bounds);
206     if (SUCCEEDED(result))
207     {
208         *windowSize = {ConvertDipsToPixels(bounds.Width), ConvertDipsToPixels(bounds.Height)};
209     }
210 
211     return result;
212 }
213 
GetLogicalDpi()214 static float GetLogicalDpi()
215 {
216     ComPtr<ABI::Windows::Graphics::Display::IDisplayInformationStatics> displayInformationStatics;
217     ComPtr<ABI::Windows::Graphics::Display::IDisplayInformation> displayInformation;
218 
219     if (SUCCEEDED(GetActivationFactory(
220             HStringReference(RuntimeClass_Windows_Graphics_Display_DisplayInformation).Get(),
221             displayInformationStatics.GetAddressOf())))
222     {
223         if (SUCCEEDED(displayInformationStatics->GetForCurrentView(&displayInformation)))
224         {
225             float dpi = 96.0f;
226             if (SUCCEEDED(displayInformation->get_LogicalDpi(&dpi)))
227             {
228                 return dpi;
229             }
230         }
231     }
232 
233     // Return 96 dpi as a default if display properties cannot be obtained.
234     return 96.0f;
235 }
236 
ConvertDipsToPixels(float dips)237 float ConvertDipsToPixels(float dips)
238 {
239     static const float dipsPerInch = 96.0f;
240     return dips * GetLogicalDpi() / dipsPerInch;
241 }
242 }  // namespace rx
243