blob: 57dcb4fbdcfc8a082212f9520e7555f0f91d6411 [file] [log] [blame]
//
// Copyright 2014 The ANGLE Project Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
// CoreWindowNativeWindow.cpp: NativeWindow for managing ICoreWindow native window types.
#include "libANGLE/renderer/d3d/d3d11/winrt/CoreWindowNativeWindow.h"
#include <windows.graphics.display.h>
using namespace ABI::Windows::Foundation::Collections;
namespace rx
{
CoreWindowNativeWindow::~CoreWindowNativeWindow()
{
unregisterForSizeChangeEvents();
}
bool CoreWindowNativeWindow::initialize(EGLNativeWindowType window, IPropertySet *propertySet)
{
ComPtr<IPropertySet> props = propertySet;
ComPtr<IInspectable> win = static_cast<IInspectable *>(window);
SIZE swapChainSize = {};
HRESULT result = S_OK;
// IPropertySet is an optional parameter and can be null.
// If one is specified, cache as an IMap and read the properties
// used for initial host initialization.
if (propertySet)
{
result = props.As(&mPropertyMap);
if (FAILED(result))
{
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;
}
}
if (SUCCEEDED(result))
{
result = win.As(&mCoreWindow);
}
if (SUCCEEDED(result))
{
// If a swapchain size is specfied, then the automatic resize
// behaviors implemented by the host should be disabled. The swapchain
// will be still be scaled when being rendered to fit the bounds
// of the host.
// Scaling of the swapchain output occurs automatically because if
// the scaling mode setting DXGI_SCALING_STRETCH on the swapchain.
if (mSwapChainSizeSpecified)
{
mClientRect = {0, 0, swapChainSize.cx, swapChainSize.cy};
}
else
{
Size coreWindowSize;
result = GetCoreWindowSizeInPixels(mCoreWindow, &coreWindowSize);
if (SUCCEEDED(result))
{
mClientRect = clientRect(coreWindowSize);
}
}
}
if (SUCCEEDED(result))
{
mNewClientRect = mClientRect;
mClientRectChanged = false;
return registerForSizeChangeEvents();
}
return false;
}
bool CoreWindowNativeWindow::registerForSizeChangeEvents()
{
ComPtr<IWindowSizeChangedEventHandler> sizeChangedHandler;
HRESULT result = Microsoft::WRL::MakeAndInitialize<CoreWindowSizeChangedHandler>(
sizeChangedHandler.ReleaseAndGetAddressOf(), this->shared_from_this());
if (SUCCEEDED(result))
{
result = mCoreWindow->add_SizeChanged(sizeChangedHandler.Get(), &mSizeChangedEventToken);
}
if (SUCCEEDED(result))
{
return true;
}
return false;
}
void CoreWindowNativeWindow::unregisterForSizeChangeEvents()
{
if (mCoreWindow)
{
(void)mCoreWindow->remove_SizeChanged(mSizeChangedEventToken);
}
mSizeChangedEventToken.value = 0;
}
HRESULT CoreWindowNativeWindow::createSwapChain(ID3D11Device *device,
IDXGIFactory2 *factory,
DXGI_FORMAT format,
unsigned int width,
unsigned int height,
bool containsAlpha,
IDXGISwapChain1 **swapChain)
{
if (device == nullptr || factory == nullptr || swapChain == nullptr || width == 0 ||
height == 0)
{
return E_INVALIDARG;
}
DXGI_SWAP_CHAIN_DESC1 swapChainDesc = {0};
swapChainDesc.Width = width;
swapChainDesc.Height = height;
swapChainDesc.Format = format;
swapChainDesc.Stereo = FALSE;
swapChainDesc.SampleDesc.Count = 1;
swapChainDesc.SampleDesc.Quality = 0;
swapChainDesc.BufferUsage =
DXGI_USAGE_SHADER_INPUT | DXGI_USAGE_RENDER_TARGET_OUTPUT | DXGI_USAGE_BACK_BUFFER;
swapChainDesc.BufferCount = 4;
swapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL;
swapChainDesc.Scaling = DXGI_SCALING_STRETCH;
swapChainDesc.AlphaMode = DXGI_ALPHA_MODE_UNSPECIFIED;
#if defined(STARBOARD)
// Normally for UWP on XB1, the swap chain surface should always be 1080p,
// regardless of the actual output resolution. However, by using a special
// surface format (R10G10B10A2), it is possible to use other resolutions
// that will be passed to the output without scaling.
swapChainDesc.Format = DXGI_FORMAT_R10G10B10A2_UNORM;
swapChainDesc.AlphaMode = DXGI_ALPHA_MODE_IGNORE;
#endif
*swapChain = nullptr;
ComPtr<IDXGISwapChain1> newSwapChain;
HRESULT result = factory->CreateSwapChainForCoreWindow(
device, mCoreWindow.Get(), &swapChainDesc, nullptr, newSwapChain.ReleaseAndGetAddressOf());
if (SUCCEEDED(result))
{
result = newSwapChain.CopyTo(swapChain);
}
if (SUCCEEDED(result))
{
// If automatic swapchain resize behaviors have been disabled, then
// unregister for the resize change events.
if (mSupportsSwapChainResize == false)
{
unregisterForSizeChangeEvents();
}
}
ComPtr<IDXGIDevice1> pDXGIDevice;
result = device->QueryInterface(__uuidof(IDXGIDevice1), (void **)pDXGIDevice.GetAddressOf());
if (SUCCEEDED(result))
{
pDXGIDevice->SetMaximumFrameLatency(swapChainDesc.BufferCount-1);
}
return result;
}
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 = {ConvertDipsToPixels(bounds.Width), ConvertDipsToPixels(bounds.Height)};
}
return result;
}
static float GetLogicalDpi()
{
ComPtr<ABI::Windows::Graphics::Display::IDisplayPropertiesStatics> displayProperties;
if (SUCCEEDED(GetActivationFactory(
HStringReference(RuntimeClass_Windows_Graphics_Display_DisplayProperties).Get(),
displayProperties.GetAddressOf())))
{
float dpi = 96.0f;
if (SUCCEEDED(displayProperties->get_LogicalDpi(&dpi)))
{
return dpi;
}
}
// Return 96 dpi as a default if display properties cannot be obtained.
return 96.0f;
}
float ConvertDipsToPixels(float dips)
{
static const float dipsPerInch = 96.0f;
return dips * GetLogicalDpi() / dipsPerInch;
}
} // namespace rx