1
0
mirror of https://github.com/borgesdan/xn65 synced 2024-12-29 21:54:47 +01:00
xn65/sources/framework-dx/adapter.cpp

260 lines
8.6 KiB
C++
Raw Permalink Normal View History

2024-09-06 22:23:32 -03:00
#include "xna-dx/framework.hpp"
2024-03-18 15:41:46 -03:00
2024-07-20 19:08:40 -03:00
namespace xna {
static void setOutputVars(comptr<IDXGIAdapter1> const& adapter, String& deviceName, intptr_t& monitorHandle);
2024-04-23 16:11:17 -03:00
static size_t getDisplayModesCount(IDXGIAdapter* adapter);
2024-07-20 22:20:18 -03:00
static sptr<DisplayModeCollection> createDisplayModeCollection(std::vector<DXGI_MODE_DESC1> const& source);
static void setCurrentDisplayMode(DisplayModeCollection& displayModes, SurfaceFormat surfaceFormat, Uint width, Uint height, sptr<DisplayMode>& currentDisplayMode);
static sptr<DisplayModeCollection> getSupportedDisplayModes(comptr<IDXGIAdapter1>& dxAdapter);
2024-03-18 15:41:46 -03:00
2024-05-19 17:52:27 -03:00
GraphicsAdapter::GraphicsAdapter() {
Implementation = unew<GraphicsAdapterImplementation>();
2024-05-19 17:52:27 -03:00
}
uptr<GraphicsAdapter> GraphicsAdapter::DefaultAdapter() {
2024-06-25 17:06:37 -03:00
comptr<IDXGIFactory1> pFactory = nullptr;
2024-07-20 19:08:40 -03:00
2024-06-25 17:06:37 -03:00
if FAILED(CreateDXGIFactory1(__uuidof(IDXGIFactory1), (void**)pFactory.GetAddressOf()))
throw csharp::InvalidOperationException();
2024-04-01 16:18:18 -03:00
2024-06-25 17:06:37 -03:00
comptr<IDXGIAdapter1> pAdapter = nullptr;
2024-07-20 19:08:40 -03:00
2024-06-25 17:06:37 -03:00
if (pFactory->EnumAdapters1(0, pAdapter.GetAddressOf()) != DXGI_ERROR_NOT_FOUND) {
2024-07-20 19:08:40 -03:00
auto adp = uptr<GraphicsAdapter>(new GraphicsAdapter());
adp->Implementation->Adapter = pAdapter;
adp->Implementation->Factory = pFactory;
2024-07-20 19:08:40 -03:00
DXGI_ADAPTER_DESC1 desc{};
pAdapter->GetDesc1(&desc);
adp->description = misc::ToString(desc.Description);
2024-07-20 19:08:40 -03:00
adp->deviceId = static_cast<Uint>(desc.DeviceId);
2024-07-19 22:11:57 -03:00
adp->isDefault = true;
2024-07-20 19:08:40 -03:00
adp->revision = static_cast<Uint>(desc.Revision);
adp->subSystemId = static_cast<Uint>(desc.SubSysId);
adp->vendorId = static_cast<Uint>(desc.VendorId);
setOutputVars(pAdapter, adp->deviceName, adp->monitorHandle);
2024-07-21 21:54:50 -03:00
adp->supportedDisplayModes = getSupportedDisplayModes(pAdapter);
if (adp->supportedDisplayModes && adp->supportedDisplayModes->Count() > 0) {
setCurrentDisplayMode(*adp->supportedDisplayModes, SurfaceFormat::Color,
GraphicsDeviceManager::DefaultBackBufferWidth,
GraphicsDeviceManager::DefaultBackBufferHeight, adp->currentDisplayMode);
}
2024-04-21 16:06:22 -03:00
2024-04-22 16:14:55 -03:00
return adp;
2024-04-21 16:06:22 -03:00
}
return nullptr;
}
2024-05-19 17:52:27 -03:00
void GraphicsAdapter::Adapters(std::vector<uptr<GraphicsAdapter>>& adapters) {
2024-06-25 17:06:37 -03:00
comptr<IDXGIFactory1> pFactory = nullptr;
2024-04-21 16:06:22 -03:00
2024-06-25 17:06:37 -03:00
if FAILED(CreateDXGIFactory1(__uuidof(IDXGIFactory1), (void**)pFactory.GetAddressOf()))
throw csharp::InvalidOperationException();
2024-04-21 16:06:22 -03:00
2024-07-20 19:08:40 -03:00
comptr<IDXGIAdapter1> pAdapter = nullptr;
2024-04-21 16:06:22 -03:00
2024-07-16 12:28:03 -03:00
for (UINT count = 0; pFactory->EnumAdapters1(count, pAdapter.GetAddressOf()) != DXGI_ERROR_NOT_FOUND; ++count) {
2024-07-20 19:08:40 -03:00
auto adp = uptr<GraphicsAdapter>(new GraphicsAdapter());
2024-04-21 16:06:22 -03:00
adp->Implementation->Adapter = pAdapter;
adp->Implementation->Factory = pFactory;
2024-04-21 16:06:22 -03:00
2024-07-20 19:08:40 -03:00
DXGI_ADAPTER_DESC1 desc{};
pAdapter->GetDesc1(&desc);
adp->description = misc::ToString(desc.Description);
2024-07-20 19:08:40 -03:00
adp->deviceId = static_cast<Uint>(desc.DeviceId);
2024-07-19 22:11:57 -03:00
adp->isDefault = count == 0;
2024-07-20 19:08:40 -03:00
adp->revision = static_cast<Uint>(desc.Revision);
adp->subSystemId = static_cast<Uint>(desc.SubSysId);
adp->vendorId = static_cast<Uint>(desc.VendorId);
setOutputVars(pAdapter, adp->deviceName, adp->monitorHandle);
2024-07-20 22:20:18 -03:00
adp->supportedDisplayModes = getSupportedDisplayModes(pAdapter);
if (adp->supportedDisplayModes && adp->supportedDisplayModes->Count() > 0) {
setCurrentDisplayMode(*adp->supportedDisplayModes, SurfaceFormat::Color,
GraphicsDeviceManager::DefaultBackBufferWidth,
GraphicsDeviceManager::DefaultBackBufferHeight, adp->currentDisplayMode);
}
2024-07-19 22:11:57 -03:00
adapters.push_back(std::move(adp));
2024-03-18 15:41:46 -03:00
}
2024-07-20 19:08:40 -03:00
}
2024-07-20 23:44:10 -03:00
bool GraphicsAdapter::QueryBackBufferFormat(
GraphicsProfile graphicsProfile, SurfaceFormat format,
DepthFormat depthFormat, Int multiSampleCount,
SurfaceFormat& selectedFormat, DepthFormat& selectedDepthFormat,
Int& selectedMultiSampleCount) const
{
2024-07-21 20:37:16 -03:00
selectedFormat = format;
selectedDepthFormat = depthFormat;
selectedMultiSampleCount = multiSampleCount;
2024-07-20 23:44:10 -03:00
comptr<IDXGIOutput> pOutput = nullptr;
if (Implementation->Adapter->EnumOutputs(0, pOutput.GetAddressOf()) != DXGI_ERROR_NOT_FOUND){
2024-07-20 23:44:10 -03:00
comptr<IDXGIOutput1> pOutput1 = nullptr;
pOutput->QueryInterface(IID_IDXGIOutput1, (void**)pOutput1.GetAddressOf());
DXGI_MODE_DESC1 modeToMath{};
2024-07-21 20:37:16 -03:00
modeToMath.Format = DxHelpers::SurfaceFormatToDx(format);
//If pConcernedDevice is NULL, the Format member of DXGI_MODE_DESC1 cannot be DXGI_FORMAT_UNKNOWN.
if (modeToMath.Format == DXGI_FORMAT_UNKNOWN)
return false;
2024-07-20 23:44:10 -03:00
DXGI_MODE_DESC1 closestMath;
2024-07-21 20:37:16 -03:00
const auto hresult = pOutput1->FindClosestMatchingMode1(&modeToMath, &closestMath, nullptr);
if FAILED(hresult)
return false;
2024-07-20 23:44:10 -03:00
selectedFormat = DxHelpers::SurfaceFormatToXna(closestMath.Format);
return selectedFormat == format;
}
return false;
}
2024-07-20 22:20:18 -03:00
//INTERNAL FUNCTIONS
2024-04-21 16:06:22 -03:00
2024-07-20 22:20:18 -03:00
sptr<DisplayModeCollection> getSupportedDisplayModes(comptr<IDXGIAdapter1>& dxAdapter) {
const auto totalDisplay = getDisplayModesCount(dxAdapter.Get());
2024-04-22 11:22:18 -03:00
if (totalDisplay == 0)
return nullptr;
2024-07-16 12:28:03 -03:00
comptr<IDXGIOutput> pOutput = nullptr;
2024-07-20 22:20:18 -03:00
comptr<IDXGIOutput1> pOutput1 = nullptr;
2024-04-22 11:22:18 -03:00
UINT bufferOffset = 0;
2024-07-20 19:08:40 -03:00
2024-07-20 22:20:18 -03:00
std::vector<DXGI_MODE_DESC1> buffer(totalDisplay);
2024-07-20 19:08:40 -03:00
2024-07-20 22:20:18 -03:00
if (dxAdapter->EnumOutputs(0, pOutput.GetAddressOf()) != DXGI_ERROR_NOT_FOUND) {
2024-03-18 15:41:46 -03:00
for (size_t f = 0; f < SURFACE_FORMAT_COUNT; ++f) {
const auto currentSurface = static_cast<SurfaceFormat>(f);
2024-06-22 22:05:35 -03:00
DXGI_FORMAT format = DxHelpers::SurfaceFormatToDx(currentSurface);
2024-03-18 15:41:46 -03:00
2024-04-22 11:22:18 -03:00
UINT numModes = 0;
2024-07-20 22:20:18 -03:00
if (!pOutput1) {
pOutput->QueryInterface(IID_IDXGIOutput1, (void**)pOutput1.GetAddressOf());
}
//See ref: https://learn.microsoft.com/en-us/windows/win32/api/dxgi/nf-dxgi-idxgioutput-getdisplaymodelist?redirectedfrom=MSDN
pOutput1->GetDisplayModeList1(format, 0, &numModes, nullptr);
2024-03-18 15:41:46 -03:00
if (numModes == 0)
2024-07-20 19:08:40 -03:00
continue;
2024-03-18 15:41:46 -03:00
2024-07-20 22:20:18 -03:00
pOutput1->GetDisplayModeList1(format, 0, &numModes, buffer.data() + bufferOffset);
2024-03-18 15:41:46 -03:00
2024-04-22 11:22:18 -03:00
bufferOffset += numModes;
2024-07-20 19:08:40 -03:00
}
2024-04-21 20:03:36 -03:00
}
2024-03-18 15:41:46 -03:00
2024-04-21 20:03:36 -03:00
if (!pOutput)
return nullptr;
2024-04-23 16:11:17 -03:00
return createDisplayModeCollection(buffer);
2024-07-20 22:20:18 -03:00
}
2024-04-23 16:11:17 -03:00
2024-07-20 22:20:18 -03:00
void setCurrentDisplayMode(DisplayModeCollection& displayModes, SurfaceFormat surfaceFormat, Uint width, Uint height, sptr<DisplayMode>& currentDisplayMode) {
auto modes = displayModes.Query(surfaceFormat);
2024-04-23 16:11:17 -03:00
2024-07-20 22:20:18 -03:00
for (size_t i = 0; i < modes.size(); ++i) {
auto& m = modes[i];
2024-07-19 22:11:57 -03:00
2024-07-19 23:21:25 -03:00
if (m->Format() == surfaceFormat && m->Width() == width && m->Height() == height) {
2024-07-19 22:11:57 -03:00
currentDisplayMode = m;
}
2024-07-20 22:20:18 -03:00
else if (i + 1 == modes.size()) {
2024-07-19 22:11:57 -03:00
currentDisplayMode = m;
}
}
}
size_t getDisplayModesCount(IDXGIAdapter* adapter) {
2024-07-20 22:20:18 -03:00
comptr<IDXGIOutput> pOutput = nullptr;
comptr<IDXGIOutput1> pOutput1 = nullptr;
size_t numModes = 0;
2024-04-23 16:11:17 -03:00
2024-07-20 22:20:18 -03:00
2024-07-16 12:28:03 -03:00
if (adapter->EnumOutputs(0, pOutput.GetAddressOf()) != DXGI_ERROR_NOT_FOUND) {
2024-04-23 16:11:17 -03:00
for (size_t f = 0; f < SURFACE_FORMAT_COUNT; ++f) {
const auto currentSurface = static_cast<SurfaceFormat>(f);
2024-06-22 22:05:35 -03:00
DXGI_FORMAT format = DxHelpers::SurfaceFormatToDx(currentSurface);
2024-04-23 16:11:17 -03:00
UINT num = 0;
2024-07-20 22:20:18 -03:00
if (!pOutput1) {
pOutput->QueryInterface(IID_IDXGIOutput1, (void**)pOutput1.GetAddressOf());
}
//See ref: https://learn.microsoft.com/en-us/windows/win32/api/dxgi/nf-dxgi-idxgioutput-getdisplaymodelist?redirectedfrom=MSDN
pOutput1->GetDisplayModeList1(format, 0, &num, nullptr);
2024-04-23 16:11:17 -03:00
numModes += num;
2024-07-20 19:08:40 -03:00
}
2024-04-23 16:11:17 -03:00
}
return numModes;
}
2024-07-20 22:20:18 -03:00
sptr<DisplayModeCollection> createDisplayModeCollection(std::vector<DXGI_MODE_DESC1> const& source) {
auto collection = snew<DisplayModeCollection>();
2024-07-20 19:08:40 -03:00
2024-04-26 11:35:59 -03:00
std::vector<sptr<DisplayMode>> displayList;
sptr<DisplayMode> pDisplay = nullptr;
2024-04-21 20:03:36 -03:00
2024-04-23 16:11:17 -03:00
for (size_t i = 0; i < source.size(); ++i) {
auto& modedesc = source[i];
2024-04-21 20:03:36 -03:00
2024-07-19 23:21:25 -03:00
DisplayModeRate rate;
rate.RefreshRate.Denominator = modedesc.RefreshRate.Denominator;
rate.RefreshRate.Numerator = modedesc.RefreshRate.Numerator;
rate.Scaling = static_cast<DisplayModeScaling>(modedesc.Scaling);
rate.ScanlineOrdering = static_cast<DisplayModeScanlineOrder>(modedesc.ScanlineOrdering);
2024-04-21 20:03:36 -03:00
2024-07-19 23:21:25 -03:00
if (pDisplay && pDisplay->Width() == modedesc.Width && pDisplay->Height() == modedesc.Height && pDisplay->Format() == DxHelpers::SurfaceFormatToXna(modedesc.Format)) {
pDisplay->Rates.push_back(rate);
2024-04-21 20:03:36 -03:00
}
else {
2024-07-19 23:21:25 -03:00
pDisplay = snew<DisplayMode>(
modedesc.Width,
2024-07-20 19:08:40 -03:00
modedesc.Height,
2024-07-19 23:21:25 -03:00
DxHelpers::SurfaceFormatToXna(modedesc.Format));
2024-07-20 19:08:40 -03:00
2024-07-19 23:21:25 -03:00
pDisplay->Rates.push_back(rate);
2024-04-21 20:03:36 -03:00
displayList.push_back(pDisplay);
}
2024-03-18 15:41:46 -03:00
}
2024-05-20 11:51:32 -03:00
collection->DisplayModes = displayList;
2024-04-21 20:03:36 -03:00
2024-04-23 16:11:17 -03:00
return collection;
2024-07-20 19:08:40 -03:00
}
2024-07-19 22:11:57 -03:00
2024-07-20 19:08:40 -03:00
static void setOutputVars(comptr<IDXGIAdapter1> const& adapter, String& deviceName, intptr_t& monitorHandle) {
2024-07-19 22:11:57 -03:00
comptr<IDXGIOutput> pOutput = nullptr;
if (adapter->EnumOutputs(0, pOutput.GetAddressOf()) != DXGI_ERROR_NOT_FOUND) {
DXGI_OUTPUT_DESC outputDesc;
pOutput->GetDesc(&outputDesc);
deviceName = misc::ToString(outputDesc.DeviceName);
2024-07-20 19:08:40 -03:00
monitorHandle = reinterpret_cast<intptr_t>(outputDesc.Monitor);
2024-07-19 22:11:57 -03:00
}
}
2024-03-18 15:41:46 -03:00
}