mirror of
https://github.com/EduApps-CDG/OpenDX
synced 2024-12-30 09:45:37 +01:00
[dxgi] Implemented some DXGI classes
This commit is contained in:
parent
9b8fda512a
commit
bed6d23e7f
105
src/dxgi/dxgi_adapter.cpp
Normal file
105
src/dxgi/dxgi_adapter.cpp
Normal file
@ -0,0 +1,105 @@
|
|||||||
|
#include <cstdlib>
|
||||||
|
#include <cstring>
|
||||||
|
|
||||||
|
#include "dxgi_adapter.h"
|
||||||
|
#include "dxgi_factory.h"
|
||||||
|
#include "dxgi_output.h"
|
||||||
|
|
||||||
|
namespace dxvk {
|
||||||
|
|
||||||
|
DxgiAdapter::DxgiAdapter(
|
||||||
|
DxgiFactory* factory,
|
||||||
|
const Rc<DxvkAdapter>& 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<uint32_t>(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;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
50
src/dxgi/dxgi_adapter.h
Normal file
50
src/dxgi/dxgi_adapter.h
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include <dxvk_adapter.h>
|
||||||
|
|
||||||
|
#include "dxgi_object.h"
|
||||||
|
|
||||||
|
namespace dxvk {
|
||||||
|
|
||||||
|
class DxgiFactory;
|
||||||
|
class DxgiOutput;
|
||||||
|
|
||||||
|
class DxgiAdapter : public DxgiObject<IDXGIAdapter> {
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
DxgiAdapter(
|
||||||
|
DxgiFactory* factory,
|
||||||
|
const Rc<DxvkAdapter>& 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<DxvkAdapter> m_adapter;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
88
src/dxgi/dxgi_factory.cpp
Normal file
88
src/dxgi/dxgi_factory.cpp
Normal file
@ -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;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
55
src/dxgi/dxgi_factory.h
Normal file
55
src/dxgi/dxgi_factory.h
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include <dxvk_instance.h>
|
||||||
|
|
||||||
|
#include "dxgi_adapter.h"
|
||||||
|
|
||||||
|
namespace dxvk {
|
||||||
|
|
||||||
|
class DxgiFactory : public DxgiObject<IDXGIFactory> {
|
||||||
|
|
||||||
|
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<DxvkInstance> m_instance;
|
||||||
|
std::vector<Com<DxgiAdapter>> m_adapters;
|
||||||
|
|
||||||
|
HWND m_associatedWindow = nullptr;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
18
src/dxgi/dxgi_include.h
Normal file
18
src/dxgi/dxgi_include.h
Normal file
@ -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 <dxgi1_2.h>
|
||||||
|
|
||||||
|
#include <SDL2/SDL.h>
|
48
src/dxgi/dxgi_main.cpp
Normal file
48
src/dxgi/dxgi_main.cpp
Normal file
@ -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);
|
||||||
|
}
|
||||||
|
}
|
41
src/dxgi/dxgi_object.h
Normal file
41
src/dxgi/dxgi_object.h
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "dxgi_private_data.h"
|
||||||
|
|
||||||
|
namespace dxvk {
|
||||||
|
|
||||||
|
template<typename Base>
|
||||||
|
class DxgiObject : public ComObject<Base> {
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
244
src/dxgi/dxgi_output.cpp
Normal file
244
src/dxgi/dxgi_output.cpp
Normal file
@ -0,0 +1,244 @@
|
|||||||
|
#include <cstdlib>
|
||||||
|
#include <cstring>
|
||||||
|
|
||||||
|
#include <sstream>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#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<DXGI_MODE_DESC> 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
74
src/dxgi/dxgi_output.h
Normal file
74
src/dxgi/dxgi_output.h
Normal file
@ -0,0 +1,74 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "dxgi_object.h"
|
||||||
|
|
||||||
|
namespace dxvk {
|
||||||
|
|
||||||
|
class DxgiAdapter;
|
||||||
|
|
||||||
|
class DxgiOutput : public DxgiObject<IDXGIOutput> {
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
149
src/dxgi/dxgi_private_data.cpp
Normal file
149
src/dxgi/dxgi_private_data.cpp
Normal file
@ -0,0 +1,149 @@
|
|||||||
|
#include <cmath>
|
||||||
|
#include <cstring>
|
||||||
|
#include <cstdlib>
|
||||||
|
|
||||||
|
#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<IUnknown*>(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));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
105
src/dxgi/dxgi_private_data.h
Normal file
105
src/dxgi/dxgi_private_data.h
Normal file
@ -0,0 +1,105 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#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<DxgiPrivateDataEntry> m_entries;
|
||||||
|
|
||||||
|
DxgiPrivateDataEntry* findEntry(REFGUID guid);
|
||||||
|
void insertEntry(DxgiPrivateDataEntry&& entry);
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
0
src/dxgi/dxgi_swapchain.cpp
Normal file
0
src/dxgi/dxgi_swapchain.cpp
Normal file
0
src/dxgi/dxgi_swapchain.h
Normal file
0
src/dxgi/dxgi_swapchain.h
Normal file
17
src/dxgi/meson.build
Normal file
17
src/dxgi/meson.build
Normal file
@ -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('.') ])
|
@ -1,2 +1,4 @@
|
|||||||
subdir('util')
|
subdir('util')
|
||||||
subdir('dxvk')
|
subdir('dxvk')
|
||||||
|
subdir('dxgi')
|
||||||
|
subdir('d3d11')
|
Loading…
x
Reference in New Issue
Block a user