Files
jeanlemotan 48ab06b1d9 First
2024-07-02 18:10:39 +02:00

338 lines
12 KiB
C++

///////////////////////////////////////////////////////////////////////////////
// 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 <EAAssert/eaassert.h>
#include <EAMain/EAMain.h>
#include <EAStdC/EASprintf.h>
#include <EAStdC/EAString.h>
EA_DISABLE_ALL_VC_WARNINGS()
#pragma warning(disable: 4472 4355) // additional warnings generated by XDK with VS2015
#include <memory>
#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN
#endif
#include <Windows.h>
#if defined EA_PLATFORM_CAPILANO
#if defined EAMAIN_CAPILANO_DX12
#include <d3d12_x.h>
#else
#include <d3d11_x.h>
#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<TSender,TResult>::{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<TSender,TResult>::{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<SuspendingEventArgs^>([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<Object^>([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^>([](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<char *>(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<size_t>(ftell(fp));
fseek(fp, 0, SEEK_SET);
char *argsBuffer = static_cast<char *>(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<char *>(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<IWinRTRunner> 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