diff --git a/src/dxgi/dxgi_adapter.cpp b/src/dxgi/dxgi_adapter.cpp new file mode 100644 index 00000000..e067ad05 --- /dev/null +++ b/src/dxgi/dxgi_adapter.cpp @@ -0,0 +1,105 @@ +#include +#include + +#include "dxgi_adapter.h" +#include "dxgi_factory.h" +#include "dxgi_output.h" + +namespace dxvk { + + DxgiAdapter::DxgiAdapter( + DxgiFactory* factory, + const Rc& adapter) + : m_factory (factory), + m_adapter (adapter) { + TRACE(this, factory, adapter); + } + + + DxgiAdapter::~DxgiAdapter() { + TRACE(this); + } + + + HRESULT DxgiAdapter::QueryInterface( + REFIID riid, + void **ppvObject) { + COM_QUERY_IFACE(riid, ppvObject, IDXGIAdapter); + + Logger::warn("DxgiAdapter::QueryInterface: Unknown interface query"); + return E_NOINTERFACE; + } + + + HRESULT DxgiAdapter::GetParent( + REFIID riid, + void **ppParent) { + return m_factory->QueryInterface(riid, ppParent); + } + + + HRESULT DxgiAdapter::CheckInterfaceSupport( + REFGUID InterfaceName, + LARGE_INTEGER *pUMDVersion) { + Logger::err("DxgiAdapter::CheckInterfaceSupport: No D3D10 support"); + return DXGI_ERROR_UNSUPPORTED; + } + + + HRESULT DxgiAdapter::EnumOutputs( + UINT Output, + IDXGIOutput **ppOutput) { + TRACE(this, Output, ppOutput); + + if (ppOutput == nullptr) + return DXGI_ERROR_INVALID_CALL; + + int numDisplays = SDL_GetNumVideoDisplays(); + + if (numDisplays < 0) { + Logger::err("DxgiAdapter::EnumOutputs: Failed to query display count"); + return DXGI_ERROR_DRIVER_INTERNAL_ERROR; + } + + if (Output >= static_cast(numDisplays)) + return DXGI_ERROR_NOT_FOUND; + + *ppOutput = ref(new DxgiOutput(this, Output)); + return S_OK; + } + + + HRESULT DxgiAdapter::GetDesc(DXGI_ADAPTER_DESC* pDesc) { + if (pDesc == nullptr) + return DXGI_ERROR_INVALID_CALL; + + const auto deviceProp = m_adapter->deviceProperties(); + const auto memoryProp = m_adapter->memoryProperties(); + + std::memset(pDesc->Description, 0, sizeof(pDesc->Description)); + std::mbstowcs(pDesc->Description, deviceProp.deviceName, _countof(pDesc->Description) - 1); + + VkDeviceSize deviceMemory = 0; + VkDeviceSize sharedMemory = 0; + + for (uint32_t i = 0; i < memoryProp.memoryHeapCount; i++) { + VkMemoryHeap heap = memoryProp.memoryHeaps[i]; + + if (heap.flags & VK_MEMORY_HEAP_DEVICE_LOCAL_BIT) + deviceMemory += heap.size; + else + sharedMemory += heap.size; + } + + pDesc->VendorId = deviceProp.vendorID; + pDesc->DeviceId = deviceProp.deviceID; + pDesc->SubSysId = 0; + pDesc->Revision = 0; + pDesc->DedicatedVideoMemory = deviceMemory; + pDesc->DedicatedSystemMemory = 0; + pDesc->SharedSystemMemory = sharedMemory; + pDesc->AdapterLuid = LUID { 0, 0 }; // TODO implement + return S_OK; + } + +} diff --git a/src/dxgi/dxgi_adapter.h b/src/dxgi/dxgi_adapter.h new file mode 100644 index 00000000..972ecd6f --- /dev/null +++ b/src/dxgi/dxgi_adapter.h @@ -0,0 +1,50 @@ +#pragma once + +#include +#include + +#include + +#include "dxgi_object.h" + +namespace dxvk { + + class DxgiFactory; + class DxgiOutput; + + class DxgiAdapter : public DxgiObject { + + public: + + DxgiAdapter( + DxgiFactory* factory, + const Rc& adapter); + ~DxgiAdapter(); + + HRESULT QueryInterface( + REFIID riid, + void **ppvObject) final; + + HRESULT GetParent( + REFIID riid, + void **ppParent) final; + + HRESULT CheckInterfaceSupport( + REFGUID InterfaceName, + LARGE_INTEGER *pUMDVersion) final; + + HRESULT EnumOutputs( + UINT Output, + IDXGIOutput **ppOutput) final; + + HRESULT GetDesc( + DXGI_ADAPTER_DESC *pDesc) final; + + private: + + DxgiFactory* m_factory; + Rc m_adapter; + + }; + +} diff --git a/src/dxgi/dxgi_factory.cpp b/src/dxgi/dxgi_factory.cpp new file mode 100644 index 00000000..82d92de5 --- /dev/null +++ b/src/dxgi/dxgi_factory.cpp @@ -0,0 +1,88 @@ +#include "dxgi_factory.h" +#include "dxgi_swapchain.h" + +namespace dxvk { + + DxgiFactory::DxgiFactory() + : m_instance(new DxvkInstance()) { + TRACE(this); + + auto adapters = m_instance->enumAdapters(); + for (auto a : adapters) + m_adapters.push_back(new DxgiAdapter(this, a)); + } + + + DxgiFactory::~DxgiFactory() { + TRACE(this); + } + + + HRESULT DxgiFactory::QueryInterface( + REFIID riid, + void** ppvObject) { + COM_QUERY_IFACE(riid, ppvObject, IDXGIFactory); + + Logger::warn("DxgiFactory::QueryInterface: Unknown interface query"); + return E_NOINTERFACE; + } + + + HRESULT DxgiFactory::GetParent( + REFIID riid, + void** ppParent) { + Logger::warn("DxgiFactory::GetParent: Unknown interface query"); + return E_NOINTERFACE; + } + + + HRESULT DxgiFactory::CreateSoftwareAdapter( + HMODULE Module, + IDXGIAdapter** ppAdapter) { + Logger::err("DxgiFactory::CreateSoftwareAdapter: Software adapters not supported"); + return DXGI_ERROR_UNSUPPORTED; + } + + + HRESULT DxgiFactory::CreateSwapChain( + IUnknown* pDevice, + DXGI_SWAP_CHAIN_DESC* pDesc, + IDXGISwapChain** ppSwapChain) { + TRACE(this, pDevice, pDesc, ppSwapChain); + return DXGI_ERROR_UNSUPPORTED; + } + + + HRESULT DxgiFactory::EnumAdapters( + UINT Adapter, + IDXGIAdapter** ppAdapter) { + TRACE(this, Adapter, ppAdapter); + + if (ppAdapter == nullptr) + return DXGI_ERROR_INVALID_CALL; + + if (Adapter >= m_adapters.size()) + return DXGI_ERROR_NOT_FOUND; + + *ppAdapter = m_adapters.at(Adapter).ref(); + return S_OK; + } + + + HRESULT DxgiFactory::GetWindowAssociation(HWND *pWindowHandle) { + if (pWindowHandle == nullptr) + return DXGI_ERROR_INVALID_CALL; + + *pWindowHandle = m_associatedWindow; + return S_OK; + } + + + HRESULT DxgiFactory::MakeWindowAssociation(HWND WindowHandle, UINT Flags) { + TRACE(this, WindowHandle, Flags); + Logger::warn("DxgiFactory::MakeWindowAssociation: Ignoring flags"); + m_associatedWindow = WindowHandle; + return S_OK; + } + +} diff --git a/src/dxgi/dxgi_factory.h b/src/dxgi/dxgi_factory.h new file mode 100644 index 00000000..6903dc45 --- /dev/null +++ b/src/dxgi/dxgi_factory.h @@ -0,0 +1,55 @@ +#pragma once + +#include + +#include + +#include "dxgi_adapter.h" + +namespace dxvk { + + class DxgiFactory : public DxgiObject { + + public: + + DxgiFactory(); + ~DxgiFactory(); + + HRESULT QueryInterface( + REFIID riid, + void** ppvObject) final; + + HRESULT GetParent( + REFIID riid, + void** ppParent) final; + + HRESULT CreateSoftwareAdapter( + HMODULE Module, + IDXGIAdapter** ppAdapter) final; + + HRESULT CreateSwapChain( + IUnknown* pDevice, + DXGI_SWAP_CHAIN_DESC* pDesc, + IDXGISwapChain** ppSwapChain) final; + + HRESULT EnumAdapters( + UINT Adapter, + IDXGIAdapter** ppAdapter) final; + + HRESULT GetWindowAssociation( + HWND *pWindowHandle) final; + + HRESULT MakeWindowAssociation( + HWND WindowHandle, + UINT Flags) final; + + private: + + Rc m_instance; + std::vector> m_adapters; + + HWND m_associatedWindow = nullptr; + + }; + +} diff --git a/src/dxgi/dxgi_include.h b/src/dxgi/dxgi_include.h new file mode 100644 index 00000000..5fab09b3 --- /dev/null +++ b/src/dxgi/dxgi_include.h @@ -0,0 +1,18 @@ +#pragma once + +#define DLLEXPORT __declspec(dllexport) + +#include "../util/com/com_guid.h" +#include "../util/com/com_object.h" +#include "../util/com/com_pointer.h" + +#include "../util/log/log.h" +#include "../util/log/log_debug.h" + +#include "../util/util_enum.h" +#include "../util/util_error.h" +#include "../util/util_string.h" + +#include + +#include diff --git a/src/dxgi/dxgi_main.cpp b/src/dxgi/dxgi_main.cpp new file mode 100644 index 00000000..5fe9fa43 --- /dev/null +++ b/src/dxgi/dxgi_main.cpp @@ -0,0 +1,48 @@ +#include "dxgi_factory.h" +#include "dxgi_include.h" + +namespace dxvk { + + struct SdlInstance { + SdlInstance() { + TRACE(this); + + if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_NOPARACHUTE)) + Logger::err("Instance::init: Failed to initialize SDL"); + } + + ~SdlInstance() { + TRACE(this); + SDL_Quit(); + } + }; + + SdlInstance sdl; + + HRESULT createDxgiFactory(REFIID riid, void **ppFactory) { + TRACE(riid, ppFactory); + + if (riid != __uuidof(IDXGIFactory)) { + Logger::err("CreateDXGIFactory: Requested version of IDXGIFactory not supported"); + return DXGI_ERROR_UNSUPPORTED; + } + + try { + *ppFactory = ref(new DxgiFactory()); + return S_OK; + } catch (const DxvkError& err) { + Logger::err(err.message()); + return DXGI_ERROR_UNSUPPORTED; + } + } +} + +extern "C" { + DLLEXPORT HRESULT __stdcall CreateDXGIFactory1(REFIID riid, void **ppFactory) { + return dxvk::createDxgiFactory(riid, ppFactory); + } + + DLLEXPORT HRESULT __stdcall CreateDXGIFactory(REFIID riid, void **ppFactory) { + return dxvk::createDxgiFactory(riid, ppFactory); + } +} \ No newline at end of file diff --git a/src/dxgi/dxgi_object.h b/src/dxgi/dxgi_object.h new file mode 100644 index 00000000..004b6dbb --- /dev/null +++ b/src/dxgi/dxgi_object.h @@ -0,0 +1,41 @@ +#pragma once + +#include "dxgi_private_data.h" + +namespace dxvk { + + template + class DxgiObject : public ComObject { + + public: + + HRESULT GetPrivateData( + REFGUID Name, + UINT *pDataSize, + void *pData) final { + return m_privateData.getData( + Name, pDataSize, pData); + } + + HRESULT SetPrivateData( + REFGUID Name, + UINT DataSize, + const void *pData) final { + return m_privateData.setData( + Name, DataSize, pData); + } + + HRESULT SetPrivateDataInterface( + REFGUID Name, + const IUnknown *pUnknown) final { + return m_privateData.setInterface( + Name, pUnknown); + } + + private: + + DxgiPrivateData m_privateData; + + }; + +} diff --git a/src/dxgi/dxgi_output.cpp b/src/dxgi/dxgi_output.cpp new file mode 100644 index 00000000..4f027372 --- /dev/null +++ b/src/dxgi/dxgi_output.cpp @@ -0,0 +1,244 @@ +#include +#include + +#include +#include + +#include "dxgi_adapter.h" +#include "dxgi_output.h" + +namespace dxvk { + + DxgiOutput::DxgiOutput( + DxgiAdapter* adapter, + UINT display) + : m_adapter (adapter), + m_display (display) { + TRACE(this, adapter); + } + + + DxgiOutput::~DxgiOutput() { + TRACE(this); + } + + + HRESULT DxgiOutput::QueryInterface( + REFIID riid, + void **ppvObject) { + COM_QUERY_IFACE(riid, ppvObject, IDXGIOutput); + + Logger::warn("DxgiOutput::QueryInterface: Unknown interface query"); + return E_NOINTERFACE; + } + + + HRESULT DxgiOutput::GetParent( + REFIID riid, + void **ppParent) { + return m_adapter->QueryInterface(riid, ppParent); + } + + + HRESULT DxgiOutput::FindClosestMatchingMode( + const DXGI_MODE_DESC *pModeToMatch, + DXGI_MODE_DESC *pClosestMatch, + IUnknown *pConcernedDevice) { + Logger::err("DxgiOutput::FindClosestMatchingMode: Not implemented"); + return E_NOTIMPL; + } + + + HRESULT DxgiOutput::GetDesc(DXGI_OUTPUT_DESC *pDesc) { + if (pDesc == nullptr) + return DXGI_ERROR_INVALID_CALL; + + // Display name, Windows requires wide chars + const char* displayName = SDL_GetDisplayName(m_display); + + if (displayName == nullptr) { + Logger::err("DxgiOutput::GetDesc: Failed to get display name"); + return DXGI_ERROR_DRIVER_INTERNAL_ERROR; + } + + std::memset(pDesc->DeviceName, 0, sizeof(pDesc->DeviceName)); + std::mbstowcs(pDesc->DeviceName, displayName, _countof(pDesc->DeviceName) - 1); + + // Current desktop rect of the display + SDL_Rect rect; + + if (SDL_GetDisplayBounds(m_display, &rect)) { + Logger::err("DxgiOutput::GetDesc: Failed to get display bounds"); + return DXGI_ERROR_DRIVER_INTERNAL_ERROR; + } + + pDesc->DesktopCoordinates.left = rect.x; + pDesc->DesktopCoordinates.top = rect.y; + pDesc->DesktopCoordinates.right = rect.x + rect.w; + pDesc->DesktopCoordinates.bottom = rect.y + rect.h; + + // We don't have any info for these + pDesc->AttachedToDesktop = 1; + pDesc->Rotation = DXGI_MODE_ROTATION_UNSPECIFIED; + pDesc->Monitor = nullptr; + return S_OK; + } + + + HRESULT DxgiOutput::GetDisplayModeList( + DXGI_FORMAT EnumFormat, + UINT Flags, + UINT *pNumModes, + DXGI_MODE_DESC *pDesc) { + TRACE(this, EnumFormat, Flags, pNumModes, pDesc); + + if (pNumModes == nullptr) + return DXGI_ERROR_INVALID_CALL; + + // In order to check whether a display mode is 'centered' or + // 'streched' in DXGI terms, we compare its size to the desktop + // 'mode. If they are the same, we consider the mode to be + // 'centered', which most games will prefer over 'streched'. + SDL_DisplayMode desktopMode; + + if (SDL_GetDesktopDisplayMode(m_display, &desktopMode)) { + Logger::err("DxgiOutput::GetDisplayModeList: Failed to list display modes"); + return DXGI_ERROR_DRIVER_INTERNAL_ERROR; + } + + // Create a list of suitable display modes. Because of the way DXGI + // swapchains are handled by DXVK, we can ignore the format constraints + // here and just pick whatever modes SDL returns for the current display. + std::vector modes; + + int numDisplayModes = SDL_GetNumDisplayModes(m_display); + + if (numDisplayModes < 0) { + Logger::err("DxgiOutput::GetDisplayModeList: Failed to list display modes"); + return DXGI_ERROR_DRIVER_INTERNAL_ERROR; + } + + for (int i = 0; i < numDisplayModes; i++) { + SDL_DisplayMode currMode; + + if (SDL_GetDisplayMode(m_display, i, &currMode)) { + Logger::err("DxgiOutput::GetDisplayModeList: Failed to list display modes"); + return DXGI_ERROR_DRIVER_INTERNAL_ERROR; + } + + // We don't want duplicates, so we'll filter out modes + // with matching resolution and refresh rate. + bool hasMode = false; + + for (int j = 0; j < i && !hasMode; j++) { + SDL_DisplayMode testMode; + + if (SDL_GetDisplayMode(m_display, j, &testMode)) { + Logger::err("DxgiOutput::GetDisplayModeList: Failed to list display modes"); + return DXGI_ERROR_DRIVER_INTERNAL_ERROR; + } + + hasMode = testMode.w == currMode.w + && testMode.h == currMode.h + && testMode.refresh_rate == currMode.refresh_rate; + } + + // Convert the SDL display mode to a DXGI display mode info + // structure and filter out any unwanted modes based on the + // supplied flags. + if (!hasMode) { + bool isNativeMode = (currMode.w == desktopMode.w) + && (currMode.h == desktopMode.h); + + if (isNativeMode || (Flags & DXGI_ENUM_MODES_SCALING)) { + DXGI_MODE_DESC mode; + mode.Width = currMode.w; + mode.Height = currMode.h; + mode.RefreshRate.Numerator = currMode.refresh_rate; + mode.RefreshRate.Denominator = 1; + mode.Format = EnumFormat; + mode.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_PROGRESSIVE; + mode.Scaling = isNativeMode + ? DXGI_MODE_SCALING_CENTERED + : DXGI_MODE_SCALING_STRETCHED; + modes.push_back(mode); + } + } + } + + // Copy list of display modes to the application-provided + // destination buffer. The buffer may not be appropriately + // sized by the time this is called. + if (pDesc != nullptr) { + for (uint32_t i = 0; i < modes.size() && i < *pNumModes; i++) + pDesc[i] = modes.at(i); + } + + // If the buffer is too small, we shall ask the application + // to query the display mode list again by returning the + // appropriate DXGI error code. + if ((pDesc == nullptr) || (modes.size() <= *pNumModes)) { + *pNumModes = modes.size(); + return S_OK; + } else { + return DXGI_ERROR_MORE_DATA; + } + + } + + + HRESULT DxgiOutput::GetDisplaySurfaceData(IDXGISurface *pDestination) { + Logger::err("DxgiOutput::GetDisplaySurfaceData: Not implemented"); + return E_NOTIMPL; + } + + + HRESULT DxgiOutput::GetFrameStatistics(DXGI_FRAME_STATISTICS *pStats) { + Logger::err("DxgiOutput::GetFrameStatistics: Not implemented"); + return E_NOTIMPL; + } + + + HRESULT DxgiOutput::GetGammaControl(DXGI_GAMMA_CONTROL *pArray) { + Logger::err("DxgiOutput::GetGammaControl: Not implemented"); + return E_NOTIMPL; + } + + + HRESULT DxgiOutput::GetGammaControlCapabilities(DXGI_GAMMA_CONTROL_CAPABILITIES *pGammaCaps) { + Logger::err("DxgiOutput::GetGammaControlCapabilities: Not implemented"); + return E_NOTIMPL; + } + + + void DxgiOutput::ReleaseOwnership() { + Logger::warn("DxgiOutput::ReleaseOwnership: Stub"); + } + + + HRESULT DxgiOutput::SetDisplaySurface(IDXGISurface *pScanoutSurface) { + Logger::err("DxgiOutput::SetDisplaySurface: Not implemented"); + return E_NOTIMPL; + } + + + HRESULT DxgiOutput::SetGammaControl(const DXGI_GAMMA_CONTROL *pArray) { + Logger::err("DxgiOutput::SetGammaControl: Not implemented"); + return E_NOTIMPL; + } + + + HRESULT DxgiOutput::TakeOwnership( + IUnknown *pDevice, + BOOL Exclusive) { + Logger::warn("DxgiOutput::TakeOwnership: Stub"); + return S_OK; + } + + + HRESULT DxgiOutput::WaitForVBlank() { + Logger::warn("DxgiOutput::WaitForVBlank: Stub"); + return S_OK; + } + +} diff --git a/src/dxgi/dxgi_output.h b/src/dxgi/dxgi_output.h new file mode 100644 index 00000000..0abf323a --- /dev/null +++ b/src/dxgi/dxgi_output.h @@ -0,0 +1,74 @@ +#pragma once + +#include "dxgi_object.h" + +namespace dxvk { + + class DxgiAdapter; + + class DxgiOutput : public DxgiObject { + + public: + + DxgiOutput( + DxgiAdapter* adapter, + UINT display); + + ~DxgiOutput(); + + HRESULT QueryInterface( + REFIID riid, + void **ppvObject) final; + + HRESULT GetParent( + REFIID riid, + void **ppParent) final; + + HRESULT FindClosestMatchingMode( + const DXGI_MODE_DESC *pModeToMatch, + DXGI_MODE_DESC *pClosestMatch, + IUnknown *pConcernedDevice) final; + + HRESULT GetDesc( + DXGI_OUTPUT_DESC *pDesc) final; + + HRESULT GetDisplayModeList( + DXGI_FORMAT EnumFormat, + UINT Flags, + UINT *pNumModes, + DXGI_MODE_DESC *pDesc) final; + + HRESULT GetDisplaySurfaceData( + IDXGISurface *pDestination) final; + + HRESULT GetFrameStatistics( + DXGI_FRAME_STATISTICS *pStats) final; + + HRESULT GetGammaControl( + DXGI_GAMMA_CONTROL *pArray) final; + + HRESULT GetGammaControlCapabilities( + DXGI_GAMMA_CONTROL_CAPABILITIES *pGammaCaps) final; + + void ReleaseOwnership() final; + + HRESULT SetDisplaySurface( + IDXGISurface *pScanoutSurface) final; + + HRESULT SetGammaControl( + const DXGI_GAMMA_CONTROL *pArray) final; + + HRESULT TakeOwnership( + IUnknown *pDevice, + BOOL Exclusive) final; + + HRESULT WaitForVBlank() final; + + private: + + DxgiAdapter* m_adapter; + UINT m_display; + + }; + +} diff --git a/src/dxgi/dxgi_private_data.cpp b/src/dxgi/dxgi_private_data.cpp new file mode 100644 index 00000000..b900a616 --- /dev/null +++ b/src/dxgi/dxgi_private_data.cpp @@ -0,0 +1,149 @@ +#include +#include +#include + +#include "dxgi_private_data.h" + +namespace dxvk { + + DxgiPrivateDataEntry::DxgiPrivateDataEntry() { } + DxgiPrivateDataEntry::DxgiPrivateDataEntry( + REFGUID guid, + UINT size, + const void* data) + : m_guid(guid), + m_size(size), + m_data(std::malloc(size)) { + std::memcpy(m_data, data, size); + } + + + DxgiPrivateDataEntry::DxgiPrivateDataEntry( + REFGUID guid, + const IUnknown* iface) + : m_guid (guid), + m_iface (const_cast(iface)) { + m_iface->AddRef(); + } + + + DxgiPrivateDataEntry::~DxgiPrivateDataEntry() { + this->destroy(); + } + + + DxgiPrivateDataEntry::DxgiPrivateDataEntry(DxgiPrivateDataEntry&& other) + : m_guid (other.m_guid), + m_size (other.m_size), + m_data (other.m_data), + m_iface (other.m_iface) { + other.m_guid = __uuidof(IUnknown); + other.m_size = 0; + other.m_data = nullptr; + other.m_iface = nullptr; + } + + + DxgiPrivateDataEntry& DxgiPrivateDataEntry::operator = (DxgiPrivateDataEntry&& other) { + this->destroy(); + this->m_guid = other.m_guid; + this->m_size = other.m_size; + this->m_data = other.m_data; + this->m_iface = other.m_iface; + + other.m_guid = __uuidof(IUnknown); + other.m_size = 0; + other.m_data = nullptr; + other.m_iface = nullptr; + return *this; + } + + + HRESULT DxgiPrivateDataEntry::get(UINT& size, void* data) const { + if (size != 0 && data == nullptr) + return DXGI_ERROR_INVALID_CALL; + + const UINT minSize = m_iface != nullptr + ? sizeof(IUnknown*) + : m_size; + + const HRESULT result = size < minSize + ? DXGI_ERROR_MORE_DATA + : S_OK; + + if (size >= minSize) { + if (m_iface != nullptr) { + m_iface->AddRef(); + std::memcpy(data, &m_iface, minSize); + } else { + std::memcpy(data, m_data, minSize); + } + } + + size = minSize; + return result; + } + + + void DxgiPrivateDataEntry::destroy() { + if (m_data != nullptr) + std::free(m_data); + if (m_iface != nullptr) + m_iface->Release(); + } + + + HRESULT DxgiPrivateData::setData( + REFGUID guid, + UINT size, + const void* data) { + this->insertEntry(DxgiPrivateDataEntry(guid, size, data)); + return S_OK; + } + + + HRESULT DxgiPrivateData::setInterface( + REFGUID guid, + const IUnknown* iface) { + this->insertEntry(DxgiPrivateDataEntry(guid, iface)); + return S_OK; + } + + + HRESULT DxgiPrivateData::getData( + REFGUID guid, + UINT* size, + void* data) { + if (size == nullptr) + return DXGI_ERROR_INVALID_CALL; + + auto entry = this->findEntry(guid); + + if (entry == nullptr) + return DXGI_ERROR_NOT_FOUND; + + return entry->get(*size, data); + } + + + DxgiPrivateDataEntry* DxgiPrivateData::findEntry(REFGUID guid) { + for (DxgiPrivateDataEntry& e : m_entries) { + if (e.hasGuid(guid)) + return &e; + } + + return nullptr; + } + + + void DxgiPrivateData::insertEntry(DxgiPrivateDataEntry&& entry) { + DxgiPrivateDataEntry srcEntry = std::move(entry); + DxgiPrivateDataEntry* dstEntry = this->findEntry(srcEntry.guid()); + + if (dstEntry != nullptr) + *dstEntry = std::move(srcEntry); + else + m_entries.push_back(std::move(srcEntry)); + } + +} diff --git a/src/dxgi/dxgi_private_data.h b/src/dxgi/dxgi_private_data.h new file mode 100644 index 00000000..26bab34d --- /dev/null +++ b/src/dxgi/dxgi_private_data.h @@ -0,0 +1,105 @@ +#pragma once + +#include + +#include "dxgi_include.h" + +namespace dxvk { + + /** + * \brief Data entry for private storage + * Stores a single private storage item. + */ + class DxgiPrivateDataEntry { + + public: + + DxgiPrivateDataEntry(); + DxgiPrivateDataEntry( + REFGUID guid, + UINT size, + const void* data); + DxgiPrivateDataEntry( + REFGUID guid, + const IUnknown* iface); + ~DxgiPrivateDataEntry(); + + DxgiPrivateDataEntry (DxgiPrivateDataEntry&& other); + DxgiPrivateDataEntry& operator = (DxgiPrivateDataEntry&& other); + + /** + * \brief The entry's GUID + * \returns The GUID + */ + REFGUID guid() const { + return m_guid; + } + + /** + * \brief Checks whether the GUID matches another one + * + * GUIDs are used to identify private data entries. + * \param [in] guid The GUID to compare to + * \returns \c true if this entry holds the same GUID + */ + bool hasGuid(REFGUID guid) const { + return m_guid == guid; + } + + /** + * \brief Retrieves stored data + * + * \param [in,out] size Destination buffer size + * \param [in] data Appliaction-provided buffer + * \returns \c S_OK on success, or \c DXGI_ERROR_MORE_DATA + * if the destination buffer is too small + */ + HRESULT get(UINT& size, void* data) const; + + private: + + GUID m_guid = __uuidof(IUnknown); + UINT m_size = 0; + void* m_data = nullptr; + IUnknown* m_iface = nullptr; + + void destroy(); + + }; + + + /** + * \brief Private storage for DXGI objects + * + * Provides storage for application-defined + * byte arrays or COM interfaces that can be + * retrieved using GUIDs. + */ + class DxgiPrivateData { + + public: + + HRESULT setData( + REFGUID guid, + UINT size, + const void* data); + + HRESULT setInterface( + REFGUID guid, + const IUnknown* iface); + + HRESULT getData( + REFGUID guid, + UINT* size, + void* data); + + private: + + std::vector m_entries; + + DxgiPrivateDataEntry* findEntry(REFGUID guid); + void insertEntry(DxgiPrivateDataEntry&& entry); + + }; + +} diff --git a/src/dxgi/dxgi_swapchain.cpp b/src/dxgi/dxgi_swapchain.cpp new file mode 100644 index 00000000..e69de29b diff --git a/src/dxgi/dxgi_swapchain.h b/src/dxgi/dxgi_swapchain.h new file mode 100644 index 00000000..e69de29b diff --git a/src/dxgi/meson.build b/src/dxgi/meson.build new file mode 100644 index 00000000..57c101ec --- /dev/null +++ b/src/dxgi/meson.build @@ -0,0 +1,17 @@ +dxgi_src = [ + 'dxgi_adapter.cpp', + 'dxgi_factory.cpp', + 'dxgi_main.cpp', + 'dxgi_output.cpp', + 'dxgi_private_data.cpp', + 'dxgi_swapchain.cpp', +] + +dxgi_dll = shared_library('dxgi', dxgi_src, + link_with : [ util_lib ], + dependencies : [ dxvk_dep ], + include_directories : dxvk_include_path) + +dxgi_dep = declare_dependency( + link_with : [ dxgi_dll ], + include_directories : [ dxvk_include_path, include_directories('.') ]) diff --git a/src/meson.build b/src/meson.build index 185ea80b..5938df46 100644 --- a/src/meson.build +++ b/src/meson.build @@ -1,2 +1,4 @@ subdir('util') -subdir('dxvk') \ No newline at end of file +subdir('dxvk') +subdir('dxgi') +subdir('d3d11') \ No newline at end of file