Commit da056468 by Austin Kinross Committed by Jamie Madill

For WinRT, add EGLRenderSurfaceScaleProperty to specify swapchain scaling factor

Change-Id: Iede6682306082346cf2a3a55fe58f732b7a453df Reviewed-on: https://chromium-review.googlesource.com/277931Tested-by: 's avatarAustin Kinross <aukinros@microsoft.com> Reviewed-by: 's avatarJamie Madill <jmadill@chromium.org>
parent ce39f6ff
...@@ -28,10 +28,24 @@ const wchar_t EGLNativeWindowTypeProperty[] = L"EGLNativeWindowTypeProperty"; ...@@ -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. // 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. // The render surface size width and height must be greater than 0.
// If this property is set, then the render surface size is fixed. // 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. // 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 default behavior uses the window size if a CoreWindow is specified or
// the size of the SwapChainPanel control if one is specified. // the size of the SwapChainPanel control if one is specified.
// //
const wchar_t EGLRenderSurfaceSizeProperty[] = L"EGLRenderSurfaceSizeProperty"; 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_ #endif // ANGLE_WINDOWSSTORE_H_
...@@ -24,7 +24,6 @@ bool CoreWindowNativeWindow::initialize(EGLNativeWindowType window, IPropertySet ...@@ -24,7 +24,6 @@ bool CoreWindowNativeWindow::initialize(EGLNativeWindowType window, IPropertySet
ComPtr<IPropertySet> props = propertySet; ComPtr<IPropertySet> props = propertySet;
ComPtr<IInspectable> win = window; ComPtr<IInspectable> win = window;
SIZE swapChainSize = {}; SIZE swapChainSize = {};
bool swapChainSizeSpecified = false;
HRESULT result = S_OK; HRESULT result = S_OK;
// IPropertySet is an optional parameter and can be null. // IPropertySet is an optional parameter and can be null.
...@@ -33,12 +32,40 @@ bool CoreWindowNativeWindow::initialize(EGLNativeWindowType window, IPropertySet ...@@ -33,12 +32,40 @@ bool CoreWindowNativeWindow::initialize(EGLNativeWindowType window, IPropertySet
if (propertySet) if (propertySet)
{ {
result = props.As(&mPropertyMap); result = props.As(&mPropertyMap);
if (SUCCEEDED(result)) if (FAILED(result))
{ {
// The EGLRenderSurfaceSizeProperty is optional and may be missing. The IPropertySet return false;
// was prevalidated to contain the EGLNativeWindowType before being passed to }
// this host.
result = GetOptionalSizePropertyValue(mPropertyMap, EGLRenderSurfaceSizeProperty, &swapChainSize, &swapChainSizeSpecified); // 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 ...@@ -55,14 +82,19 @@ bool CoreWindowNativeWindow::initialize(EGLNativeWindowType window, IPropertySet
// of the host. // of the host.
// Scaling of the swapchain output occurs automatically because if // Scaling of the swapchain output occurs automatically because if
// the scaling mode setting DXGI_SCALING_STRETCH on the swapchain. // the scaling mode setting DXGI_SCALING_STRETCH on the swapchain.
if (swapChainSizeSpecified) if (mSwapChainSizeSpecified)
{ {
mClientRect = { 0, 0, swapChainSize.cx, swapChainSize.cy }; mClientRect = { 0, 0, swapChainSize.cx, swapChainSize.cy };
mSupportsSwapChainResize = false;
} }
else 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 ...@@ -154,13 +186,20 @@ HRESULT CoreWindowNativeWindow::createSwapChain(ID3D11Device *device, DXGIFactor
return result; 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; ABI::Windows::Foundation::Rect bounds;
HRESULT result = coreWindow->get_Bounds(&bounds); HRESULT result = coreWindow->get_Bounds(&bounds);
if (SUCCEEDED(result)) if (SUCCEEDED(result))
{ {
*windowSize = { 0, 0, ConvertDipsToPixels(bounds.Width), ConvertDipsToPixels(bounds.Height) }; *windowSize = { ConvertDipsToPixels(bounds.Width), ConvertDipsToPixels(bounds.Height) };
} }
return result; return result;
......
...@@ -24,10 +24,14 @@ class CoreWindowNativeWindow : public InspectableNativeWindow, public std::enabl ...@@ -24,10 +24,14 @@ class CoreWindowNativeWindow : public InspectableNativeWindow, public std::enabl
public: public:
~CoreWindowNativeWindow(); ~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(); bool registerForSizeChangeEvents();
void unregisterForSizeChangeEvents(); void unregisterForSizeChangeEvents();
HRESULT createSwapChain(ID3D11Device *device, DXGIFactory *factory, DXGI_FORMAT format, unsigned int width, unsigned int height, DXGISwapChain **swapChain);
private: private:
ComPtr<ABI::Windows::UI::Core::ICoreWindow> mCoreWindow; ComPtr<ABI::Windows::UI::Core::ICoreWindow> mCoreWindow;
...@@ -72,7 +76,7 @@ class CoreWindowSizeChangedHandler : ...@@ -72,7 +76,7 @@ class CoreWindowSizeChangedHandler :
std::weak_ptr<InspectableNativeWindow> mHost; 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_ #endif // LIBANGLE_RENDERER_D3D_D3D11_WINRT_COREWINDOWNATIVEWINDOW_H_
...@@ -162,12 +162,35 @@ HRESULT CreatePropertyMap(IMap<HSTRING, IInspectable*>** propertyMap) ...@@ -162,12 +162,35 @@ HRESULT CreatePropertyMap(IMap<HSTRING, IInspectable*>** propertyMap)
return result; 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) HRESULT SetInspectablePropertyValue(const ComPtr<IMap<HSTRING, IInspectable*>>& propertyMap, const wchar_t* propertyName, IInspectable* inspectable)
{ {
boolean propertyReplaced = false; boolean propertyReplaced = false;
return propertyMap->Insert(HStringReference(propertyName).Get(), inspectable, &propertyReplaced); 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) TEST(NativeWindowTest, NativeWindowNull)
{ {
NativeWindow nativeWindow(nullptr); NativeWindow nativeWindow(nullptr);
...@@ -191,9 +214,7 @@ TEST(NativeWindowTest, NativeWindowNotInspectable) ...@@ -191,9 +214,7 @@ TEST(NativeWindowTest, NativeWindowNotInspectable)
TEST(NativeWindowTest, NativeWindowValidCoreWindow) TEST(NativeWindowTest, NativeWindowValidCoreWindow)
{ {
MockCoreWindow mockCoreWindow; MockCoreWindow mockCoreWindow;
EXPECT_CALL(mockCoreWindow, get_Bounds(testing::_)).Times(1); expectNativeWindowInitCalls(mockCoreWindow, true);
EXPECT_CALL(mockCoreWindow, add_SizeChanged(testing::_, testing::_)).Times(1);
EXPECT_CALL(mockCoreWindow, remove_SizeChanged(testing::_)).Times(1);
NativeWindow nativeWindow(&mockCoreWindow); NativeWindow nativeWindow(&mockCoreWindow);
EXPECT_TRUE(nativeWindow.initialize()); EXPECT_TRUE(nativeWindow.initialize());
} }
...@@ -205,11 +226,12 @@ TEST(NativeWindowTest, NativeWindowValidCoreWindowInPropertySet) ...@@ -205,11 +226,12 @@ TEST(NativeWindowTest, NativeWindowValidCoreWindowInPropertySet)
{ {
MockCoreWindow mockCoreWindow; MockCoreWindow mockCoreWindow;
ComPtr<IMap<HSTRING, IInspectable*>> propertySet; ComPtr<IMap<HSTRING, IInspectable*>> propertySet;
EXPECT_CALL(mockCoreWindow, get_Bounds(testing::_)).Times(1);
EXPECT_CALL(mockCoreWindow, add_SizeChanged(testing::_, testing::_)).Times(1); // Add the CoreWindow to the property set
EXPECT_CALL(mockCoreWindow, remove_SizeChanged(testing::_)).Times(1);
EXPECT_HRESULT_SUCCEEDED(CreatePropertyMap(&propertySet)); EXPECT_HRESULT_SUCCEEDED(CreatePropertyMap(&propertySet));
EXPECT_HRESULT_SUCCEEDED(SetInspectablePropertyValue(propertySet, EGLNativeWindowTypeProperty, &mockCoreWindow)); EXPECT_HRESULT_SUCCEEDED(SetInspectablePropertyValue(propertySet, EGLNativeWindowTypeProperty, &mockCoreWindow));
expectNativeWindowInitCalls(mockCoreWindow, true);
NativeWindow nativeWindow(propertySet.Get()); NativeWindow nativeWindow(propertySet.Get());
EXPECT_TRUE(nativeWindow.initialize()); EXPECT_TRUE(nativeWindow.initialize());
} }
...@@ -223,11 +245,112 @@ TEST(NativeWindowTest, NativeWindowMissingCoreWindowInPropertySet) ...@@ -223,11 +245,112 @@ TEST(NativeWindowTest, NativeWindowMissingCoreWindowInPropertySet)
{ {
MockCoreWindow mockCoreWindow; MockCoreWindow mockCoreWindow;
ComPtr<IMap<HSTRING, IInspectable*>> propertySet; ComPtr<IMap<HSTRING, IInspectable*>> propertySet;
EXPECT_HRESULT_SUCCEEDED(CreatePropertyMap(&propertySet)); EXPECT_HRESULT_SUCCEEDED(CreatePropertyMap(&propertySet));
NativeWindow nativeWindow(propertySet.Get()); NativeWindow nativeWindow(propertySet.Get());
EXPECT_FALSE(nativeWindow.initialize()); EXPECT_FALSE(nativeWindow.initialize());
} }
CoUninitialize(); 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 } // namespace
...@@ -197,16 +197,47 @@ bool IsEGLConfiguredPropertySet(EGLNativeWindowType window, ABI::Windows::Founda ...@@ -197,16 +197,47 @@ bool IsEGLConfiguredPropertySet(EGLNativeWindowType window, ABI::Windows::Founda
// A Valid EGLNativeWindowType IInspectable can only be: // A Valid EGLNativeWindowType IInspectable can only be:
// //
// ICoreWindow // ICoreWindow
// ISwapChainPanel
// IPropertySet // IPropertySet
// //
// Anything else will be rejected as an invalid IInspectable. // Anything else will be rejected as an invalid IInspectable.
bool IsValidEGLNativeWindowType(EGLNativeWindowType window) bool IsValidEGLNativeWindowType(EGLNativeWindowType window)
{ {
return IsCoreWindow(window) || IsSwapChainPanel(window) || IsEGLConfiguredPropertySet(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 // 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. // it to the caller.
// //
// Possible return values are: // Possible return values are:
...@@ -217,9 +248,15 @@ bool IsValidEGLNativeWindowType(EGLNativeWindowType window) ...@@ -217,9 +248,15 @@ bool IsValidEGLNativeWindowType(EGLNativeWindowType window)
// * Invalid property value (width/height must be > 0) // * Invalid property value (width/height must be > 0)
// Additional errors may be returned from IMap or IPropertyValue // 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; return E_INVALIDARG;
} }
...@@ -228,52 +265,95 @@ HRESULT GetOptionalSizePropertyValue(const ComPtr<ABI::Windows::Foundation::Coll ...@@ -228,52 +265,95 @@ HRESULT GetOptionalSizePropertyValue(const ComPtr<ABI::Windows::Foundation::Coll
*valueExists = false; *valueExists = false;
*value = { 0, 0 }; *value = { 0, 0 };
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))
{
// 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 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; ComPtr<ABI::Windows::Foundation::IPropertyValue> propertyValue;
ABI::Windows::Foundation::PropertyType propertyType = ABI::Windows::Foundation::PropertyType::PropertyType_Empty; ABI::Windows::Foundation::PropertyType propertyType = ABI::Windows::Foundation::PropertyType::PropertyType_Empty;
Size sizeValue = { 0, 0 }; float scaleValue = 0.0f;
boolean hasKey = false; boolean hasKey = false;
HRESULT result = propertyMap->HasKey(HStringReference(propertyName).Get(), &hasKey); if (!propertyMap || !value || !valueExists)
if (SUCCEEDED(result) && !hasKey)
{ {
// Value does not exist, so return S_OK and set the exists parameter to false to indicate return E_INVALIDARG;
// that a the optional property does not exist.
*valueExists = false;
return S_OK;
} }
if (SUCCEEDED(result)) // Assume that the value does not exist
{ *valueExists = false;
result = propertyMap->Lookup(HStringReference(propertyName).Get(), &propertyValue); *value = 0.0f;
}
if (SUCCEEDED(result)) HRESULT result = GetOptionalPropertyValue(propertyMap, propertyName, &hasKey, propertyValue);
if (SUCCEEDED(result) && hasKey)
{ {
result = propertyValue->get_Type(&propertyType); result = propertyValue->get_Type(&propertyType);
}
// Check if the expected Size property is of PropertyType_Size type. // Check if the expected Scale property is of PropertyType_Single type.
if (SUCCEEDED(result) && propertyType == ABI::Windows::Foundation::PropertyType::PropertyType_Size) if (SUCCEEDED(result) && propertyType == ABI::Windows::Foundation::PropertyType::PropertyType_Single)
{
if (SUCCEEDED(propertyValue->GetSize(&sizeValue)) && (sizeValue.Width > 0 && sizeValue.Height > 0))
{ {
// A valid property value exists if (SUCCEEDED(propertyValue->GetSingle(&scaleValue)) && (scaleValue > 0.0f))
*value = { static_cast<long>(sizeValue.Width), static_cast<long>(sizeValue.Height) }; {
*valueExists = true; // A valid property value exists
result = S_OK; *value = scaleValue;
*valueExists = true;
result = S_OK;
}
else
{
// An invalid scale was set
result = E_INVALIDARG;
}
} }
else else
{ {
// An invalid Size property was detected. Width/Height values must > 0 // An invalid property type was detected. Size property must be of PropertyType_Single
result = E_INVALIDARG; result = E_INVALIDARG;
} }
} }
else
{
// An invalid property type was detected. Size property must be of PropertyType_Size
result = E_INVALIDARG;
}
return result; return result;
} }
} }
...@@ -31,7 +31,9 @@ class InspectableNativeWindow ...@@ -31,7 +31,9 @@ class InspectableNativeWindow
public: public:
InspectableNativeWindow() : InspectableNativeWindow() :
mSupportsSwapChainResize(true), mSupportsSwapChainResize(true),
mRequiresSwapChainScaling(false), mSwapChainSizeSpecified(false),
mSwapChainScaleSpecified(false),
mSwapChainScale(1.0f),
mClientRectChanged(false), mClientRectChanged(false),
mClientRect({0,0,0,0}), mClientRect({0,0,0,0}),
mNewClientRect({0,0,0,0}) mNewClientRect({0,0,0,0})
...@@ -42,13 +44,10 @@ class InspectableNativeWindow ...@@ -42,13 +44,10 @@ class InspectableNativeWindow
virtual bool initialize(EGLNativeWindowType window, IPropertySet *propertySet) = 0; 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 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) bool getClientRect(RECT *rect)
{ {
if (mClientRectChanged && mSupportsSwapChainResize) if (mClientRectChanged)
{ {
mClientRect = mNewClientRect; mClientRect = mNewClientRect;
} }
...@@ -58,23 +57,44 @@ class InspectableNativeWindow ...@@ -58,23 +57,44 @@ class InspectableNativeWindow
return true; 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) // If the client doesn't support swapchain resizing then we should have already unregistered from size change handler
{ ASSERT(mSupportsSwapChainResize);
mNewClientRect = { 0, 0, newSize.cx, newSize.cy };
mClientRectChanged = true;
}
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: protected:
bool mSupportsSwapChainResize; virtual HRESULT scaleSwapChain(const SIZE &windowSize, const RECT &clientRect) = 0;
bool mRequiresSwapChainScaling;
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 mClientRect;
RECT mNewClientRect; RECT mNewClientRect;
bool mClientRectChanged; bool mClientRectChanged;
...@@ -86,8 +106,17 @@ bool IsValidEGLNativeWindowType(EGLNativeWindowType window); ...@@ -86,8 +106,17 @@ bool IsValidEGLNativeWindowType(EGLNativeWindowType window);
bool IsCoreWindow(EGLNativeWindowType window, ComPtr<ABI::Windows::UI::Core::ICoreWindow> *coreWindow = nullptr); 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 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); 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_ #endif // LIBANGLE_RENDERER_D3D_D3D11_WINRT_INSPECTABLENATIVEWINDOW_H_
...@@ -25,7 +25,6 @@ bool SwapChainPanelNativeWindow::initialize(EGLNativeWindowType window, IPropert ...@@ -25,7 +25,6 @@ bool SwapChainPanelNativeWindow::initialize(EGLNativeWindowType window, IPropert
ComPtr<IPropertySet> props = propertySet; ComPtr<IPropertySet> props = propertySet;
ComPtr<IInspectable> win = window; ComPtr<IInspectable> win = window;
SIZE swapChainSize = {}; SIZE swapChainSize = {};
bool swapChainSizeSpecified = false;
HRESULT result = S_OK; HRESULT result = S_OK;
// IPropertySet is an optional parameter and can be null. // IPropertySet is an optional parameter and can be null.
...@@ -34,12 +33,40 @@ bool SwapChainPanelNativeWindow::initialize(EGLNativeWindowType window, IPropert ...@@ -34,12 +33,40 @@ bool SwapChainPanelNativeWindow::initialize(EGLNativeWindowType window, IPropert
if (propertySet) if (propertySet)
{ {
result = props.As(&mPropertyMap); result = props.As(&mPropertyMap);
if (SUCCEEDED(result)) if (FAILED(result))
{ {
// The EGLRenderSurfaceSizeProperty is optional and may be missing. The IPropertySet return false;
// was prevalidated to contain the EGLNativeWindowType before being passed to }
// this host.
result = GetOptionalSizePropertyValue(mPropertyMap, EGLRenderSurfaceSizeProperty, &swapChainSize, &swapChainSizeSpecified); // 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 ...@@ -57,16 +84,20 @@ bool SwapChainPanelNativeWindow::initialize(EGLNativeWindowType window, IPropert
// Scaling of the swapchain output needs to be handled by the // Scaling of the swapchain output needs to be handled by the
// host for swapchain panels even though the scaling mode setting // host for swapchain panels even though the scaling mode setting
// DXGI_SCALING_STRETCH is configured on the swapchain. // DXGI_SCALING_STRETCH is configured on the swapchain.
if (swapChainSizeSpecified) if (mSwapChainSizeSpecified)
{ {
mClientRect = { 0, 0, swapChainSize.cx, swapChainSize.cy }; mClientRect = { 0, 0, swapChainSize.cx, swapChainSize.cy };
// Enable host swapchain scaling
mRequiresSwapChainScaling = true;
} }
else 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() ...@@ -107,7 +138,7 @@ bool SwapChainPanelNativeWindow::registerForSizeChangeEvents()
void SwapChainPanelNativeWindow::unregisterForSizeChangeEvents() void SwapChainPanelNativeWindow::unregisterForSizeChangeEvents()
{ {
ComPtr<ABI::Windows::UI::Xaml::IFrameworkElement> frameworkElement; ComPtr<ABI::Windows::UI::Xaml::IFrameworkElement> frameworkElement;
if (SUCCEEDED(mSwapChainPanel.As(&frameworkElement))) if (mSwapChainPanel && SUCCEEDED(mSwapChainPanel.As(&frameworkElement)))
{ {
(void)frameworkElement->remove_SizeChanged(mSizeChangedEventToken); (void)frameworkElement->remove_SizeChanged(mSizeChangedEventToken);
} }
...@@ -139,7 +170,7 @@ HRESULT SwapChainPanelNativeWindow::createSwapChain(ID3D11Device *device, DXGIFa ...@@ -139,7 +170,7 @@ HRESULT SwapChainPanelNativeWindow::createSwapChain(ID3D11Device *device, DXGIFa
ComPtr<IDXGISwapChain1> newSwapChain; ComPtr<IDXGISwapChain1> newSwapChain;
ComPtr<ISwapChainPanelNative> swapChainPanelNative; ComPtr<ISwapChainPanelNative> swapChainPanelNative;
RECT currentPanelSize = {}; SIZE currentPanelSize = {};
HRESULT result = factory->CreateSwapChainForComposition(device, &swapChainDesc, nullptr, newSwapChain.ReleaseAndGetAddressOf()); HRESULT result = factory->CreateSwapChainForComposition(device, &swapChainDesc, nullptr, newSwapChain.ReleaseAndGetAddressOf());
...@@ -165,34 +196,26 @@ HRESULT SwapChainPanelNativeWindow::createSwapChain(ID3D11Device *device, DXGIFa ...@@ -165,34 +196,26 @@ HRESULT SwapChainPanelNativeWindow::createSwapChain(ID3D11Device *device, DXGIFa
// If the host is responsible for scaling the output of the swapchain, then // 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 // 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 // first reading the current size of the swapchain panel, then scaling
if (SUCCEEDED(result) && mRequiresSwapChainScaling)
{
result = GetSwapChainPanelSize(mSwapChainPanel, &currentPanelSize);
}
// 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 (SUCCEEDED(result))
{ {
// If automatic swapchain resize behaviors have been disabled, then if (mSwapChainSizeSpecified || mSwapChainScaleSpecified)
// unregister for the resize change events.
if (mSupportsSwapChainResize == false)
{ {
unregisterForSizeChangeEvents(); result = GetSwapChainPanelSize(mSwapChainPanel, &currentPanelSize);
// Scale the swapchain to fit inside the contents of the panel.
if (SUCCEEDED(result))
{
result = scaleSwapChain(currentPanelSize, mClientRect);
}
} }
} }
return result; 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 // Setup a scale matrix for the swap chain
DXGI_MATRIX_3X2_F scaleMatrix = {}; DXGI_MATRIX_3X2_F scaleMatrix = {};
scaleMatrix._11 = renderScale.Width; scaleMatrix._11 = renderScale.Width;
...@@ -208,7 +231,7 @@ HRESULT SwapChainPanelNativeWindow::scaleSwapChain(const SIZE &newSize) ...@@ -208,7 +231,7 @@ HRESULT SwapChainPanelNativeWindow::scaleSwapChain(const SIZE &newSize)
return result; 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; ComPtr<ABI::Windows::UI::Xaml::IUIElement> uiElement;
ABI::Windows::Foundation::Size renderSize = { 0, 0 }; ABI::Windows::Foundation::Size renderSize = { 0, 0 };
...@@ -220,7 +243,7 @@ HRESULT GetSwapChainPanelSize(const ComPtr<ABI::Windows::UI::Xaml::Controls::ISw ...@@ -220,7 +243,7 @@ HRESULT GetSwapChainPanelSize(const ComPtr<ABI::Windows::UI::Xaml::Controls::ISw
if (SUCCEEDED(result)) if (SUCCEEDED(result))
{ {
*windowSize = { 0, 0, lround(renderSize.Width), lround(renderSize.Height) }; *windowSize = { lround(renderSize.Width), lround(renderSize.Height) };
} }
return result; return result;
......
...@@ -18,11 +18,14 @@ class SwapChainPanelNativeWindow : public InspectableNativeWindow, public std::e ...@@ -18,11 +18,14 @@ class SwapChainPanelNativeWindow : public InspectableNativeWindow, public std::e
public: public:
~SwapChainPanelNativeWindow(); ~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(); bool registerForSizeChangeEvents();
void unregisterForSizeChangeEvents(); 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: private:
ComPtr<ABI::Windows::UI::Xaml::Controls::ISwapChainPanel> mSwapChainPanel; ComPtr<ABI::Windows::UI::Xaml::Controls::ISwapChainPanel> mSwapChainPanel;
...@@ -74,6 +77,6 @@ class SwapChainPanelSizeChangedHandler : ...@@ -74,6 +77,6 @@ class SwapChainPanelSizeChangedHandler :
std::weak_ptr<InspectableNativeWindow> mHost; 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_ #endif // LIBANGLE_RENDERER_D3D_D3D11_WINRT_SWAPCHAINPANELNATIVEWINDOW_H_
...@@ -269,38 +269,192 @@ HRESULT CreatePropertyMap(IMap<HSTRING, IInspectable*>** propertyMap) ...@@ -269,38 +269,192 @@ HRESULT CreatePropertyMap(IMap<HSTRING, IInspectable*>** propertyMap)
return result; 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) HRESULT SetInspectablePropertyValue(const ComPtr<IMap<HSTRING, IInspectable*>>& propertyMap, const wchar_t* propertyName, IInspectable* inspectable)
{ {
boolean propertyReplaced = false; boolean propertyReplaced = false;
return propertyMap->Insert(HStringReference(propertyName).Get(), inspectable, &propertyReplaced); 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; MockSwapChainPanel mockSwapChainPanel;
NativeWindow nativeWindow(reinterpret_cast<IInspectable*>(&mockSwapChainPanel)); NativeWindow nativeWindow(reinterpret_cast<IInspectable*>(&mockSwapChainPanel));
EXPECT_CALL(mockSwapChainPanel, get_RenderSize(testing::_)).Times(1); expectNativeWindowInitCalls(mockSwapChainPanel, true);
EXPECT_CALL(mockSwapChainPanel, add_SizeChanged(testing::_, testing::_)).Times(1);
EXPECT_CALL(mockSwapChainPanel, remove_SizeChanged(testing::_)).Times(1);
EXPECT_TRUE(nativeWindow.initialize()); EXPECT_TRUE(nativeWindow.initialize());
} }
TEST(NativeWindowTest, NativeWindowValidSwapChainPanelInPropertySet) TEST(NativeWindowTest, SwapChainPanelInPropertySet)
{ {
// COM is required to be initialized for creation of the property set // COM is required to be initialized for creation of the property set
EXPECT_HRESULT_SUCCEEDED(CoInitializeEx(NULL, COINIT_MULTITHREADED)); EXPECT_HRESULT_SUCCEEDED(CoInitializeEx(NULL, COINIT_MULTITHREADED));
{ {
MockSwapChainPanel mockSwapChainPanel; MockSwapChainPanel mockSwapChainPanel;
ComPtr<IMap<HSTRING, IInspectable*>> propertySet; ComPtr<IMap<HSTRING, IInspectable*>> propertySet;
// Create a simple property set with the swapchainpanel
EXPECT_HRESULT_SUCCEEDED(CreatePropertyMap(&propertySet)); EXPECT_HRESULT_SUCCEEDED(CreatePropertyMap(&propertySet));
EXPECT_HRESULT_SUCCEEDED(SetInspectablePropertyValue(propertySet, EGLNativeWindowTypeProperty, reinterpret_cast<IInspectable*>(&mockSwapChainPanel))); EXPECT_HRESULT_SUCCEEDED(SetInspectablePropertyValue(propertySet, EGLNativeWindowTypeProperty, reinterpret_cast<IInspectable*>(&mockSwapChainPanel)));
// Check native window init calls
NativeWindow nativeWindow(propertySet.Get()); NativeWindow nativeWindow(propertySet.Get());
EXPECT_CALL(mockSwapChainPanel, get_RenderSize(testing::_)).Times(1); expectNativeWindowInitCalls(mockSwapChainPanel, true);
EXPECT_CALL(mockSwapChainPanel, add_SizeChanged(testing::_, testing::_)).Times(1);
EXPECT_CALL(mockSwapChainPanel, remove_SizeChanged(testing::_)).Times(1);
EXPECT_TRUE(nativeWindow.initialize()); EXPECT_TRUE(nativeWindow.initialize());
} }
CoUninitialize(); 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 } // namespace
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment