Skip to content

Commit e62bb5a

Browse files
committed
cross-adapter support wip
1 parent 9c0454b commit e62bb5a

File tree

6 files changed

+255
-53
lines changed

6 files changed

+255
-53
lines changed

ShaderGlass/CaptureManager.cpp

Lines changed: 75 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,29 @@ const std::vector<CaptureDevice>& CaptureManager::CaptureDevices()
7979
return m_captureDevices;
8080
}
8181

82+
const std::vector<GraphicsAdapter>& CaptureManager::GraphicsAdapters()
83+
{
84+
if(!m_graphicsAdapters.size())
85+
{
86+
const auto& adapters = EnumerateAdapters();
87+
int no = 1;
88+
for(auto adapter : adapters)
89+
{
90+
DXGI_ADAPTER_DESC desc;
91+
if(SUCCEEDED(adapter->GetDesc(&desc)))
92+
{
93+
if((desc.VendorId == 0x1414) && (desc.DeviceId == 0x8c))
94+
continue; // Microsoft Basic Render Driver
95+
96+
wchar_t id[24];
97+
_snwprintf_s(id, 24, L"%lx:%lx", desc.AdapterLuid.HighPart, desc.AdapterLuid.LowPart);
98+
m_graphicsAdapters.emplace_back(no++, std::wstring(desc.Description), std::wstring(id), adapter);
99+
}
100+
}
101+
}
102+
return m_graphicsAdapters;
103+
}
104+
82105
bool CaptureManager::UpdateInput()
83106
{
84107
if(IsActive())
@@ -97,30 +120,39 @@ DWORD WINAPI ThreadFuncProxy(LPVOID lpParam)
97120

98121
bool CaptureManager::StartSession()
99122
{
100-
if(!m_d3dDevice)
101-
{
102-
m_d3dDevice = CreateD3DDevice();
103-
m_d3dDevice->GetImmediateContext(m_context.put());
104-
}
105-
106-
auto dxgiDevice = m_d3dDevice.as<IDXGIDevice>();
107-
auto device = HasCaptureAPI() ? CreateDirect3DDevice(dxgiDevice.get()) : nullptr;
123+
bool hybrid = false;
108124

109-
// get GPU name
125+
if(!m_captureDevice)
110126
{
111-
winrt::com_ptr<IDXGIAdapter> adapter;
112-
if(SUCCEEDED(dxgiDevice->GetAdapter(adapter.put())))
127+
m_captureDevice = CreateD3DDevice(m_captureAdapter);
128+
if(m_captureAdapter != m_renderAdapter)
113129
{
114-
DXGI_ADAPTER_DESC desc;
115-
if(SUCCEEDED(adapter->GetDesc(&desc)))
130+
m_renderDevice = CreateD3DDevice(m_renderAdapter);
131+
hybrid = true;
132+
}
133+
else
134+
{
135+
m_renderDevice = m_captureDevice;
136+
}
137+
m_renderDevice->GetImmediateContext(m_renderContext.put());
138+
139+
// get actual GPU name
140+
{
141+
auto dxgiDevice = m_renderDevice.as<IDXGIDevice>();
142+
winrt::com_ptr<IDXGIAdapter> adapter;
143+
if(SUCCEEDED(dxgiDevice->GetAdapter(adapter.put())))
116144
{
117-
m_deviceName = std::wstring(desc.Description);
145+
DXGI_ADAPTER_DESC desc;
146+
if(SUCCEEDED(adapter->GetDesc(&desc)))
147+
{
148+
m_deviceName = std::wstring(desc.Description);
149+
}
118150
}
119151
}
120152
}
121153

122154
#ifdef _DEBUG
123-
m_d3dDevice->QueryInterface(__uuidof(ID3D11Debug), reinterpret_cast<void**>(m_debug.put()));
155+
m_renderDevice->QueryInterface(__uuidof(ID3D11Debug), reinterpret_cast<void**>(m_debug.put()));
124156
#endif
125157

126158
winrt::Windows::Graphics::Capture::GraphicsCaptureItem captureItem {nullptr};
@@ -148,8 +180,8 @@ bool CaptureManager::StartSession()
148180
m_options.flipMode,
149181
m_options.allowTearing,
150182
m_options.useHDR,
151-
m_d3dDevice,
152-
m_context);
183+
m_renderDevice,
184+
m_renderContext);
153185
UpdatePixelSize();
154186
UpdateOutputSize();
155187
UpdateOutputFlip();
@@ -164,7 +196,7 @@ bool CaptureManager::StartSession()
164196
{
165197
winrt::com_ptr<ID3D11Texture2D> inputTexture;
166198
winrt::com_ptr<ID3D11ShaderResourceView> inputTextureView;
167-
auto hr = DirectX::CreateWICTextureFromFileEx(m_d3dDevice.get(),
199+
auto hr = DirectX::CreateWICTextureFromFileEx(m_renderDevice.get(),
168200
m_options.imageFile.c_str(),
169201
0,
170202
D3D11_USAGE_DEFAULT,
@@ -182,7 +214,7 @@ bool CaptureManager::StartSession()
182214
m_options.imageWidth = desc.Width;
183215
m_options.imageHeight = desc.Height;
184216

185-
m_session = make_unique<CaptureSession>(device, inputTexture, *m_shaderGlass, m_frameEvent);
217+
m_session = make_unique<CaptureSession>(inputTexture, *m_shaderGlass, m_frameEvent);
186218
UpdatePixelSize();
187219
}
188220
else if(m_options.deviceFormatNo)
@@ -192,7 +224,7 @@ bool CaptureManager::StartSession()
192224
if(!FindDeviceFormat(m_options.deviceFormatNo, di, fi))
193225
return false;
194226

195-
m_deviceCapture.Start(m_d3dDevice, di->no, fi->no);
227+
m_deviceCapture.Start(m_renderDevice, di->no, fi->no);
196228

197229
// retrieve input image size
198230
auto inputTexture = m_deviceCapture.m_outputTexture;
@@ -201,18 +233,19 @@ bool CaptureManager::StartSession()
201233
m_options.imageWidth = desc.Width;
202234
m_options.imageHeight = desc.Height;
203235

204-
m_session = make_unique<CaptureSession>(device, inputTexture, *m_shaderGlass, m_frameEvent);
236+
m_session = make_unique<CaptureSession>(inputTexture, *m_shaderGlass, m_frameEvent);
205237
UpdatePixelSize();
206238
}
207239
else
208240
{
209241
winrt::Windows::Graphics::DirectX::DirectXPixelFormat pixelFormat = m_options.useHDR ? winrt::Windows::Graphics::DirectX::DirectXPixelFormat::R16G16B16A16Float
210242
: winrt::Windows::Graphics::DirectX::DirectXPixelFormat::B8G8R8A8UIntNormalized;
211243

212-
m_session = make_unique<CaptureSession>(device, captureItem, pixelFormat, *m_shaderGlass, m_options.maxCaptureRate, m_frameEvent);
244+
m_session =
245+
make_unique<CaptureSession>(m_captureDevice, hybrid ? m_renderDevice : nullptr, captureItem, pixelFormat, *m_shaderGlass, m_options.maxCaptureRate, m_frameEvent);
213246
}
214247

215-
m_active = true;
248+
m_active = true;
216249
auto thread = CreateThread(NULL, 0, ThreadFuncProxy, this, 0, NULL);
217250
SetThreadPriority(thread, THREAD_PRIORITY_TIME_CRITICAL);
218251

@@ -239,7 +272,7 @@ void CaptureManager::UpdateCursor()
239272
{
240273
if(m_options.captureCursor && m_options.transparent)
241274
{
242-
m_cursorEmulator.Init(m_d3dDevice, m_instance, m_options.outputWindow);
275+
m_cursorEmulator.Init(m_renderDevice, m_instance, m_options.outputWindow);
243276
m_cursorEmulator.Start();
244277
if(m_session)
245278
m_session->UpdateCursor(false);
@@ -451,7 +484,7 @@ void CaptureManager::SaveOutput(LPWSTR fileName)
451484
{
452485
if(m_outputTexture)
453486
{
454-
DirectX::SaveWICTextureToFile(m_context.get(), m_outputTexture.get(), GUID_ContainerFormatPng, fileName, nullptr, nullptr, true);
487+
DirectX::SaveWICTextureToFile(m_renderContext.get(), m_outputTexture.get(), GUID_ContainerFormatPng, fileName, nullptr, nullptr, true);
455488
}
456489
}
457490

@@ -539,3 +572,20 @@ bool CaptureManager::FindDeviceFormat(int deviceFormatNo, std::vector<CaptureDev
539572

540573
return false;
541574
}
575+
576+
void CaptureManager::SetCaptureAdapters(const std::wstring& captureId, const std::wstring& renderId)
577+
{
578+
m_captureAdapter = nullptr;
579+
m_renderAdapter = nullptr;
580+
if(captureId.size() || renderId.size())
581+
{
582+
const auto& graphicsAdapters = GraphicsAdapters();
583+
for(const auto& ga : graphicsAdapters)
584+
{
585+
if(ga.id == captureId)
586+
m_captureAdapter = ga.adapter;
587+
if(ga.id == renderId)
588+
m_renderAdapter = ga.adapter;
589+
}
590+
}
591+
}

ShaderGlass/CaptureManager.h

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ class CaptureManager
5757
std::vector<std::tuple<int, ShaderParam*>> Params();
5858
const ShaderCache& Cache();
5959
const std::vector<CaptureDevice>& CaptureDevices();
60+
const std::vector<GraphicsAdapter>& GraphicsAdapters();
6061
void ShowCursor();
6162
void HideCursor();
6263

@@ -93,11 +94,13 @@ class CaptureManager
9394
float OutFPS();
9495
int FindByName(const char* presetName);
9596
bool FindDeviceFormat(int deviceFormatNo, std::vector<CaptureDevice>::const_iterator& device, std::vector<CaptureFormat>::const_iterator& format);
97+
void SetCaptureAdapters(const std::wstring& captureId, const std::wstring& renderId);
9698

9799
private:
98100
volatile bool m_active {false};
99-
winrt::com_ptr<ID3D11Device> m_d3dDevice {nullptr};
100-
winrt::com_ptr<ID3D11DeviceContext> m_context {nullptr};
101+
winrt::com_ptr<ID3D11Device> m_captureDevice {nullptr};
102+
winrt::com_ptr<ID3D11Device> m_renderDevice {nullptr};
103+
winrt::com_ptr<ID3D11DeviceContext> m_renderContext {nullptr};
101104
winrt::com_ptr<ID3D11Debug> m_debug {nullptr};
102105
winrt::com_ptr<ID3D11Texture2D> m_outputTexture {nullptr};
103106
std::unique_ptr<CaptureSession> m_session {nullptr};
@@ -106,6 +109,9 @@ class CaptureManager
106109
std::vector<std::tuple<int, std::string, double>> m_queuedParams;
107110
std::vector<std::tuple<int, std::string, double>> m_lastParams;
108111
std::vector<CaptureDevice> m_captureDevices;
112+
std::vector<GraphicsAdapter> m_graphicsAdapters;
113+
IDXGIAdapter* m_captureAdapter {nullptr};
114+
IDXGIAdapter* m_renderAdapter {nullptr};
109115
ShaderCache m_shaderCache;
110116
DeviceCapture m_deviceCapture;
111117
CursorEmulator m_cursorEmulator;

ShaderGlass/CaptureSession.cpp

Lines changed: 125 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -24,13 +24,18 @@ using namespace Windows::UI;
2424
using namespace Windows::UI::Composition;
2525
} // namespace winrt
2626

27-
CaptureSession::CaptureSession(winrt::IDirect3DDevice const& device,
27+
CaptureSession::CaptureSession(winrt::com_ptr<ID3D11Device> captureDevice,
28+
winrt::com_ptr<ID3D11Device> renderDevice,
2829
winrt::GraphicsCaptureItem const& item,
2930
winrt::DirectXPixelFormat pixelFormat,
3031
ShaderGlass& shaderGlass,
3132
bool maxCaptureRate,
32-
HANDLE frameEvent) : m_device {device}, m_item {item}, m_pixelFormat {pixelFormat}, m_shaderGlass {shaderGlass}, m_frameEvent(frameEvent)
33+
HANDLE frameEvent) :
34+
m_device {nullptr}, m_item {item}, m_pixelFormat {pixelFormat}, m_shaderGlass {shaderGlass}, m_textureBridge {captureDevice, renderDevice}, m_frameEvent(frameEvent)
3335
{
36+
auto dxgiDevice = captureDevice.as<IDXGIDevice>();
37+
m_device = CreateDirect3DDevice(dxgiDevice.get());
38+
3439
m_contentSize = m_item.Size();
3540
m_framePool = winrt::Direct3D11CaptureFramePool::CreateFreeThreaded(m_device, pixelFormat, 2, m_contentSize);
3641
m_session = m_framePool.CreateCaptureSession(m_item);
@@ -65,10 +70,8 @@ CaptureSession::CaptureSession(winrt::IDirect3DDevice const& device,
6570
WINRT_ASSERT(m_session != nullptr);
6671
}
6772

68-
CaptureSession::CaptureSession(winrt::Windows::Graphics::DirectX::Direct3D11::IDirect3DDevice const& device,
69-
winrt::com_ptr<ID3D11Texture2D> inputImage,
70-
ShaderGlass& shaderGlass,
71-
HANDLE frameEvent) : m_device {device}, m_inputImage {inputImage}, m_shaderGlass {shaderGlass}, m_frameEvent {frameEvent}
73+
CaptureSession::CaptureSession(winrt::com_ptr<ID3D11Texture2D> inputImage, ShaderGlass& shaderGlass, HANDLE frameEvent) :
74+
m_device {nullptr}, m_inputImage {inputImage}, m_shaderGlass {shaderGlass}, m_textureBridge {nullptr, nullptr}, m_frameEvent {frameEvent}
7275
{
7376
Reset();
7477
ProcessInput();
@@ -90,17 +93,21 @@ void CaptureSession::UpdateCursor(bool captureCursor)
9093

9194
void CaptureSession::OnFrameArrived(winrt::Direct3D11CaptureFramePool const& sender, winrt::IInspectable const&)
9295
{
93-
auto frame = sender.TryGetNextFrame();
94-
m_inputFrame = GetDXGIInterfaceFromObject<ID3D11Texture2D>(frame.Surface());
96+
auto frame = sender.TryGetNextFrame();
97+
auto inputFrame = GetDXGIInterfaceFromObject<ID3D11Texture2D>(frame.Surface());
9598

9699
auto contentSize = frame.ContentSize();
100+
auto resized = false;
97101
if(contentSize.Width != m_contentSize.Width || contentSize.Height != m_contentSize.Height)
98102
{
99103
m_contentSize.Width = contentSize.Width;
100104
m_contentSize.Height = contentSize.Height;
101105
m_framePool.Recreate(m_device, m_pixelFormat, 2, m_contentSize);
106+
resized = true;
102107
}
103108

109+
m_textureBridge.PutInputFrame(inputFrame, resized);
110+
104111
SetEvent(m_frameEvent);
105112
OnInputFrame();
106113
}
@@ -127,7 +134,7 @@ void CaptureSession::ProcessInput()
127134
}
128135
else
129136
{
130-
m_shaderGlass.Process(m_inputFrame, m_frameTicks, m_numInputFrames);
137+
m_shaderGlass.Process(m_textureBridge.GetInputFrame(), m_frameTicks, m_numInputFrames);
131138
}
132139
}
133140

@@ -143,3 +150,112 @@ void CaptureSession::Stop()
143150
m_session = nullptr;
144151
m_item = nullptr;
145152
}
153+
154+
TextureBridge::TextureBridge(winrt::com_ptr<ID3D11Device> captureDevice, winrt::com_ptr<ID3D11Device> renderDevice) : m_captureDevice {captureDevice}, m_renderDevice {renderDevice}
155+
{
156+
if(m_renderDevice)
157+
{
158+
m_renderDevice->GetImmediateContext(m_renderContext.put());
159+
m_captureDevice->GetImmediateContext(m_captureContext.put());
160+
}
161+
}
162+
163+
TextureBridge::~TextureBridge()
164+
{
165+
if(m_inputData)
166+
{
167+
free(m_inputData);
168+
m_inputData = nullptr;
169+
}
170+
}
171+
172+
void TextureBridge::PutInputFrame(winrt::com_ptr<ID3D11Texture2D> inputFrame, bool resized)
173+
{
174+
if(m_renderDevice)
175+
{
176+
// copy to staging texture and then memory buffer
177+
HRESULT hr;
178+
D3D11_TEXTURE2D_DESC sharedDesc = {};
179+
inputFrame->GetDesc(&sharedDesc);
180+
181+
if(!m_sharedFrame || resized)
182+
{
183+
sharedDesc.Usage = D3D11_USAGE_STAGING;
184+
sharedDesc.BindFlags = 0;
185+
sharedDesc.CPUAccessFlags = D3D11_CPU_ACCESS_READ;
186+
sharedDesc.MiscFlags = 0;
187+
hr = m_captureDevice->CreateTexture2D(&sharedDesc, nullptr, m_sharedFrame.put());
188+
assert(SUCCEEDED(hr));
189+
}
190+
191+
m_captureContext->CopyResource(m_sharedFrame.get(), inputFrame.get());
192+
193+
D3D11_MAPPED_SUBRESOURCE sourceResource;
194+
hr = m_captureContext->Map(m_sharedFrame.get(), 0, D3D11_MAP_READ, 0, &sourceResource);
195+
assert(SUCCEEDED(hr));
196+
if(sourceResource.DepthPitch)
197+
{
198+
std::unique_lock lock(m_inputMutex);
199+
200+
if(resized || m_inputSize == 0)
201+
{
202+
memcpy(&m_inputFrameDesc, &sharedDesc, sizeof(D3D11_TEXTURE2D_DESC));
203+
m_inputResized = true;
204+
}
205+
206+
if(sourceResource.DepthPitch != m_inputSize)
207+
{
208+
if(m_inputData)
209+
free(m_inputData);
210+
211+
m_inputSize = sourceResource.DepthPitch;
212+
m_inputData = malloc(m_inputSize);
213+
assert(m_inputData);
214+
}
215+
memcpy(m_inputData, sourceResource.pData, sourceResource.DepthPitch);
216+
m_inputUpdated = true;
217+
}
218+
m_captureContext->Unmap(m_sharedFrame.get(), 0);
219+
}
220+
else
221+
{
222+
m_inputFrame = inputFrame;
223+
}
224+
}
225+
226+
winrt::com_ptr<ID3D11Texture2D> TextureBridge::GetInputFrame()
227+
{
228+
if(m_renderDevice && m_inputUpdated)
229+
{
230+
// copy from local buffer
231+
HRESULT hr;
232+
if(!m_inputFrame || m_inputResized)
233+
{
234+
D3D11_TEXTURE2D_DESC inputDesc = {};
235+
memcpy(&inputDesc, &m_inputFrameDesc, sizeof(D3D11_TEXTURE2D_DESC));
236+
237+
inputDesc.Usage = D3D11_USAGE_DYNAMIC;
238+
inputDesc.BindFlags = D3D11_BIND_SHADER_RESOURCE;
239+
inputDesc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
240+
inputDesc.MiscFlags = 0;
241+
hr = m_renderDevice->CreateTexture2D(&inputDesc, nullptr, m_inputFrame.put());
242+
assert(SUCCEEDED(hr));
243+
m_inputResized = false;
244+
}
245+
246+
{
247+
std::unique_lock lock(m_inputMutex);
248+
if(m_inputData && m_inputSize)
249+
{
250+
D3D11_MAPPED_SUBRESOURCE destinationResource;
251+
hr = m_renderContext->Map(m_inputFrame.get(), 0, D3D11_MAP_WRITE_DISCARD, 0, &destinationResource);
252+
assert(SUCCEEDED(hr));
253+
assert(m_inputSize == destinationResource.DepthPitch);
254+
memcpy(destinationResource.pData, m_inputData, destinationResource.DepthPitch);
255+
m_renderContext->Unmap(m_inputFrame.get(), 0);
256+
}
257+
m_inputUpdated = false;
258+
}
259+
}
260+
return m_inputFrame;
261+
}

0 commit comments

Comments
 (0)