Skip to content

Commit a4e72df

Browse files
committed
feat(d3d11, dxmt): gamma support
1 parent a60483b commit a4e72df

File tree

11 files changed

+260
-22
lines changed

11 files changed

+260
-22
lines changed

src/d3d11/d3d11_swapchain.cpp

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
#include "wsi_window.hpp"
2121
#include "dxmt_info.hpp"
2222
#include "dxmt_presenter.hpp"
23+
#include "dxgi_monitor.hpp"
2324
#include <cfloat>
2425
#include <format>
2526

@@ -92,9 +93,16 @@ class MTLD3D11SwapChain final : public MTLDXGISubObject<IDXGISwapChain4, MTLD3D1
9293
scale_factor = std::max(Config::getInstance().getOption<float>("d3d11.metalSpatialUpscaleFactor", 2), 1.0f);
9394
}
9495

96+
if (FAILED(factory_->QueryInterface(IID_PPV_ARGS(&monitor_info_)))) {
97+
ERR("MTLD3D11SwapChain: failed to get IMTLDXGIMonitor");
98+
} else {
99+
monitor_info_->GetMonitorData(&monitor_data_);
100+
}
101+
95102
presenter = Rc(new Presenter(pDevice->GetMTLDevice(), layer_weak_,
96103
pDevice->GetDXMTDevice().queue().cmd_library,
97-
scale_factor, desc_.SampleDesc.Count));
104+
scale_factor, desc_.SampleDesc.Count,
105+
monitor_data_ ? &monitor_data_->gammaCurve : nullptr));
98106

99107
frame_latency = kSwapchainLatency;
100108
present_semaphore_ = CreateSemaphore(nullptr, frame_latency,
@@ -596,6 +604,8 @@ class MTLD3D11SwapChain final : public MTLDXGISubObject<IDXGISwapChain4, MTLD3D1
596604

597605
std::unique_lock<d3d11_device_mutex> lock(device_->mutex);
598606

607+
presenter->updateGammaLUT();
608+
599609
device_context_->PrepareFlush();
600610
auto &cmd_queue = device_->GetDXMTDevice().queue();
601611
auto chunk = cmd_queue.CurrentChunk();
@@ -870,6 +880,8 @@ class MTLD3D11SwapChain final : public MTLDXGISubObject<IDXGISwapChain4, MTLD3D1
870880
HWND hWnd;
871881
HMONITOR monitor_;
872882
Com<IDXGIOutput1> target_;
883+
Com<IMTLDXGIMonitor> monitor_info_;
884+
MTLDXGI_MONITOR_DATA *monitor_data_ = nullptr;
873885
wsi::DXMTWindowState window_state_;
874886
uint32_t frame_latency;
875887
DXGI_COLOR_SPACE_TYPE colorspace_ = DXGI_COLOR_SPACE_RGB_FULL_G22_NONE_P709;

src/dxgi/dxgi_adapter.cpp

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111

1212
namespace dxmt {
1313

14-
Com<IDXGIOutput> CreateOutput(IMTLDXGIAdapter *pAadapter, HMONITOR monitor, DxgiOptions &options);
14+
Com<IDXGIOutput> CreateOutput(IMTLDXGIAdapter *pAadapter, IMTLDXGIFactory *pFactory, HMONITOR monitor, DxgiOptions &options);
1515

1616
LUID GetAdapterLuid(WMT::Device device) {
1717
// NOTE: use big-endian registryID, be consistent with MVK
@@ -20,7 +20,7 @@ LUID GetAdapterLuid(WMT::Device device) {
2020

2121
class MTLDXGIAdatper : public MTLDXGIObject<IMTLDXGIAdapter> {
2222
public:
23-
MTLDXGIAdatper(WMT::Device device, IDXGIFactory *factory, Config &config)
23+
MTLDXGIAdatper(WMT::Device device, IMTLDXGIFactory *factory, Config &config)
2424
: device_(device), factory_(factory), options_(config) {
2525
D3DKMT_OPENADAPTERFROMLUID open = {};
2626
open.AdapterLuid = GetAdapterLuid(device_);
@@ -190,9 +190,10 @@ class MTLDXGIAdatper : public MTLDXGIObject<IMTLDXGIAdapter> {
190190
if (monitor == nullptr)
191191
return DXGI_ERROR_NOT_FOUND;
192192

193-
*ppOutput = CreateOutput(this, monitor, options_);
193+
*ppOutput = CreateOutput(this, factory_.ptr(), monitor, options_);
194194
return S_OK;
195195
}
196+
196197
HRESULT STDMETHODCALLTYPE
197198
CheckInterfaceSupport(const GUID &guid, LARGE_INTEGER *umd_version) final {
198199
HRESULT hr = DXGI_ERROR_UNSUPPORTED;
@@ -274,13 +275,13 @@ class MTLDXGIAdatper : public MTLDXGIObject<IMTLDXGIAdapter> {
274275
private:
275276
WMT::Reference<WMT::Device> device_;
276277
D3DKMT_HANDLE local_kmt_ = 0;
277-
Com<IDXGIFactory> factory_;
278+
Com<IMTLDXGIFactory> factory_;
278279
DxgiOptions options_;
279280
uint64_t mem_reserved_[2] = {0, 0};
280281
};
281282

282283
Com<IMTLDXGIAdapter> CreateAdapter(WMT::Device Device,
283-
IDXGIFactory2 *pFactory, Config &config) {
284+
IMTLDXGIFactory *pFactory, Config &config) {
284285
return Com<IMTLDXGIAdapter>::transfer(
285286
new MTLDXGIAdatper(Device, pFactory, config));
286287
}

src/dxgi/dxgi_factory.cpp

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
#include "com/com_pointer.hpp"
22
#include "config/config.hpp"
33
#include "dxgi_interfaces.h"
4+
#include "dxgi_monitor.hpp"
45
#include "dxgi_object.hpp"
56
#include "com/com_guid.hpp"
67
#include "log/log.hpp"
@@ -11,12 +12,12 @@
1112
namespace dxmt {
1213

1314
Com<IMTLDXGIAdapter> CreateAdapter(WMT::Device Device,
14-
IDXGIFactory2 *pFactory, Config &config);
15+
IMTLDXGIFactory *pFactory, Config &config);
1516

16-
class MTLDXGIFactory : public MTLDXGIObject<IDXGIFactory6> {
17+
class MTLDXGIFactory : public MTLDXGIObject<IMTLDXGIFactory> {
1718

1819
public:
19-
MTLDXGIFactory(UINT Flags) : flags_(Flags) {};
20+
MTLDXGIFactory(UINT Flags) : flags_(Flags), monitor_info_(new MTLDXGIMonitor(this)) {};
2021

2122
HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid,
2223
void **ppvObject) final {
@@ -34,6 +35,11 @@ class MTLDXGIFactory : public MTLDXGIObject<IDXGIFactory6> {
3435
return S_OK;
3536
}
3637

38+
if (riid == __uuidof(IMTLDXGIMonitor)) {
39+
*ppvObject = ref(monitor_info_);
40+
return S_OK;
41+
}
42+
3743
if (logQueryInterfaceError(__uuidof(IDXGIFactory2), riid)) {
3844
WARN("DXGIFactory: Unknown interface query ", str::format(riid));
3945
}
@@ -301,10 +307,17 @@ class MTLDXGIFactory : public MTLDXGIObject<IDXGIFactory6> {
301307
return adapter->QueryInterface(riid, ppvAdapter);
302308
};
303309

310+
MTLDXGIMonitor STDMETHODCALLTYPE
311+
*GetMonitor() override {
312+
return monitor_info_;
313+
}
314+
304315
private:
305316
UINT flags_;
306317

307318
HWND associated_window_ = nullptr;
319+
320+
MTLDXGIMonitor *monitor_info_ = nullptr;
308321
};
309322

310323
extern "C" HRESULT __stdcall CreateDXGIFactory2(UINT Flags, REFIID riid,

src/dxgi/dxgi_interfaces.h

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
#include "util_d3dkmt.h"
55
#include "Metal.hpp"
66
#include "com/com_guid.hpp"
7+
#include "dxgi_object.hpp"
78

89
DEFINE_COM_INTERFACE("acdf3ef1-b33a-4cb6-97bd-1c1974827e6d", IMTLDXGIAdapter)
910
: public IDXGIAdapter4 {
@@ -21,6 +22,22 @@ DEFINE_COM_INTERFACE("6bfa1657-9cb1-471a-a4fb-7cacf8a81207", IMTLDXGIDevice)
2122
IDXGISwapChain1 **ppSwapChain) = 0;
2223
};
2324

25+
struct MTLDXGI_MONITOR_DATA;
26+
namespace dxmt {
27+
class MTLDXGIMonitor;
28+
};
29+
30+
DEFINE_COM_INTERFACE("8f804acf-f020-4914-98d4-a951da684b7f", IMTLDXGIMonitor)
31+
: public IUnknown {
32+
virtual HRESULT STDMETHODCALLTYPE SetMonitorData(const MTLDXGI_MONITOR_DATA *pData) = 0;
33+
virtual HRESULT STDMETHODCALLTYPE GetMonitorData(MTLDXGI_MONITOR_DATA **ppData) = 0;
34+
};
35+
36+
DEFINE_COM_INTERFACE("413dae46-5707-46e1-b66d-6e58b9f15113", IMTLDXGIFactory)
37+
: public IDXGIFactory6 {
38+
virtual dxmt::MTLDXGIMonitor * STDMETHODCALLTYPE GetMonitor() = 0;
39+
};
40+
2441
static constexpr IID DXMT_NVEXT_GUID = dxmt::guid::make_guid("ba0af616-4a43-4259-815c-db3b89829905");
2542

2643
namespace dxmt {

src/dxgi/dxgi_monitor.cpp

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
#include "dxgi_interfaces.h"
2+
#include "dxgi_monitor.hpp"
3+
4+
namespace dxmt {
5+
6+
MTLDXGIMonitor::MTLDXGIMonitor(IUnknown *pParent) : parent_(pParent) {
7+
}
8+
9+
ULONG
10+
STDMETHODCALLTYPE
11+
MTLDXGIMonitor::AddRef() {
12+
return parent_->AddRef();
13+
}
14+
15+
ULONG
16+
STDMETHODCALLTYPE
17+
MTLDXGIMonitor::Release() {
18+
return parent_->Release();
19+
}
20+
21+
HRESULT
22+
STDMETHODCALLTYPE
23+
MTLDXGIMonitor::QueryInterface(REFIID riid, void **ppvObject) {
24+
return parent_->QueryInterface(riid, ppvObject);
25+
}
26+
27+
HRESULT
28+
STDMETHODCALLTYPE
29+
MTLDXGIMonitor::SetMonitorData(const MTLDXGI_MONITOR_DATA *pData) {
30+
if (!pData)
31+
return DXGI_ERROR_INVALID_CALL;
32+
33+
monitorData = *pData;
34+
35+
return S_OK;
36+
}
37+
38+
HRESULT
39+
STDMETHODCALLTYPE
40+
MTLDXGIMonitor::GetMonitorData(MTLDXGI_MONITOR_DATA **ppData) {
41+
if (!ppData)
42+
return DXGI_ERROR_INVALID_CALL;
43+
44+
*ppData = &monitorData;
45+
46+
return S_OK;
47+
}
48+
49+
} // namespace dxmt

src/dxgi/dxgi_monitor.hpp

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
#pragma once
2+
3+
#include "dxgi.h"
4+
#include "dxgi_interfaces.h"
5+
#include "dxmt_presenter.hpp"
6+
7+
struct MTLDXGI_MONITOR_DATA {
8+
dxmt::DXMTGammaCurve gammaCurve;
9+
};
10+
11+
namespace dxmt {
12+
13+
class MTLDXGIMonitor : public IMTLDXGIMonitor {
14+
public:
15+
MTLDXGIMonitor(IUnknown* pParent);
16+
ULONG STDMETHODCALLTYPE AddRef();
17+
ULONG STDMETHODCALLTYPE Release();
18+
HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void **ppvObject);
19+
20+
HRESULT STDMETHODCALLTYPE SetMonitorData(const MTLDXGI_MONITOR_DATA *pData);
21+
HRESULT STDMETHODCALLTYPE GetMonitorData(MTLDXGI_MONITOR_DATA **ppData);
22+
23+
private:
24+
IUnknown *parent_;
25+
MTLDXGI_MONITOR_DATA monitorData{};
26+
};
27+
28+
} // namespace dxmt

src/dxgi/dxgi_output.cpp

Lines changed: 59 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
#include "com/com_guid.hpp"
55
#include "com/com_pointer.hpp"
66
#include "dxgi_interfaces.h"
7+
#include "dxgi_monitor.hpp"
78
#include "dxgi_object.hpp"
89
#include "dxgi_options.hpp"
910
#include "dxmt_format.hpp"
@@ -13,6 +14,10 @@
1314

1415
namespace dxmt {
1516

17+
inline float GetGammaControlPointPosition(uint32_t cp_index) {
18+
return float(cp_index) / float(DXMT_DXGI_GAMMA_CP_COUNT - 1);
19+
}
20+
1621
/*
1722
* \see
1823
* https://github.com/microsoft/DirectXTex/blob/main/DirectXTex/DirectXTexUtil.cpp
@@ -136,12 +141,21 @@ void FilterModesByDesc(std::vector<DXGI_MODE_DESC1> &Modes,
136141

137142
class MTLDXGIOutput : public MTLDXGIObject<IDXGIOutput6> {
138143
public:
139-
MTLDXGIOutput(IMTLDXGIAdapter *adapter, HMONITOR monitor, DxgiOptions &options)
140-
: adapter_(adapter), monitor_(monitor), options_(options) {
144+
MTLDXGIOutput(IMTLDXGIAdapter *adapter, IMTLDXGIFactory *factory, HMONITOR monitor, DxgiOptions &options)
145+
: adapter_(adapter), factory_(factory), monitor_(monitor), options_(options) {
141146
WMTGetDisplayDescription(monitor_ == wsi::getDefaultMonitor()
142147
? WMTGetPrimaryDisplayId()
143148
: WMTGetSecondaryDisplayId(),
144149
&native_desc_);
150+
monitor_info_ = factory_->GetMonitor();
151+
MTLDXGI_MONITOR_DATA monitorData;
152+
for (uint32_t i = 0; i < DXMT_DXGI_GAMMA_CP_COUNT; i++) {
153+
float pos = GetGammaControlPointPosition(i);
154+
monitorData.gammaCurve.Red[i] = monitorData.gammaCurve.Green[i] = monitorData.gammaCurve.Blue[i] = pos;
155+
}
156+
monitorData.gammaCurve.gammaIsIdentity = true;
157+
monitorData.gammaCurve.updated = false;
158+
monitor_info_->SetMonitorData(&monitorData);
145159
}
146160

147161
~MTLDXGIOutput() {}
@@ -287,22 +301,56 @@ class MTLDXGIOutput : public MTLDXGIObject<IDXGIOutput6> {
287301
gamma_caps->ScaleAndOffsetSupported = false;
288302
gamma_caps->MaxConvertedValue = 1.0f;
289303
gamma_caps->MinConvertedValue = 0.0f;
290-
gamma_caps->NumGammaControlPoints = 1;
304+
gamma_caps->NumGammaControlPoints = DXMT_DXGI_GAMMA_CP_COUNT;
305+
for (uint32_t i = 0; i < gamma_caps->NumGammaControlPoints; i++)
306+
gamma_caps->ControlPointPositions[i] = GetGammaControlPointPosition(i);
291307
return S_OK;
292308
}
293309

294310
HRESULT
295311
STDMETHODCALLTYPE
296312
SetGammaControl(const DXGI_GAMMA_CONTROL *gamma_control) final {
297-
ERR("Not implemented");
298-
return E_NOTIMPL;
313+
MTLDXGI_MONITOR_DATA *monitorData = nullptr;
314+
if (gamma_control == nullptr)
315+
return E_NOTIMPL;
316+
317+
HRESULT hr = monitor_info_->GetMonitorData(&monitorData);
318+
if (FAILED(hr))
319+
return hr;
320+
321+
for (uint32_t i = 0; i < DXMT_DXGI_GAMMA_CP_COUNT; i++) {
322+
monitorData->gammaCurve.Red[i] = gamma_control->GammaCurve[i].Red;
323+
monitorData->gammaCurve.Green[i] = gamma_control->GammaCurve[i].Green;
324+
monitorData->gammaCurve.Blue[i] = gamma_control->GammaCurve[i].Blue;
325+
float identity = GetGammaControlPointPosition(i);
326+
monitorData->gammaCurve.gammaIsIdentity &= gamma_control->GammaCurve[i].Red == identity
327+
&& gamma_control->GammaCurve[i].Green == identity
328+
&& gamma_control->GammaCurve[i].Blue == identity;
329+
}
330+
monitorData->gammaCurve.updated = true;
331+
332+
return S_OK;
299333
}
300334

301335
HRESULT
302336
STDMETHODCALLTYPE
303337
GetGammaControl(DXGI_GAMMA_CONTROL *gamma_control) final {
304-
ERR("Not implemented");
305-
return E_NOTIMPL;
338+
MTLDXGI_MONITOR_DATA *monitorData = nullptr;
339+
if (gamma_control == nullptr)
340+
return E_NOTIMPL;
341+
342+
HRESULT hr = monitor_info_->GetMonitorData(&monitorData);
343+
if (FAILED(hr))
344+
return hr;
345+
346+
gamma_control->Scale = { 1.0f, 1.0f, 1.0f };
347+
gamma_control->Offset = { 0.0f, 0.0f, 0.0f };
348+
for (uint32_t i = 0; i < DXMT_DXGI_GAMMA_CP_COUNT; i++) {
349+
gamma_control->GammaCurve[i].Red = monitorData->gammaCurve.Red[i];
350+
gamma_control->GammaCurve[i].Green = monitorData->gammaCurve.Green[i];
351+
gamma_control->GammaCurve[i].Blue = monitorData->gammaCurve.Blue[i];
352+
}
353+
return S_OK;
306354
}
307355

308356
HRESULT
@@ -603,13 +651,15 @@ class MTLDXGIOutput : public MTLDXGIObject<IDXGIOutput6> {
603651

604652
private:
605653
Com<IMTLDXGIAdapter> adapter_ = nullptr;
654+
Com<IMTLDXGIFactory> factory_ = nullptr;
655+
MTLDXGIMonitor *monitor_info_ = nullptr;
606656
HMONITOR monitor_ = nullptr;
607657
WMTDisplayDescription native_desc_;
608658
DxgiOptions &options_;
609659
};
610660

611-
Com<IDXGIOutput> CreateOutput(IMTLDXGIAdapter *pAadapter, HMONITOR monitor, DxgiOptions &options) {
612-
return Com<IDXGIOutput>::transfer(new MTLDXGIOutput(pAadapter, monitor, options));
661+
Com<IDXGIOutput> CreateOutput(IMTLDXGIAdapter *pAadapter, IMTLDXGIFactory *pFactory, HMONITOR monitor, DxgiOptions &options) {
662+
return Com<IDXGIOutput>::transfer(new MTLDXGIOutput(pAadapter, pFactory, monitor, options));
613663
};
614664

615665
} // namespace dxmt

src/dxgi/meson.build

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ dxgi_res = wrc_generator.process('version.rc')
33
dxgi_src = [
44
'dxgi_adapter.cpp',
55
'dxgi_factory.cpp',
6+
'dxgi_monitor.cpp',
67
'dxgi_output.cpp',
78
'dxgi_options.cpp',
89
'dxgi.cpp',

0 commit comments

Comments
 (0)