#include "xna/graphics/adapter.hpp" #include "xna/graphics/displaymode.hpp" #include "xna/game/gdevicemanager.hpp" #include "xna/xna-dx.hpp" namespace xna { static void setOutputVars(comptr const& adapter, String& deviceName, intptr_t& monitorHandle); static size_t getDisplayModesCount(IDXGIAdapter* adapter); static uptr createDisplayModeCollection(std::vector const& source); static void setCurrentDisplayMode(GraphicsAdapter& adapter, SurfaceFormat surfaceFormat, Uint width, Uint height, sptr& currentDisplayMode); GraphicsAdapter::GraphicsAdapter() { impl = unew(); } uptr GraphicsAdapter::DefaultAdapter() { comptr pFactory = nullptr; if FAILED(CreateDXGIFactory1(__uuidof(IDXGIFactory1), (void**)pFactory.GetAddressOf())) Exception::Throw(Exception::FAILED_TO_CREATE); comptr pAdapter = nullptr; if (pFactory->EnumAdapters1(0, pAdapter.GetAddressOf()) != DXGI_ERROR_NOT_FOUND) { auto adp = uptr(new GraphicsAdapter()); adp->impl->dxAdapter = pAdapter; adp->impl->dxFactory = pFactory; DXGI_ADAPTER_DESC1 desc{}; pAdapter->GetDesc1(&desc); adp->description = XnaHelper::ToString(desc.Description); adp->deviceId = static_cast(desc.DeviceId); adp->isDefault = true; adp->revision = static_cast(desc.Revision); adp->subSystemId = static_cast(desc.SubSysId); adp->vendorId = static_cast(desc.VendorId); setOutputVars(pAdapter, adp->deviceName, adp->monitorHandle); setCurrentDisplayMode(*adp, SurfaceFormat::Color, GraphicsDeviceManager::DefaultBackBufferWidth, GraphicsDeviceManager::DefaultBackBufferHeight, adp->currentDisplayMode); return adp; } return nullptr; } void GraphicsAdapter::Adapters(std::vector>& adapters) { comptr pFactory = nullptr; if FAILED(CreateDXGIFactory1(__uuidof(IDXGIFactory1), (void**)pFactory.GetAddressOf())) Exception::Throw(Exception::FAILED_TO_CREATE); comptr pAdapter = nullptr; for (UINT count = 0; pFactory->EnumAdapters1(count, pAdapter.GetAddressOf()) != DXGI_ERROR_NOT_FOUND; ++count) { auto adp = uptr(new GraphicsAdapter()); adp->impl->dxAdapter = pAdapter; adp->impl->dxFactory = pFactory; DXGI_ADAPTER_DESC1 desc{}; pAdapter->GetDesc1(&desc); adp->description = XnaHelper::ToString(desc.Description); adp->deviceId = static_cast(desc.DeviceId); adp->isDefault = count == 0; adp->revision = static_cast(desc.Revision); adp->subSystemId = static_cast(desc.SubSysId); adp->vendorId = static_cast(desc.VendorId); setOutputVars(pAdapter, adp->deviceName, adp->monitorHandle); setCurrentDisplayMode(*adp, SurfaceFormat::Color, GraphicsDeviceManager::DefaultBackBufferWidth, GraphicsDeviceManager::DefaultBackBufferHeight, adp->currentDisplayMode); adapters.push_back(std::move(adp)); } } uptr GraphicsAdapter::SupportedDisplayModes() const { if (!impl->dxAdapter) return nullptr; const auto totalDisplay = getDisplayModesCount(impl->dxAdapter.Get()); if (totalDisplay == 0) return nullptr; comptr pOutput = nullptr; UINT bufferOffset = 0; std::vector buffer(totalDisplay); if (impl->dxAdapter->EnumOutputs(0, pOutput.GetAddressOf()) != DXGI_ERROR_NOT_FOUND) { for (size_t f = 0; f < SURFACE_FORMAT_COUNT; ++f) { const auto currentSurface = static_cast(f); DXGI_FORMAT format = DxHelpers::SurfaceFormatToDx(currentSurface); UINT numModes = 0; pOutput->GetDisplayModeList(format, 0, &numModes, nullptr); if (numModes == 0) continue; pOutput->GetDisplayModeList(format, 0, &numModes, buffer.data() + bufferOffset); bufferOffset += numModes; } } if (!pOutput) return nullptr; return createDisplayModeCollection(buffer); } uptr GraphicsAdapter::SupportedDisplayModes(SurfaceFormat surfaceFormat) const { if (!impl->dxAdapter) return nullptr; comptr pOutput = nullptr; UINT bufferOffset = 0; if (impl->dxAdapter->EnumOutputs(0, pOutput.GetAddressOf()) != DXGI_ERROR_NOT_FOUND) { DXGI_FORMAT format = DxHelpers::SurfaceFormatToDx(surfaceFormat); UINT numModes = 0; pOutput->GetDisplayModeList(format, 0, &numModes, nullptr); if (numModes == 0) return unew(); std::vector buffer(numModes); pOutput->GetDisplayModeList(format, 0, &numModes, buffer.data()); return createDisplayModeCollection(buffer); } return unew(); } bool GraphicsAdapter::PlatformImplementation::GetOutput(UINT slot, IDXGIOutput*& output) const { if (!dxAdapter) return false; if (dxAdapter->EnumOutputs(slot, &output) != DXGI_ERROR_NOT_FOUND) return true; return false; } //INTERNAL FUNCTIONS void setCurrentDisplayMode(GraphicsAdapter& adapter, SurfaceFormat surfaceFormat, Uint width, Uint height, sptr& currentDisplayMode) { const auto modes = adapter.SupportedDisplayModes(surfaceFormat); for (size_t i = 0; i < modes->DisplayModes.size(); ++i) { auto& m = modes->DisplayModes[i]; if (m->Format() == surfaceFormat && m->Width() == width && m->Height() == height) { currentDisplayMode = m; } else if (i + 1 == modes->DisplayModes.size()) { currentDisplayMode = m; } } } size_t getDisplayModesCount(IDXGIAdapter* adapter) { comptr pOutput = nullptr; size_t numModes = 0; if (adapter->EnumOutputs(0, pOutput.GetAddressOf()) != DXGI_ERROR_NOT_FOUND) { for (size_t f = 0; f < SURFACE_FORMAT_COUNT; ++f) { const auto currentSurface = static_cast(f); DXGI_FORMAT format = DxHelpers::SurfaceFormatToDx(currentSurface); UINT num = 0; pOutput->GetDisplayModeList(format, 0, &num, nullptr); numModes += num; } } return numModes; } uptr createDisplayModeCollection(std::vector const& source) { auto collection = unew(); std::vector> displayList; sptr pDisplay = nullptr; for (size_t i = 0; i < source.size(); ++i) { auto& modedesc = source[i]; DisplayModeRate rate; rate.RefreshRate.Denominator = modedesc.RefreshRate.Denominator; rate.RefreshRate.Numerator = modedesc.RefreshRate.Numerator; rate.Scaling = static_cast(modedesc.Scaling); rate.ScanlineOrdering = static_cast(modedesc.ScanlineOrdering); if (pDisplay && pDisplay->Width() == modedesc.Width && pDisplay->Height() == modedesc.Height && pDisplay->Format() == DxHelpers::SurfaceFormatToXna(modedesc.Format)) { pDisplay->Rates.push_back(rate); } else { pDisplay = snew( modedesc.Width, modedesc.Height, DxHelpers::SurfaceFormatToXna(modedesc.Format)); pDisplay->Rates.push_back(rate); displayList.push_back(pDisplay); } } collection->DisplayModes = displayList; return collection; } static void setOutputVars(comptr const& adapter, String& deviceName, intptr_t& monitorHandle) { comptr pOutput = nullptr; if (adapter->EnumOutputs(0, pOutput.GetAddressOf()) != DXGI_ERROR_NOT_FOUND) { DXGI_OUTPUT_DESC outputDesc; pOutput->GetDesc(&outputDesc); deviceName = XnaHelper::ToString(outputDesc.DeviceName); monitorHandle = reinterpret_cast(outputDesc.Monitor); } } }