mirror of
https://github.com/doitsujin/dxvk.git
synced 2025-02-20 10:54:16 +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('dxvk')
|
||||
subdir('dxvk')
|
||||
subdir('dxgi')
|
||||
subdir('d3d11')
|
Loading…
x
Reference in New Issue
Block a user