зеркало из https://github.com/AvaloniaUI/angle.git
For WinRT, add EGLRenderSurfaceScaleProperty to specify swapchain scaling factor
Change-Id: Iede6682306082346cf2a3a55fe58f732b7a453df Reviewed-on: https://chromium-review.googlesource.com/277931 Tested-by: Austin Kinross <aukinros@microsoft.com> Reviewed-by: Jamie Madill <jmadill@chromium.org>
This commit is contained in:
Родитель
ce39f6ff93
Коммит
da0564680b
|
@ -28,10 +28,24 @@ const wchar_t EGLNativeWindowTypeProperty[] = L"EGLNativeWindowTypeProperty";
|
|||
// Description: Set this property to specify a preferred size in pixels of the render surface.
|
||||
// The render surface size width and height must be greater than 0.
|
||||
// If this property is set, then the render surface size is fixed.
|
||||
// The render surface will then be scaled to the window dimensions.
|
||||
// If this property is missing, a default behavior will be provided.
|
||||
// The default behavior uses the window size if a CoreWindow is specified or
|
||||
// the size of the SwapChainPanel control if one is specified.
|
||||
//
|
||||
const wchar_t EGLRenderSurfaceSizeProperty[] = L"EGLRenderSurfaceSizeProperty";
|
||||
|
||||
//
|
||||
// Property: EGLRenderResolutionScaleProperty
|
||||
// Type: Single
|
||||
// Description: Use this to specify a preferred scale for the render surface compared to the window.
|
||||
// For example, if the window is 800x480, and:
|
||||
// - scale is set to 0.5f then the surface will be 400x240
|
||||
// - scale is set to 1.2f then the surface will be 960x576
|
||||
// If the window resizes or rotates then the surface will resize accordingly.
|
||||
// EGLRenderResolutionScaleProperty and EGLRenderSurfaceSizeProperty cannot both be set.
|
||||
// The scale factor should be > 0.0f.
|
||||
//
|
||||
const wchar_t EGLRenderResolutionScaleProperty[] = L"EGLRenderResolutionScaleProperty";
|
||||
|
||||
#endif // ANGLE_WINDOWSSTORE_H_
|
||||
|
|
|
@ -24,7 +24,6 @@ bool CoreWindowNativeWindow::initialize(EGLNativeWindowType window, IPropertySet
|
|||
ComPtr<IPropertySet> props = propertySet;
|
||||
ComPtr<IInspectable> win = window;
|
||||
SIZE swapChainSize = {};
|
||||
bool swapChainSizeSpecified = false;
|
||||
HRESULT result = S_OK;
|
||||
|
||||
// IPropertySet is an optional parameter and can be null.
|
||||
|
@ -33,12 +32,40 @@ bool CoreWindowNativeWindow::initialize(EGLNativeWindowType window, IPropertySet
|
|||
if (propertySet)
|
||||
{
|
||||
result = props.As(&mPropertyMap);
|
||||
if (SUCCEEDED(result))
|
||||
if (FAILED(result))
|
||||
{
|
||||
// The EGLRenderSurfaceSizeProperty is optional and may be missing. The IPropertySet
|
||||
// was prevalidated to contain the EGLNativeWindowType before being passed to
|
||||
// this host.
|
||||
result = GetOptionalSizePropertyValue(mPropertyMap, EGLRenderSurfaceSizeProperty, &swapChainSize, &swapChainSizeSpecified);
|
||||
return false;
|
||||
}
|
||||
|
||||
// The EGLRenderSurfaceSizeProperty is optional and may be missing. The IPropertySet
|
||||
// was prevalidated to contain the EGLNativeWindowType before being passed to
|
||||
// this host.
|
||||
result = GetOptionalSizePropertyValue(mPropertyMap, EGLRenderSurfaceSizeProperty, &swapChainSize, &mSwapChainSizeSpecified);
|
||||
if (FAILED(result))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// The EGLRenderResolutionScaleProperty is optional and may be missing. The IPropertySet
|
||||
// was prevalidated to contain the EGLNativeWindowType before being passed to
|
||||
// this host.
|
||||
result = GetOptionalSinglePropertyValue(mPropertyMap, EGLRenderResolutionScaleProperty, &mSwapChainScale, &mSwapChainScaleSpecified);
|
||||
if (FAILED(result))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!mSwapChainScaleSpecified)
|
||||
{
|
||||
// Default value for the scale is 1.0f
|
||||
mSwapChainScale = 1.0f;
|
||||
}
|
||||
|
||||
// A EGLRenderSurfaceSizeProperty and a EGLRenderResolutionScaleProperty can't both be specified
|
||||
if (mSwapChainScaleSpecified && mSwapChainSizeSpecified)
|
||||
{
|
||||
ERR("It is invalid to specify both an EGLRenderSurfaceSizeProperty and a EGLRenderResolutionScaleProperty.");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -55,14 +82,19 @@ bool CoreWindowNativeWindow::initialize(EGLNativeWindowType window, IPropertySet
|
|||
// of the host.
|
||||
// Scaling of the swapchain output occurs automatically because if
|
||||
// the scaling mode setting DXGI_SCALING_STRETCH on the swapchain.
|
||||
if (swapChainSizeSpecified)
|
||||
if (mSwapChainSizeSpecified)
|
||||
{
|
||||
mClientRect = { 0, 0, swapChainSize.cx, swapChainSize.cy };
|
||||
mSupportsSwapChainResize = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
result = GetCoreWindowSizeInPixels(mCoreWindow, &mClientRect);
|
||||
SIZE coreWindowSize;
|
||||
result = GetCoreWindowSizeInPixels(mCoreWindow, &coreWindowSize);
|
||||
|
||||
if (SUCCEEDED(result))
|
||||
{
|
||||
mClientRect = { 0, 0, static_cast<long>(coreWindowSize.cx * mSwapChainScale), static_cast<long>(coreWindowSize.cy * mSwapChainScale) };
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -154,13 +186,20 @@ HRESULT CoreWindowNativeWindow::createSwapChain(ID3D11Device *device, DXGIFactor
|
|||
return result;
|
||||
}
|
||||
|
||||
HRESULT GetCoreWindowSizeInPixels(const ComPtr<ABI::Windows::UI::Core::ICoreWindow>& coreWindow, RECT *windowSize)
|
||||
inline HRESULT CoreWindowNativeWindow::scaleSwapChain(const SIZE &windowSize, const RECT &clientRect)
|
||||
{
|
||||
// We don't need to do any additional work to scale CoreWindow swapchains.
|
||||
// Using DXGI_SCALING_STRETCH to create the swapchain above does all the necessary work.
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT GetCoreWindowSizeInPixels(const ComPtr<ABI::Windows::UI::Core::ICoreWindow>& coreWindow, SIZE *windowSize)
|
||||
{
|
||||
ABI::Windows::Foundation::Rect bounds;
|
||||
HRESULT result = coreWindow->get_Bounds(&bounds);
|
||||
if (SUCCEEDED(result))
|
||||
{
|
||||
*windowSize = { 0, 0, ConvertDipsToPixels(bounds.Width), ConvertDipsToPixels(bounds.Height) };
|
||||
*windowSize = { ConvertDipsToPixels(bounds.Width), ConvertDipsToPixels(bounds.Height) };
|
||||
}
|
||||
|
||||
return result;
|
||||
|
|
|
@ -24,10 +24,14 @@ class CoreWindowNativeWindow : public InspectableNativeWindow, public std::enabl
|
|||
public:
|
||||
~CoreWindowNativeWindow();
|
||||
|
||||
bool initialize(EGLNativeWindowType window, IPropertySet *propertySet);
|
||||
bool initialize(EGLNativeWindowType window, IPropertySet *propertySet) override;
|
||||
HRESULT createSwapChain(ID3D11Device *device, DXGIFactory *factory, DXGI_FORMAT format, unsigned int width, unsigned int height, DXGISwapChain **swapChain) override;
|
||||
|
||||
protected:
|
||||
HRESULT scaleSwapChain(const SIZE &windowSize, const RECT &clientRect) override;
|
||||
|
||||
bool registerForSizeChangeEvents();
|
||||
void unregisterForSizeChangeEvents();
|
||||
HRESULT createSwapChain(ID3D11Device *device, DXGIFactory *factory, DXGI_FORMAT format, unsigned int width, unsigned int height, DXGISwapChain **swapChain);
|
||||
|
||||
private:
|
||||
ComPtr<ABI::Windows::UI::Core::ICoreWindow> mCoreWindow;
|
||||
|
@ -72,7 +76,7 @@ class CoreWindowSizeChangedHandler :
|
|||
std::weak_ptr<InspectableNativeWindow> mHost;
|
||||
};
|
||||
|
||||
HRESULT GetCoreWindowSizeInPixels(const ComPtr<ABI::Windows::UI::Core::ICoreWindow>& coreWindow, RECT *windowSize);
|
||||
HRESULT GetCoreWindowSizeInPixels(const ComPtr<ABI::Windows::UI::Core::ICoreWindow>& coreWindow, SIZE *windowSize);
|
||||
}
|
||||
|
||||
#endif // LIBANGLE_RENDERER_D3D_D3D11_WINRT_COREWINDOWNATIVEWINDOW_H_
|
||||
|
|
|
@ -162,12 +162,35 @@ HRESULT CreatePropertyMap(IMap<HSTRING, IInspectable*>** propertyMap)
|
|||
return result;
|
||||
}
|
||||
|
||||
HRESULT CreatePropertyValueStatics(IPropertyValueStatics** propertyStatics)
|
||||
{
|
||||
ComPtr<IPropertyValueStatics> propertyValueStatics;
|
||||
HRESULT result = GetActivationFactory(HStringReference(RuntimeClass_Windows_Foundation_PropertyValue).Get(), &propertyValueStatics);
|
||||
EXPECT_HRESULT_SUCCEEDED(result);
|
||||
|
||||
result = propertyValueStatics.CopyTo(propertyStatics);
|
||||
EXPECT_HRESULT_SUCCEEDED(result);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
HRESULT SetInspectablePropertyValue(const ComPtr<IMap<HSTRING, IInspectable*>>& propertyMap, const wchar_t* propertyName, IInspectable* inspectable)
|
||||
{
|
||||
boolean propertyReplaced = false;
|
||||
return propertyMap->Insert(HStringReference(propertyName).Get(), inspectable, &propertyReplaced);
|
||||
}
|
||||
|
||||
void expectNativeWindowInitCalls(MockCoreWindow &coreWindow, bool expectBounds)
|
||||
{
|
||||
if (expectBounds)
|
||||
{
|
||||
EXPECT_CALL(coreWindow, get_Bounds(testing::_)).Times(1);
|
||||
}
|
||||
|
||||
EXPECT_CALL(coreWindow, add_SizeChanged(testing::_, testing::_)).Times(1);
|
||||
EXPECT_CALL(coreWindow, remove_SizeChanged(testing::_)).Times(1);
|
||||
}
|
||||
|
||||
TEST(NativeWindowTest, NativeWindowNull)
|
||||
{
|
||||
NativeWindow nativeWindow(nullptr);
|
||||
|
@ -191,9 +214,7 @@ TEST(NativeWindowTest, NativeWindowNotInspectable)
|
|||
TEST(NativeWindowTest, NativeWindowValidCoreWindow)
|
||||
{
|
||||
MockCoreWindow mockCoreWindow;
|
||||
EXPECT_CALL(mockCoreWindow, get_Bounds(testing::_)).Times(1);
|
||||
EXPECT_CALL(mockCoreWindow, add_SizeChanged(testing::_, testing::_)).Times(1);
|
||||
EXPECT_CALL(mockCoreWindow, remove_SizeChanged(testing::_)).Times(1);
|
||||
expectNativeWindowInitCalls(mockCoreWindow, true);
|
||||
NativeWindow nativeWindow(&mockCoreWindow);
|
||||
EXPECT_TRUE(nativeWindow.initialize());
|
||||
}
|
||||
|
@ -205,11 +226,12 @@ TEST(NativeWindowTest, NativeWindowValidCoreWindowInPropertySet)
|
|||
{
|
||||
MockCoreWindow mockCoreWindow;
|
||||
ComPtr<IMap<HSTRING, IInspectable*>> propertySet;
|
||||
EXPECT_CALL(mockCoreWindow, get_Bounds(testing::_)).Times(1);
|
||||
EXPECT_CALL(mockCoreWindow, add_SizeChanged(testing::_, testing::_)).Times(1);
|
||||
EXPECT_CALL(mockCoreWindow, remove_SizeChanged(testing::_)).Times(1);
|
||||
|
||||
// Add the CoreWindow to the property set
|
||||
EXPECT_HRESULT_SUCCEEDED(CreatePropertyMap(&propertySet));
|
||||
EXPECT_HRESULT_SUCCEEDED(SetInspectablePropertyValue(propertySet, EGLNativeWindowTypeProperty, &mockCoreWindow));
|
||||
|
||||
expectNativeWindowInitCalls(mockCoreWindow, true);
|
||||
NativeWindow nativeWindow(propertySet.Get());
|
||||
EXPECT_TRUE(nativeWindow.initialize());
|
||||
}
|
||||
|
@ -223,11 +245,112 @@ TEST(NativeWindowTest, NativeWindowMissingCoreWindowInPropertySet)
|
|||
{
|
||||
MockCoreWindow mockCoreWindow;
|
||||
ComPtr<IMap<HSTRING, IInspectable*>> propertySet;
|
||||
|
||||
EXPECT_HRESULT_SUCCEEDED(CreatePropertyMap(&propertySet));
|
||||
|
||||
NativeWindow nativeWindow(propertySet.Get());
|
||||
EXPECT_FALSE(nativeWindow.initialize());
|
||||
}
|
||||
CoUninitialize();
|
||||
}
|
||||
|
||||
// Tests that the scale property works as expected in a property set with a SwapChainPanel
|
||||
class CoreWindowScaleTest : public testing::TestWithParam<std::pair<float, bool>>
|
||||
{
|
||||
};
|
||||
|
||||
TEST_P(CoreWindowScaleTest, ValidateScale)
|
||||
{
|
||||
float scale = GetParam().first;
|
||||
bool expectedResult = GetParam().second;
|
||||
|
||||
// COM is required to be initialized for creation of the property set
|
||||
EXPECT_HRESULT_SUCCEEDED(CoInitializeEx(NULL, COINIT_MULTITHREADED));
|
||||
{
|
||||
MockCoreWindow mockCoreWindow;
|
||||
ComPtr<IMap<HSTRING, IInspectable*>> propertySet;
|
||||
ComPtr<IPropertyValueStatics> propertyValueStatics;
|
||||
ComPtr<IPropertyValue> singleValue;
|
||||
|
||||
// Create a simple property set
|
||||
EXPECT_HRESULT_SUCCEEDED(CreatePropertyMap(&propertySet));
|
||||
EXPECT_HRESULT_SUCCEEDED(SetInspectablePropertyValue(propertySet, EGLNativeWindowTypeProperty, reinterpret_cast<IInspectable*>(&mockCoreWindow)));
|
||||
|
||||
// Add a valid scale factor to the property set
|
||||
EXPECT_HRESULT_SUCCEEDED(CreatePropertyValueStatics(propertyValueStatics.GetAddressOf()));
|
||||
propertyValueStatics->CreateSingle(scale, reinterpret_cast<IInspectable**>(singleValue.GetAddressOf()));
|
||||
EXPECT_HRESULT_SUCCEEDED(SetInspectablePropertyValue(propertySet, EGLRenderResolutionScaleProperty, reinterpret_cast<IInspectable*>(singleValue.Get())));
|
||||
|
||||
// Check native window init status and calls to the mock swapchainpanel
|
||||
NativeWindow nativeWindow(propertySet.Get());
|
||||
if (expectedResult)
|
||||
{
|
||||
expectNativeWindowInitCalls(mockCoreWindow, true);
|
||||
}
|
||||
|
||||
EXPECT_EQ(nativeWindow.initialize(), expectedResult);
|
||||
}
|
||||
CoUninitialize();
|
||||
}
|
||||
|
||||
typedef std::pair<float, bool> scaleValidPair;
|
||||
static const scaleValidPair scales[] = { scaleValidPair(1.0f, true),
|
||||
scaleValidPair(0.5f, true),
|
||||
scaleValidPair(0.0f, false),
|
||||
scaleValidPair(0.01f, true),
|
||||
scaleValidPair(2.00f, true) };
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(NativeWindowTest,
|
||||
CoreWindowScaleTest,
|
||||
testing::ValuesIn(scales));
|
||||
|
||||
// Tests that the size property works as expected in a property set with a SwapChainPanel
|
||||
class CoreWindowSizeTest : public testing::TestWithParam<std::tuple<float, float, bool>>
|
||||
{
|
||||
};
|
||||
|
||||
TEST_P(CoreWindowSizeTest, ValidateSize)
|
||||
{
|
||||
Size renderSize = { std::get<0>(GetParam()), std::get<1>(GetParam()) };
|
||||
bool expectedResult = std::get<2>(GetParam());
|
||||
|
||||
// COM is required to be initialized for creation of the property set
|
||||
EXPECT_HRESULT_SUCCEEDED(CoInitializeEx(NULL, COINIT_MULTITHREADED));
|
||||
{
|
||||
MockCoreWindow mockCoreWindow;
|
||||
ComPtr<IMap<HSTRING, IInspectable*>> propertySet;
|
||||
ComPtr<IPropertyValueStatics> propertyValueStatics;
|
||||
ComPtr<IPropertyValue> sizeValue;
|
||||
|
||||
// Create a simple property set
|
||||
EXPECT_HRESULT_SUCCEEDED(CreatePropertyMap(&propertySet));
|
||||
EXPECT_HRESULT_SUCCEEDED(SetInspectablePropertyValue(propertySet, EGLNativeWindowTypeProperty, reinterpret_cast<IInspectable*>(&mockCoreWindow)));
|
||||
|
||||
// Add a valid size to the property set
|
||||
EXPECT_HRESULT_SUCCEEDED(CreatePropertyValueStatics(propertyValueStatics.GetAddressOf()));
|
||||
propertyValueStatics->CreateSize(renderSize, reinterpret_cast<IInspectable**>(sizeValue.GetAddressOf()));
|
||||
EXPECT_HRESULT_SUCCEEDED(SetInspectablePropertyValue(propertySet, EGLRenderSurfaceSizeProperty, reinterpret_cast<IInspectable*>(sizeValue.Get())));
|
||||
|
||||
// Check native window init status and calls to the mock swapchainpanel
|
||||
NativeWindow nativeWindow(propertySet.Get());
|
||||
if (expectedResult)
|
||||
{
|
||||
expectNativeWindowInitCalls(mockCoreWindow, false);
|
||||
}
|
||||
|
||||
EXPECT_EQ(nativeWindow.initialize(), expectedResult);
|
||||
}
|
||||
CoUninitialize();
|
||||
}
|
||||
|
||||
typedef std::tuple<float, float, bool> sizeValidPair;
|
||||
static const sizeValidPair sizes[] = { sizeValidPair( 800, 480, true),
|
||||
sizeValidPair( 0, 480, false),
|
||||
sizeValidPair( 800, 0, false),
|
||||
sizeValidPair( 0, 0, false) };
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(NativeWindowTest,
|
||||
CoreWindowSizeTest,
|
||||
testing::ValuesIn(sizes));
|
||||
|
||||
} // namespace
|
||||
|
|
|
@ -197,16 +197,47 @@ bool IsEGLConfiguredPropertySet(EGLNativeWindowType window, ABI::Windows::Founda
|
|||
// A Valid EGLNativeWindowType IInspectable can only be:
|
||||
//
|
||||
// ICoreWindow
|
||||
// ISwapChainPanel
|
||||
// IPropertySet
|
||||
//
|
||||
//
|
||||
// Anything else will be rejected as an invalid IInspectable.
|
||||
bool IsValidEGLNativeWindowType(EGLNativeWindowType window)
|
||||
{
|
||||
return IsCoreWindow(window) || IsSwapChainPanel(window) || IsEGLConfiguredPropertySet(window);
|
||||
}
|
||||
|
||||
// Retrieve an optional property from a property set
|
||||
HRESULT GetOptionalPropertyValue(const ComPtr<ABI::Windows::Foundation::Collections::IMap<HSTRING, IInspectable*>> &propertyMap,
|
||||
const wchar_t *propertyName,
|
||||
boolean *hasKey,
|
||||
ComPtr<ABI::Windows::Foundation::IPropertyValue> &propertyValue)
|
||||
{
|
||||
if (!propertyMap || !hasKey)
|
||||
{
|
||||
return E_INVALIDARG;
|
||||
}
|
||||
|
||||
// Assume that the value does not exist
|
||||
*hasKey = false;
|
||||
|
||||
HRESULT result = propertyMap->HasKey(HStringReference(propertyName).Get(), hasKey);
|
||||
if (SUCCEEDED(result) && !(*hasKey))
|
||||
{
|
||||
// Value does not exist, so return S_OK and set the exists parameter to false to indicate
|
||||
// that a the optional property does not exist.
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
if (SUCCEEDED(result))
|
||||
{
|
||||
result = propertyMap->Lookup(HStringReference(propertyName).Get(), &propertyValue);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// Attempts to read an optional SIZE property value that is assumed to be in the form of
|
||||
// an ABI::Windows::Foundation::Size. This function validates the Size value before returning
|
||||
// an ABI::Windows::Foundation::Size. This function validates the Size value before returning
|
||||
// it to the caller.
|
||||
//
|
||||
// Possible return values are:
|
||||
|
@ -217,9 +248,15 @@ bool IsValidEGLNativeWindowType(EGLNativeWindowType window)
|
|||
// * Invalid property value (width/height must be > 0)
|
||||
// Additional errors may be returned from IMap or IPropertyValue
|
||||
//
|
||||
HRESULT GetOptionalSizePropertyValue(const ComPtr<ABI::Windows::Foundation::Collections::IMap<HSTRING, IInspectable*>>& propertyMap, const wchar_t *propertyName, SIZE *value, bool *valueExists)
|
||||
HRESULT GetOptionalSizePropertyValue(const ComPtr<ABI::Windows::Foundation::Collections::IMap<HSTRING, IInspectable*>> &propertyMap,
|
||||
const wchar_t *propertyName, SIZE *value, bool *valueExists)
|
||||
{
|
||||
if (!propertyMap || !propertyName || !value || !valueExists)
|
||||
ComPtr<ABI::Windows::Foundation::IPropertyValue> propertyValue;
|
||||
ABI::Windows::Foundation::PropertyType propertyType = ABI::Windows::Foundation::PropertyType::PropertyType_Empty;
|
||||
Size sizeValue = { 0, 0 };
|
||||
boolean hasKey = false;
|
||||
|
||||
if (!propertyMap || !value || !valueExists)
|
||||
{
|
||||
return E_INVALIDARG;
|
||||
}
|
||||
|
@ -228,52 +265,95 @@ HRESULT GetOptionalSizePropertyValue(const ComPtr<ABI::Windows::Foundation::Coll
|
|||
*valueExists = false;
|
||||
*value = { 0, 0 };
|
||||
|
||||
ComPtr<ABI::Windows::Foundation::IPropertyValue> propertyValue;
|
||||
ABI::Windows::Foundation::PropertyType propertyType = ABI::Windows::Foundation::PropertyType::PropertyType_Empty;
|
||||
Size sizeValue = { 0, 0 };
|
||||
boolean hasKey = false;
|
||||
|
||||
HRESULT result = propertyMap->HasKey(HStringReference(propertyName).Get(), &hasKey);
|
||||
if (SUCCEEDED(result) && !hasKey)
|
||||
{
|
||||
// Value does not exist, so return S_OK and set the exists parameter to false to indicate
|
||||
// that a the optional property does not exist.
|
||||
*valueExists = false;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
if (SUCCEEDED(result))
|
||||
{
|
||||
result = propertyMap->Lookup(HStringReference(propertyName).Get(), &propertyValue);
|
||||
}
|
||||
|
||||
if (SUCCEEDED(result))
|
||||
HRESULT result = GetOptionalPropertyValue(propertyMap, propertyName, &hasKey, propertyValue);
|
||||
if (SUCCEEDED(result) && hasKey)
|
||||
{
|
||||
result = propertyValue->get_Type(&propertyType);
|
||||
}
|
||||
|
||||
// Check if the expected Size property is of PropertyType_Size type.
|
||||
if (SUCCEEDED(result) && propertyType == ABI::Windows::Foundation::PropertyType::PropertyType_Size)
|
||||
{
|
||||
if (SUCCEEDED(propertyValue->GetSize(&sizeValue)) && (sizeValue.Width > 0 && sizeValue.Height > 0))
|
||||
// Check if the expected Size property is of PropertyType_Size type.
|
||||
if (SUCCEEDED(result) && propertyType == ABI::Windows::Foundation::PropertyType::PropertyType_Size)
|
||||
{
|
||||
// A valid property value exists
|
||||
*value = { static_cast<long>(sizeValue.Width), static_cast<long>(sizeValue.Height) };
|
||||
*valueExists = true;
|
||||
result = S_OK;
|
||||
if (SUCCEEDED(propertyValue->GetSize(&sizeValue)) && (sizeValue.Width > 0 && sizeValue.Height > 0))
|
||||
{
|
||||
// A valid property value exists
|
||||
*value = { static_cast<long>(sizeValue.Width), static_cast<long>(sizeValue.Height) };
|
||||
*valueExists = true;
|
||||
result = S_OK;
|
||||
}
|
||||
else
|
||||
{
|
||||
// An invalid Size property was detected. Width/Height values must > 0
|
||||
result = E_INVALIDARG;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// An invalid Size property was detected. Width/Height values must > 0
|
||||
// An invalid property type was detected. Size property must be of PropertyType_Size
|
||||
result = E_INVALIDARG;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// An invalid property type was detected. Size property must be of PropertyType_Size
|
||||
result = E_INVALIDARG;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// Attempts to read an optional float property value that is assumed to be in the form of
|
||||
// an ABI::Windows::Foundation::Single. This function validates the Single value before returning
|
||||
// it to the caller.
|
||||
//
|
||||
// Possible return values are:
|
||||
// S_OK, valueExists == true - optional Single value was successfully retrieved and validated
|
||||
// S_OK, valueExists == false - optional Single value was not found
|
||||
// E_INVALIDARG, valueExists = false - optional Single value was malformed in the property set.
|
||||
// * Incorrect property type ( must be PropertyType_Single)
|
||||
// * Invalid property value (must be > 0)
|
||||
// Additional errors may be returned from IMap or IPropertyValue
|
||||
//
|
||||
HRESULT GetOptionalSinglePropertyValue(const ComPtr<ABI::Windows::Foundation::Collections::IMap<HSTRING, IInspectable*>> &propertyMap,
|
||||
const wchar_t *propertyName, float *value, bool *valueExists)
|
||||
{
|
||||
ComPtr<ABI::Windows::Foundation::IPropertyValue> propertyValue;
|
||||
ABI::Windows::Foundation::PropertyType propertyType = ABI::Windows::Foundation::PropertyType::PropertyType_Empty;
|
||||
float scaleValue = 0.0f;
|
||||
boolean hasKey = false;
|
||||
|
||||
if (!propertyMap || !value || !valueExists)
|
||||
{
|
||||
return E_INVALIDARG;
|
||||
}
|
||||
|
||||
// Assume that the value does not exist
|
||||
*valueExists = false;
|
||||
*value = 0.0f;
|
||||
|
||||
HRESULT result = GetOptionalPropertyValue(propertyMap, propertyName, &hasKey, propertyValue);
|
||||
if (SUCCEEDED(result) && hasKey)
|
||||
{
|
||||
result = propertyValue->get_Type(&propertyType);
|
||||
|
||||
// Check if the expected Scale property is of PropertyType_Single type.
|
||||
if (SUCCEEDED(result) && propertyType == ABI::Windows::Foundation::PropertyType::PropertyType_Single)
|
||||
{
|
||||
if (SUCCEEDED(propertyValue->GetSingle(&scaleValue)) && (scaleValue > 0.0f))
|
||||
{
|
||||
// A valid property value exists
|
||||
*value = scaleValue;
|
||||
*valueExists = true;
|
||||
result = S_OK;
|
||||
}
|
||||
else
|
||||
{
|
||||
// An invalid scale was set
|
||||
result = E_INVALIDARG;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// An invalid property type was detected. Size property must be of PropertyType_Single
|
||||
result = E_INVALIDARG;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -31,7 +31,9 @@ class InspectableNativeWindow
|
|||
public:
|
||||
InspectableNativeWindow() :
|
||||
mSupportsSwapChainResize(true),
|
||||
mRequiresSwapChainScaling(false),
|
||||
mSwapChainSizeSpecified(false),
|
||||
mSwapChainScaleSpecified(false),
|
||||
mSwapChainScale(1.0f),
|
||||
mClientRectChanged(false),
|
||||
mClientRect({0,0,0,0}),
|
||||
mNewClientRect({0,0,0,0})
|
||||
|
@ -42,13 +44,10 @@ class InspectableNativeWindow
|
|||
|
||||
virtual bool initialize(EGLNativeWindowType window, IPropertySet *propertySet) = 0;
|
||||
virtual HRESULT createSwapChain(ID3D11Device *device, DXGIFactory *factory, DXGI_FORMAT format, unsigned int width, unsigned int height, DXGISwapChain **swapChain) = 0;
|
||||
virtual bool registerForSizeChangeEvents() = 0;
|
||||
virtual void unregisterForSizeChangeEvents() = 0;
|
||||
virtual HRESULT scaleSwapChain(const SIZE& newSize) { return S_OK; }
|
||||
|
||||
bool getClientRect(RECT *rect)
|
||||
{
|
||||
if (mClientRectChanged && mSupportsSwapChainResize)
|
||||
if (mClientRectChanged)
|
||||
{
|
||||
mClientRect = mNewClientRect;
|
||||
}
|
||||
|
@ -58,23 +57,44 @@ class InspectableNativeWindow
|
|||
return true;
|
||||
}
|
||||
|
||||
void setNewClientSize(const SIZE &newSize)
|
||||
// setNewClientSize is used by the WinRT size change handler. It isn't used by the rest of ANGLE.
|
||||
void setNewClientSize(const SIZE &newWindowSize)
|
||||
{
|
||||
if (mSupportsSwapChainResize && !mRequiresSwapChainScaling)
|
||||
{
|
||||
mNewClientRect = { 0, 0, newSize.cx, newSize.cy };
|
||||
mClientRectChanged = true;
|
||||
}
|
||||
// If the client doesn't support swapchain resizing then we should have already unregistered from size change handler
|
||||
ASSERT(mSupportsSwapChainResize);
|
||||
|
||||
if (mRequiresSwapChainScaling)
|
||||
if (mSupportsSwapChainResize)
|
||||
{
|
||||
scaleSwapChain(newSize);
|
||||
// If the swapchain size was specified then we should ignore this call too
|
||||
if (!mSwapChainSizeSpecified)
|
||||
{
|
||||
// We don't have to check if a swapchain scale was specified here; the default value is 1.0f which will have no effect.
|
||||
mNewClientRect = { 0, 0, static_cast<long>(newWindowSize.cx * mSwapChainScale), static_cast<long>(newWindowSize.cy * mSwapChainScale) };
|
||||
mClientRectChanged = true;
|
||||
|
||||
// If a scale was specified, then now is the time to apply the scale matrix for the new swapchain size and window size
|
||||
if (mSwapChainScaleSpecified)
|
||||
{
|
||||
scaleSwapChain(newWindowSize, mNewClientRect);
|
||||
}
|
||||
}
|
||||
|
||||
// Even if the swapchain size was fixed, the window might have changed size.
|
||||
// In this case, we should recalculate the scale matrix to account for the new window size
|
||||
if (mSwapChainSizeSpecified)
|
||||
{
|
||||
scaleSwapChain(newWindowSize, mClientRect);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected:
|
||||
bool mSupportsSwapChainResize;
|
||||
bool mRequiresSwapChainScaling;
|
||||
protected:
|
||||
virtual HRESULT scaleSwapChain(const SIZE &windowSize, const RECT &clientRect) = 0;
|
||||
|
||||
bool mSupportsSwapChainResize; // Support for IDXGISwapChain::ResizeBuffers method
|
||||
bool mSwapChainSizeSpecified; // If an EGLRenderSurfaceSizeProperty was specified
|
||||
bool mSwapChainScaleSpecified; // If an EGLRenderResolutionScaleProperty was specified
|
||||
float mSwapChainScale; // The scale value specified by the EGLRenderResolutionScaleProperty property
|
||||
RECT mClientRect;
|
||||
RECT mNewClientRect;
|
||||
bool mClientRectChanged;
|
||||
|
@ -86,8 +106,17 @@ bool IsValidEGLNativeWindowType(EGLNativeWindowType window);
|
|||
bool IsCoreWindow(EGLNativeWindowType window, ComPtr<ABI::Windows::UI::Core::ICoreWindow> *coreWindow = nullptr);
|
||||
bool IsSwapChainPanel(EGLNativeWindowType window, ComPtr<ABI::Windows::UI::Xaml::Controls::ISwapChainPanel> *swapChainPanel = nullptr);
|
||||
bool IsEGLConfiguredPropertySet(EGLNativeWindowType window, ABI::Windows::Foundation::Collections::IPropertySet **propertySet = nullptr, IInspectable **inspectable = nullptr);
|
||||
HRESULT GetOptionalSizePropertyValue(const ComPtr<ABI::Windows::Foundation::Collections::IMap<HSTRING, IInspectable*>>& propertyMap, const wchar_t *propertyName, SIZE *value, bool *valueExists);
|
||||
|
||||
HRESULT GetOptionalPropertyValue(const ComPtr<ABI::Windows::Foundation::Collections::IMap<HSTRING, IInspectable*>> &propertyMap,
|
||||
const wchar_t *propertyName,
|
||||
boolean *hasKey,
|
||||
ComPtr<ABI::Windows::Foundation::IPropertyValue> &propertyValue);
|
||||
|
||||
HRESULT GetOptionalSizePropertyValue(const ComPtr<ABI::Windows::Foundation::Collections::IMap<HSTRING, IInspectable*>> &propertyMap,
|
||||
const wchar_t *propertyName, SIZE *value, bool *valueExists);
|
||||
|
||||
HRESULT GetOptionalSinglePropertyValue(const ComPtr<ABI::Windows::Foundation::Collections::IMap<HSTRING, IInspectable*>> &propertyMap,
|
||||
const wchar_t *propertyName, float *value, bool *valueExists);
|
||||
}
|
||||
|
||||
#endif // LIBANGLE_RENDERER_D3D_D3D11_WINRT_INSPECTABLENATIVEWINDOW_H_
|
||||
|
|
|
@ -25,7 +25,6 @@ bool SwapChainPanelNativeWindow::initialize(EGLNativeWindowType window, IPropert
|
|||
ComPtr<IPropertySet> props = propertySet;
|
||||
ComPtr<IInspectable> win = window;
|
||||
SIZE swapChainSize = {};
|
||||
bool swapChainSizeSpecified = false;
|
||||
HRESULT result = S_OK;
|
||||
|
||||
// IPropertySet is an optional parameter and can be null.
|
||||
|
@ -34,12 +33,40 @@ bool SwapChainPanelNativeWindow::initialize(EGLNativeWindowType window, IPropert
|
|||
if (propertySet)
|
||||
{
|
||||
result = props.As(&mPropertyMap);
|
||||
if (SUCCEEDED(result))
|
||||
if (FAILED(result))
|
||||
{
|
||||
// The EGLRenderSurfaceSizeProperty is optional and may be missing. The IPropertySet
|
||||
// was prevalidated to contain the EGLNativeWindowType before being passed to
|
||||
// this host.
|
||||
result = GetOptionalSizePropertyValue(mPropertyMap, EGLRenderSurfaceSizeProperty, &swapChainSize, &swapChainSizeSpecified);
|
||||
return false;
|
||||
}
|
||||
|
||||
// The EGLRenderSurfaceSizeProperty is optional and may be missing. The IPropertySet
|
||||
// was prevalidated to contain the EGLNativeWindowType before being passed to
|
||||
// this host.
|
||||
result = GetOptionalSizePropertyValue(mPropertyMap, EGLRenderSurfaceSizeProperty, &swapChainSize, &mSwapChainSizeSpecified);
|
||||
if (FAILED(result))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// The EGLRenderResolutionScaleProperty is optional and may be missing. The IPropertySet
|
||||
// was prevalidated to contain the EGLNativeWindowType before being passed to
|
||||
// this host.
|
||||
result = GetOptionalSinglePropertyValue(mPropertyMap, EGLRenderResolutionScaleProperty, &mSwapChainScale, &mSwapChainScaleSpecified);
|
||||
if (FAILED(result))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!mSwapChainScaleSpecified)
|
||||
{
|
||||
// Default value for the scale is 1.0f
|
||||
mSwapChainScale = 1.0f;
|
||||
}
|
||||
|
||||
// A EGLRenderSurfaceSizeProperty and a EGLRenderResolutionScaleProperty can't both be specified
|
||||
if (mSwapChainScaleSpecified && mSwapChainSizeSpecified)
|
||||
{
|
||||
ERR("It is invalid to specify both an EGLRenderSurfaceSizeProperty and a EGLRenderResolutionScaleProperty.");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -57,16 +84,20 @@ bool SwapChainPanelNativeWindow::initialize(EGLNativeWindowType window, IPropert
|
|||
// Scaling of the swapchain output needs to be handled by the
|
||||
// host for swapchain panels even though the scaling mode setting
|
||||
// DXGI_SCALING_STRETCH is configured on the swapchain.
|
||||
if (swapChainSizeSpecified)
|
||||
if (mSwapChainSizeSpecified)
|
||||
{
|
||||
mClientRect = { 0, 0, swapChainSize.cx, swapChainSize.cy };
|
||||
|
||||
// Enable host swapchain scaling
|
||||
mRequiresSwapChainScaling = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
result = GetSwapChainPanelSize(mSwapChainPanel, &mClientRect);
|
||||
SIZE swapChainPanelSize;
|
||||
result = GetSwapChainPanelSize(mSwapChainPanel, &swapChainPanelSize);
|
||||
|
||||
if (SUCCEEDED(result))
|
||||
{
|
||||
// Update the client rect to account for any swapchain scale factor
|
||||
mClientRect = { 0, 0, static_cast<long>(swapChainPanelSize.cx * mSwapChainScale), static_cast<long>(swapChainPanelSize.cy * mSwapChainScale) };
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -107,7 +138,7 @@ bool SwapChainPanelNativeWindow::registerForSizeChangeEvents()
|
|||
void SwapChainPanelNativeWindow::unregisterForSizeChangeEvents()
|
||||
{
|
||||
ComPtr<ABI::Windows::UI::Xaml::IFrameworkElement> frameworkElement;
|
||||
if (SUCCEEDED(mSwapChainPanel.As(&frameworkElement)))
|
||||
if (mSwapChainPanel && SUCCEEDED(mSwapChainPanel.As(&frameworkElement)))
|
||||
{
|
||||
(void)frameworkElement->remove_SizeChanged(mSizeChangedEventToken);
|
||||
}
|
||||
|
@ -139,7 +170,7 @@ HRESULT SwapChainPanelNativeWindow::createSwapChain(ID3D11Device *device, DXGIFa
|
|||
|
||||
ComPtr<IDXGISwapChain1> newSwapChain;
|
||||
ComPtr<ISwapChainPanelNative> swapChainPanelNative;
|
||||
RECT currentPanelSize = {};
|
||||
SIZE currentPanelSize = {};
|
||||
|
||||
HRESULT result = factory->CreateSwapChainForComposition(device, &swapChainDesc, nullptr, newSwapChain.ReleaseAndGetAddressOf());
|
||||
|
||||
|
@ -165,34 +196,26 @@ HRESULT SwapChainPanelNativeWindow::createSwapChain(ID3D11Device *device, DXGIFa
|
|||
// If the host is responsible for scaling the output of the swapchain, then
|
||||
// scale it now before returning an instance to the caller. This is done by
|
||||
// first reading the current size of the swapchain panel, then scaling
|
||||
if (SUCCEEDED(result) && mRequiresSwapChainScaling)
|
||||
{
|
||||
result = GetSwapChainPanelSize(mSwapChainPanel, ¤tPanelSize);
|
||||
}
|
||||
|
||||
// Scale the swapchain to fit inside the contents of the panel.
|
||||
if (SUCCEEDED(result) && mRequiresSwapChainScaling)
|
||||
{
|
||||
SIZE currentSize = { currentPanelSize.right, currentPanelSize.bottom };
|
||||
result = scaleSwapChain(currentSize);
|
||||
}
|
||||
|
||||
if (SUCCEEDED(result))
|
||||
{
|
||||
// If automatic swapchain resize behaviors have been disabled, then
|
||||
// unregister for the resize change events.
|
||||
if (mSupportsSwapChainResize == false)
|
||||
if (mSwapChainSizeSpecified || mSwapChainScaleSpecified)
|
||||
{
|
||||
unregisterForSizeChangeEvents();
|
||||
result = GetSwapChainPanelSize(mSwapChainPanel, ¤tPanelSize);
|
||||
|
||||
// Scale the swapchain to fit inside the contents of the panel.
|
||||
if (SUCCEEDED(result))
|
||||
{
|
||||
result = scaleSwapChain(currentPanelSize, mClientRect);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
HRESULT SwapChainPanelNativeWindow::scaleSwapChain(const SIZE &newSize)
|
||||
HRESULT SwapChainPanelNativeWindow::scaleSwapChain(const SIZE &windowSize, const RECT &clientRect)
|
||||
{
|
||||
ABI::Windows::Foundation::Size renderScale = { (float)newSize.cx/(float)mClientRect.right, (float)newSize.cy/(float)mClientRect.bottom };
|
||||
ABI::Windows::Foundation::Size renderScale = { (float)windowSize.cx / (float)clientRect.right, (float)windowSize.cy / (float)clientRect.bottom };
|
||||
// Setup a scale matrix for the swap chain
|
||||
DXGI_MATRIX_3X2_F scaleMatrix = {};
|
||||
scaleMatrix._11 = renderScale.Width;
|
||||
|
@ -208,7 +231,7 @@ HRESULT SwapChainPanelNativeWindow::scaleSwapChain(const SIZE &newSize)
|
|||
return result;
|
||||
}
|
||||
|
||||
HRESULT GetSwapChainPanelSize(const ComPtr<ABI::Windows::UI::Xaml::Controls::ISwapChainPanel> &swapChainPanel, RECT *windowSize)
|
||||
HRESULT GetSwapChainPanelSize(const ComPtr<ABI::Windows::UI::Xaml::Controls::ISwapChainPanel> &swapChainPanel, SIZE *windowSize)
|
||||
{
|
||||
ComPtr<ABI::Windows::UI::Xaml::IUIElement> uiElement;
|
||||
ABI::Windows::Foundation::Size renderSize = { 0, 0 };
|
||||
|
@ -220,7 +243,7 @@ HRESULT GetSwapChainPanelSize(const ComPtr<ABI::Windows::UI::Xaml::Controls::ISw
|
|||
|
||||
if (SUCCEEDED(result))
|
||||
{
|
||||
*windowSize = { 0, 0, lround(renderSize.Width), lround(renderSize.Height) };
|
||||
*windowSize = { lround(renderSize.Width), lround(renderSize.Height) };
|
||||
}
|
||||
|
||||
return result;
|
||||
|
|
|
@ -18,11 +18,14 @@ class SwapChainPanelNativeWindow : public InspectableNativeWindow, public std::e
|
|||
public:
|
||||
~SwapChainPanelNativeWindow();
|
||||
|
||||
bool initialize(EGLNativeWindowType window, IPropertySet *propertySet);
|
||||
bool initialize(EGLNativeWindowType window, IPropertySet *propertySet) override;
|
||||
HRESULT createSwapChain(ID3D11Device *device, DXGIFactory *factory, DXGI_FORMAT format, unsigned int width, unsigned int height, DXGISwapChain **swapChain) override;
|
||||
|
||||
protected:
|
||||
HRESULT scaleSwapChain(const SIZE &windowSize, const RECT &clientRect) override;
|
||||
|
||||
bool registerForSizeChangeEvents();
|
||||
void unregisterForSizeChangeEvents();
|
||||
HRESULT createSwapChain(ID3D11Device *device, DXGIFactory *factory, DXGI_FORMAT format, unsigned int width, unsigned int height, DXGISwapChain **swapChain);
|
||||
HRESULT scaleSwapChain(const SIZE &newSize);
|
||||
|
||||
private:
|
||||
ComPtr<ABI::Windows::UI::Xaml::Controls::ISwapChainPanel> mSwapChainPanel;
|
||||
|
@ -74,6 +77,6 @@ class SwapChainPanelSizeChangedHandler :
|
|||
std::weak_ptr<InspectableNativeWindow> mHost;
|
||||
};
|
||||
|
||||
HRESULT GetSwapChainPanelSize(const ComPtr<ABI::Windows::UI::Xaml::Controls::ISwapChainPanel> &swapChainPanel, RECT *windowSize);
|
||||
HRESULT GetSwapChainPanelSize(const ComPtr<ABI::Windows::UI::Xaml::Controls::ISwapChainPanel> &swapChainPanel, SIZE *windowSize);
|
||||
}
|
||||
#endif // LIBANGLE_RENDERER_D3D_D3D11_WINRT_SWAPCHAINPANELNATIVEWINDOW_H_
|
||||
|
|
|
@ -269,38 +269,192 @@ HRESULT CreatePropertyMap(IMap<HSTRING, IInspectable*>** propertyMap)
|
|||
return result;
|
||||
}
|
||||
|
||||
HRESULT CreatePropertyValueStatics(IPropertyValueStatics** propertyStatics)
|
||||
{
|
||||
ComPtr<IPropertyValueStatics> propertyValueStatics;
|
||||
HRESULT result = GetActivationFactory(HStringReference(RuntimeClass_Windows_Foundation_PropertyValue).Get(), &propertyValueStatics);
|
||||
EXPECT_HRESULT_SUCCEEDED(result);
|
||||
|
||||
result = propertyValueStatics.CopyTo(propertyStatics);
|
||||
EXPECT_HRESULT_SUCCEEDED(result);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
HRESULT SetInspectablePropertyValue(const ComPtr<IMap<HSTRING, IInspectable*>>& propertyMap, const wchar_t* propertyName, IInspectable* inspectable)
|
||||
{
|
||||
boolean propertyReplaced = false;
|
||||
return propertyMap->Insert(HStringReference(propertyName).Get(), inspectable, &propertyReplaced);
|
||||
}
|
||||
|
||||
TEST(NativeWindowTest, NativeWindowValidSwapChainPanel)
|
||||
void expectNativeWindowInitCalls(MockSwapChainPanel &panel, bool expectRenderSize)
|
||||
{
|
||||
if (expectRenderSize)
|
||||
{
|
||||
EXPECT_CALL(panel, get_RenderSize(testing::_)).Times(1);
|
||||
}
|
||||
|
||||
EXPECT_CALL(panel, add_SizeChanged(testing::_, testing::_)).Times(1);
|
||||
EXPECT_CALL(panel, remove_SizeChanged(testing::_)).Times(1);
|
||||
}
|
||||
|
||||
TEST(NativeWindowTest, SwapChainPanelByItself)
|
||||
{
|
||||
MockSwapChainPanel mockSwapChainPanel;
|
||||
NativeWindow nativeWindow(reinterpret_cast<IInspectable*>(&mockSwapChainPanel));
|
||||
EXPECT_CALL(mockSwapChainPanel, get_RenderSize(testing::_)).Times(1);
|
||||
EXPECT_CALL(mockSwapChainPanel, add_SizeChanged(testing::_, testing::_)).Times(1);
|
||||
EXPECT_CALL(mockSwapChainPanel, remove_SizeChanged(testing::_)).Times(1);
|
||||
expectNativeWindowInitCalls(mockSwapChainPanel, true);
|
||||
EXPECT_TRUE(nativeWindow.initialize());
|
||||
}
|
||||
|
||||
TEST(NativeWindowTest, NativeWindowValidSwapChainPanelInPropertySet)
|
||||
TEST(NativeWindowTest, SwapChainPanelInPropertySet)
|
||||
{
|
||||
// COM is required to be initialized for creation of the property set
|
||||
EXPECT_HRESULT_SUCCEEDED(CoInitializeEx(NULL, COINIT_MULTITHREADED));
|
||||
{
|
||||
MockSwapChainPanel mockSwapChainPanel;
|
||||
ComPtr<IMap<HSTRING, IInspectable*>> propertySet;
|
||||
|
||||
// Create a simple property set with the swapchainpanel
|
||||
EXPECT_HRESULT_SUCCEEDED(CreatePropertyMap(&propertySet));
|
||||
EXPECT_HRESULT_SUCCEEDED(SetInspectablePropertyValue(propertySet, EGLNativeWindowTypeProperty, reinterpret_cast<IInspectable*>(&mockSwapChainPanel)));
|
||||
|
||||
// Check native window init calls
|
||||
NativeWindow nativeWindow(propertySet.Get());
|
||||
EXPECT_CALL(mockSwapChainPanel, get_RenderSize(testing::_)).Times(1);
|
||||
EXPECT_CALL(mockSwapChainPanel, add_SizeChanged(testing::_, testing::_)).Times(1);
|
||||
EXPECT_CALL(mockSwapChainPanel, remove_SizeChanged(testing::_)).Times(1);
|
||||
expectNativeWindowInitCalls(mockSwapChainPanel, true);
|
||||
EXPECT_TRUE(nativeWindow.initialize());
|
||||
}
|
||||
CoUninitialize();
|
||||
}
|
||||
|
||||
TEST(NativeWindowTest, SwapChainPanelInPropertySetWithSizeAndScale)
|
||||
{
|
||||
// COM is required to be initialized for creation of the property set
|
||||
EXPECT_HRESULT_SUCCEEDED(CoInitializeEx(NULL, COINIT_MULTITHREADED));
|
||||
{
|
||||
MockSwapChainPanel mockSwapChainPanel;
|
||||
ComPtr<IMap<HSTRING, IInspectable*>> propertySet;
|
||||
ComPtr<IPropertyValueStatics> propertyValueStatics;
|
||||
ComPtr<IPropertyValue> singleValue;
|
||||
ComPtr<IPropertyValue> sizeValue;
|
||||
|
||||
// Create a simple property set with the swapchainpanel
|
||||
EXPECT_HRESULT_SUCCEEDED(CreatePropertyMap(&propertySet));
|
||||
EXPECT_HRESULT_SUCCEEDED(SetInspectablePropertyValue(propertySet, EGLNativeWindowTypeProperty, reinterpret_cast<IInspectable*>(&mockSwapChainPanel)));
|
||||
|
||||
// Add a valid scale factor to the property set
|
||||
EXPECT_HRESULT_SUCCEEDED(CreatePropertyValueStatics(propertyValueStatics.GetAddressOf()));
|
||||
propertyValueStatics->CreateSingle(0.5f, reinterpret_cast<IInspectable**>(singleValue.GetAddressOf()));
|
||||
EXPECT_HRESULT_SUCCEEDED(SetInspectablePropertyValue(propertySet, EGLRenderResolutionScaleProperty, reinterpret_cast<IInspectable*>(singleValue.Get())));
|
||||
|
||||
// Add a valid size to the property set
|
||||
EXPECT_HRESULT_SUCCEEDED(CreatePropertyValueStatics(propertyValueStatics.GetAddressOf()));
|
||||
propertyValueStatics->CreateSize({ 480, 800 }, reinterpret_cast<IInspectable**>(sizeValue.GetAddressOf()));
|
||||
EXPECT_HRESULT_SUCCEEDED(SetInspectablePropertyValue(propertySet, EGLRenderSurfaceSizeProperty, reinterpret_cast<IInspectable*>(sizeValue.Get())));
|
||||
|
||||
// Check native window init fails, since we shouldn't be able to set a size and a scale together
|
||||
NativeWindow nativeWindow(propertySet.Get());
|
||||
EXPECT_FALSE(nativeWindow.initialize());
|
||||
}
|
||||
CoUninitialize();
|
||||
}
|
||||
|
||||
// Tests that the scale property works as expected in a property set with a SwapChainPanel
|
||||
class SwapChainPanelScaleTest : public testing::TestWithParam<std::pair<float, bool>>
|
||||
{
|
||||
};
|
||||
|
||||
TEST_P(SwapChainPanelScaleTest, ValidateScale)
|
||||
{
|
||||
float scale = GetParam().first;
|
||||
bool expectedResult = GetParam().second;
|
||||
|
||||
// COM is required to be initialized for creation of the property set
|
||||
EXPECT_HRESULT_SUCCEEDED(CoInitializeEx(NULL, COINIT_MULTITHREADED));
|
||||
{
|
||||
MockSwapChainPanel mockSwapChainPanel;
|
||||
ComPtr<IMap<HSTRING, IInspectable*>> propertySet;
|
||||
ComPtr<IPropertyValueStatics> propertyValueStatics;
|
||||
ComPtr<IPropertyValue> singleValue;
|
||||
|
||||
// Create a simple property set
|
||||
EXPECT_HRESULT_SUCCEEDED(CreatePropertyMap(&propertySet));
|
||||
EXPECT_HRESULT_SUCCEEDED(SetInspectablePropertyValue(propertySet, EGLNativeWindowTypeProperty, reinterpret_cast<IInspectable*>(&mockSwapChainPanel)));
|
||||
|
||||
// Add a valid scale factor to the property set
|
||||
EXPECT_HRESULT_SUCCEEDED(CreatePropertyValueStatics(propertyValueStatics.GetAddressOf()));
|
||||
propertyValueStatics->CreateSingle(scale, reinterpret_cast<IInspectable**>(singleValue.GetAddressOf()));
|
||||
EXPECT_HRESULT_SUCCEEDED(SetInspectablePropertyValue(propertySet, EGLRenderResolutionScaleProperty, reinterpret_cast<IInspectable*>(singleValue.Get())));
|
||||
|
||||
// Check native window init status and calls to the mock swapchainpanel
|
||||
NativeWindow nativeWindow(propertySet.Get());
|
||||
if (expectedResult)
|
||||
{
|
||||
expectNativeWindowInitCalls(mockSwapChainPanel, true);
|
||||
}
|
||||
|
||||
EXPECT_EQ(nativeWindow.initialize(), expectedResult);
|
||||
}
|
||||
CoUninitialize();
|
||||
}
|
||||
|
||||
typedef std::pair<float, bool> scaleValidPair;
|
||||
static const scaleValidPair scales[] = { scaleValidPair(1.0f, true),
|
||||
scaleValidPair(0.5f, true),
|
||||
scaleValidPair(0.0f, false),
|
||||
scaleValidPair(0.01f, true),
|
||||
scaleValidPair(2.00f, true) };
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(NativeWindowTest,
|
||||
SwapChainPanelScaleTest,
|
||||
testing::ValuesIn(scales));
|
||||
|
||||
// Tests that the size property works as expected in a property set with a SwapChainPanel
|
||||
class SwapChainPanelSizeTest : public testing::TestWithParam<std::tuple<float, float, bool>>
|
||||
{
|
||||
};
|
||||
|
||||
TEST_P(SwapChainPanelSizeTest, ValidateSize)
|
||||
{
|
||||
Size renderSize = { std::get<0>(GetParam()), std::get<1>(GetParam()) };
|
||||
bool expectedResult = std::get<2>(GetParam());
|
||||
|
||||
// COM is required to be initialized for creation of the property set
|
||||
EXPECT_HRESULT_SUCCEEDED(CoInitializeEx(NULL, COINIT_MULTITHREADED));
|
||||
{
|
||||
MockSwapChainPanel mockSwapChainPanel;
|
||||
ComPtr<IMap<HSTRING, IInspectable*>> propertySet;
|
||||
ComPtr<IPropertyValueStatics> propertyValueStatics;
|
||||
ComPtr<IPropertyValue> sizeValue;
|
||||
|
||||
// Create a simple property set
|
||||
EXPECT_HRESULT_SUCCEEDED(CreatePropertyMap(&propertySet));
|
||||
EXPECT_HRESULT_SUCCEEDED(SetInspectablePropertyValue(propertySet, EGLNativeWindowTypeProperty, reinterpret_cast<IInspectable*>(&mockSwapChainPanel)));
|
||||
|
||||
// Add a valid size to the property set
|
||||
EXPECT_HRESULT_SUCCEEDED(CreatePropertyValueStatics(propertyValueStatics.GetAddressOf()));
|
||||
propertyValueStatics->CreateSize(renderSize, reinterpret_cast<IInspectable**>(sizeValue.GetAddressOf()));
|
||||
EXPECT_HRESULT_SUCCEEDED(SetInspectablePropertyValue(propertySet, EGLRenderSurfaceSizeProperty, reinterpret_cast<IInspectable*>(sizeValue.Get())));
|
||||
|
||||
// Check native window init status and calls to the mock swapchainpanel
|
||||
NativeWindow nativeWindow(propertySet.Get());
|
||||
if (expectedResult)
|
||||
{
|
||||
expectNativeWindowInitCalls(mockSwapChainPanel, false);
|
||||
}
|
||||
|
||||
EXPECT_EQ(nativeWindow.initialize(), expectedResult);
|
||||
}
|
||||
CoUninitialize();
|
||||
}
|
||||
|
||||
typedef std::tuple<float, float, bool> sizeValidPair;
|
||||
static const sizeValidPair sizes[] = { sizeValidPair( 800, 480, true),
|
||||
sizeValidPair( 0, 480, false),
|
||||
sizeValidPair( 800, 0, false),
|
||||
sizeValidPair( 0, 0, false) };
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(NativeWindowTest,
|
||||
SwapChainPanelSizeTest,
|
||||
testing::ValuesIn(sizes));
|
||||
|
||||
} // namespace
|
||||
|
|
Загрузка…
Ссылка в новой задаче