/////////////////////////////////////////////////////////////////////////////// // Copyright (c) Electronic Arts Inc. All rights reserved. /////////////////////////////////////////////////////////////////////////////// #include "EABase/eabase.h" #if (defined(EA_PLATFORM_MICROSOFT) && !defined(CS_UNDEFINED_STRING) && !EA_WINAPI_FAMILY_PARTITION(EA_WINAPI_PARTITION_DESKTOP)) #include #include #include #include EA_DISABLE_ALL_VC_WARNINGS() #pragma warning(disable: 4472 4355) // additional warnings generated by XDK with VS2015 #include #ifndef WIN32_LEAN_AND_MEAN #define WIN32_LEAN_AND_MEAN #endif #include #if defined EA_PLATFORM_CAPILANO #if defined EAMAIN_CAPILANO_DX12 #include #else #include #endif #endif EA_RESTORE_ALL_VC_WARNINGS() namespace EA { namespace EAMain { // Application - implements the required functionality for a application ref class ApplicationView sealed : public Windows::ApplicationModel::Core::IFrameworkView { public: // IFrameworkView Methods virtual void Initialize(Windows::ApplicationModel::Core::CoreApplicationView^ applicationView); virtual void SetWindow(Windows::UI::Core::CoreWindow^ window) {} virtual void Load(Platform::String^ entryPoint); virtual void Run(); virtual void Uninitialize(); private: char *mCommandLine; #if EA_PLATFORM_CAPILANO #if defined EAMAIN_CAPILANO_DX12 ID3D12CommandQueue* mpCommandQueue; #else ID3DXboxPerformanceContext* mpD3DXboxPerfContext; #endif #endif void CreateDeviceResources(); void OnActivated( Windows::ApplicationModel::Core::CoreApplicationView^ applicationView, Windows::ApplicationModel::Activation::IActivatedEventArgs^ args ); }; // ApplicationSource - responsible for creating the Application instance and passing it back to the system ref class ApplicationViewSource : Windows::ApplicationModel::Core::IFrameworkViewSource { public: virtual Windows::ApplicationModel::Core::IFrameworkView^ CreateView() { return ref new ApplicationView(); } }; void OutputAppTransition(const char* transition, const wchar_t* sender, const wchar_t* args) { char msg[1024]; EA::StdC::Snprintf(msg, EAArrayCount(msg), "****\n app is %s.\n sender: ", transition); EA::StdC::Strlcat(msg, sender, EAArrayCount(msg)); EA::StdC::Strlcat(msg, "\n args: ", EAArrayCount(msg)); EA::StdC::Strlcat(msg, args, EAArrayCount(msg)); EA::StdC::Strlcat(msg, "\n****\n", EAArrayCount(msg)); OutputDebugStringA(msg); } void ApplicationView::CreateDeviceResources() { #if defined EA_PLATFORM_CAPILANO #if defined EAMAIN_CAPILANO_DX12 ID3D12Device* pD3DDevice; HRESULT hr = D3D12CreateDevice( nullptr, // specify null to use the default adapter D3D_FEATURE_LEVEL_11_0, __uuidof(ID3D12Device), (void**)&pD3DDevice ); if (FAILED(hr)) { OutputDebugStringA("Failed to create device. Suspending will not work for this application."); return; } D3D12XBOX_COMMAND_QUEUE_DESC queueDesc = {}; queueDesc.Type = D3D12_COMMAND_LIST_TYPE_DIRECT; queueDesc.Flags = D3D12_COMMAND_QUEUE_FLAG_NONE; queueDesc.EngineOrPipeIndex = 0; queueDesc.QueueIndex = 0; hr = pD3DDevice->CreateCommandQueueX(&queueDesc, __uuidof(ID3D12CommandQueue), (void**)&mpCommandQueue); if (FAILED(hr)) { OutputDebugStringA("Failed to create command queue. Suspending will not work for this application."); } if (pD3DDevice) { pD3DDevice->Release(); pD3DDevice = NULL; } #else // This flag adds support for surfaces with a different color channel ordering than the API default. // It is recommended usage, and is required for compatibility with Direct2D. UINT creationFlags = D3D11_CREATE_DEVICE_INSTRUMENTED; // This array defines the set of DirectX hardware feature levels this app will support. // Note the ordering should be preserved. // Don't forget to declare your application's minimum required feature level in its // description. All applications are assumed to support 9.1 unless otherwise stated. D3D_FEATURE_LEVEL featureLevels[] = { D3D_FEATURE_LEVEL_11_0 }; // Create the DX11 API device object, and get a corresponding context. ID3D11Device* pD3DDevice; ID3D11DeviceContext* pD3DDeviceContext; HRESULT hr = D3D11CreateDevice( nullptr, // specify null to use the default adapter D3D_DRIVER_TYPE_HARDWARE, nullptr, // leave as nullptr unless software device creationFlags, // optionally set debug and Direct2D compatibility flags featureLevels, // list of feature levels this app can support ARRAYSIZE(featureLevels), // number of entries in above list D3D11_SDK_VERSION, // always set this to D3D11_SDK_VERSION &pD3DDevice, // returns the Direct3D device created NULL, // returns feature level of device created &pD3DDeviceContext // returns the device immediate context ); if (FAILED(hr)) { OutputDebugStringA("Failed to create device. Suspending will not work for this application."); return; } hr = pD3DDevice->QueryInterface(__uuidof(mpD3DXboxPerfContext), (void **)&mpD3DXboxPerfContext); if (FAILED(hr)) { OutputDebugStringA("Failed to get perfcontext. Suspending will not work for this application."); } if (pD3DDevice) { pD3DDevice->Release(); pD3DDevice = NULL; } if (pD3DDeviceContext) { pD3DDeviceContext->Release(); pD3DDeviceContext = NULL; } #endif #else // Do nothing #endif } // Called by the system. Perform application initialization here, // hooking application wide events, etc. void ApplicationView::Initialize(Windows::ApplicationModel::Core::CoreApplicationView^ applicationView) { using namespace Platform; using namespace Windows::Foundation; using namespace Windows::ApplicationModel; using namespace Windows::ApplicationModel::Core; using namespace Windows::ApplicationModel::Activation; // Creates any resources required by the platform to run an application / enable a particular feature set (like GPU profiling or suspend/resume) CreateDeviceResources(); #pragma warning(push) // Disables warning for MS class 'Windows::Foundation::TypedEventHandler::{ctor}::__abi_PointerToMemberCapture' // "layout of class may have changed from a previous version of the compiler due to better packing of member 'Windows::Foundation::TypedEventHandler::{ctor}::__abi_PointerToMemberCapture::member'" #pragma warning(disable:4371) applicationView->Activated += ref new Windows::Foundation::TypedEventHandler< CoreApplicationView^, IActivatedEventArgs^ >( this, &ApplicationView::OnActivated ); #pragma warning(pop) CoreApplication::Suspending += ref new EventHandler([this](Object^ sender, SuspendingEventArgs^ args) { OutputAppTransition("suspending", sender ? sender->ToString()->Data() : L"NULL", args ? args->ToString()->Data() : L"NULL"); #if defined EA_PLATFORM_CAPILANO #if defined EAMAIN_CAPILANO_DX12 mpCommandQueue->SuspendX(0); #else mpD3DXboxPerfContext->Suspend(0); #endif #endif }); CoreApplication::Resuming += ref new EventHandler([this](Object^ sender, Object^ args) { OutputAppTransition("resuming", sender ? sender->ToString()->Data() : L"NULL", args ? args->ToString()->Data() : L"NULL"); #if defined EA_PLATFORM_CAPILANO #if defined EAMAIN_CAPILANO_DX12 mpCommandQueue->ResumeX(); #else mpD3DXboxPerfContext->Resume(); #endif #endif }); CoreApplication::Exiting += ref new EventHandler([](Object^ sender, Object^ args) { OutputAppTransition("exiting", sender ? sender->ToString()->Data() : L"NULL", args ? args->ToString()->Data() : L"NULL"); }); } static char *ConvertLaunchArgsToMultibyte(LPCWSTR rawArgumentString, int rawArgumentStringLength) { int bufferSize = WideCharToMultiByte( CP_UTF8, 0, rawArgumentString, rawArgumentStringLength, NULL, 0, NULL, NULL); char *commandLine = static_cast(calloc(bufferSize + 1, 1)); int rv = WideCharToMultiByte( CP_UTF8, 0, rawArgumentString, rawArgumentStringLength, commandLine, bufferSize + 1, NULL, NULL); commandLine[bufferSize] = 0; EA_ASSERT(rv == bufferSize); EA_UNUSED(rv); // avoids warnings in opt builds regarding unused variables return commandLine; } static char *ReadArgsFromFile() { FILE *fp = fopen("EAMainArgsFile.txt", "rb"); if (fp == NULL) { goto error_return; } size_t fileSize; fseek(fp, 0, SEEK_END); fileSize = static_cast(ftell(fp)); fseek(fp, 0, SEEK_SET); char *argsBuffer = static_cast(calloc(fileSize + 1, 1)); if (fread(argsBuffer, 1, fileSize, fp) != fileSize) { goto error_return_free_buffer; } return argsBuffer; error_return_free_buffer: free(argsBuffer); fclose(fp); error_return: return static_cast(calloc(1, 1)); } void ApplicationView::OnActivated( Windows::ApplicationModel::Core::CoreApplicationView^ applicationView, Windows::ApplicationModel::Activation::IActivatedEventArgs^ args ) { if (args->Kind == Windows::ApplicationModel::Activation::ActivationKind::Launch) { Windows::ApplicationModel::Activation::LaunchActivatedEventArgs ^launchArgs = (Windows::ApplicationModel::Activation::LaunchActivatedEventArgs ^) args; Platform::String ^argumentString = launchArgs->Arguments; LPCWSTR rawArgumentString = argumentString->Data(); int rawArgumentStringLength = argumentString->Length(); if (rawArgumentString == NULL || wcslen(rawArgumentString) == 0) { mCommandLine = ReadArgsFromFile(); } else { mCommandLine = ConvertLaunchArgsToMultibyte(rawArgumentString, rawArgumentStringLength); } } Windows::UI::Core::CoreWindow::GetForCurrentThread()->Activate(); } void ApplicationView::Load(Platform::String^ entryPoint) { } // Called by the system after initialization is complete. This implements the traditional game loop. void ApplicationView::Run() { using namespace EA::EAMain; std::unique_ptr winRTRunner(CreateWinRTRunner()); CommandLine commandline(mCommandLine, CommandLine::FLAG_NO_PROGRAM_NAME); winRTRunner->Run(commandline.Argc(),commandline.Argv()); do { // ProcessEvents will throw if the process is exiting, allowing us to // break out of the loop. This will be cleaned up when we get proper // process lifetime management online in a future release. Windows::UI::Core::CoreWindow::GetForCurrentThread()->Dispatcher->ProcessEvents(Windows::UI::Core::CoreProcessEventsOption::ProcessAllIfPresent); } while(!winRTRunner->IsFinished()); winRTRunner->ReportResult(); Windows::ApplicationModel::Core::CoreApplication::Exit(); free(mCommandLine); mCommandLine = nullptr; } void ApplicationView::Uninitialize() { } namespace Internal { EAMAIN_API void StartWinRtApplication() { // To do: store args so they can be passed to EAEntryPointMain. Windows::ApplicationModel::Core::CoreApplication::Run(ref new ApplicationViewSource()); } } // namespace Internal } // namespace EAMain } // namespace EA #endif