Skip to content

Commit f0b05e1

Browse files
Initial support for reusing game D3D device as fallback #58
- e.g. support overlay and screenshot in dota2 with -DX11
1 parent 1961aef commit f0b05e1

File tree

2 files changed

+116
-73
lines changed

2 files changed

+116
-73
lines changed

Capture/Hook/BaseDXHook.cs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,10 @@ protected void DebugMessage(string message)
113113
{
114114
// Ignore remoting exceptions
115115
}
116+
catch (Exception)
117+
{
118+
// Ignore all other exceptions
119+
}
116120
#endif
117121
}
118122

Capture/Hook/DXHookD3D11.cs

Lines changed: 112 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,7 @@ public DXHookD3D11(CaptureInterface ssInterface)
9191
SharpDX.Windows.RenderForm _renderForm;
9292
Texture2D _resolvedRTShared;
9393
SharpDX.DXGI.KeyedMutex _resolvedRTSharedKeyedMutex;
94-
ShaderResourceView _resolvedSharedSRV;
94+
ShaderResourceView _resolvedSRV;
9595
Capture.Hook.DX11.ScreenAlignedQuadRenderer _saQuad;
9696
Texture2D _finalRT;
9797
Texture2D _resizedRT;
@@ -107,7 +107,6 @@ public DXHookD3D11(CaptureInterface ssInterface)
107107
Texture2D _resolvedRT;
108108
SharpDX.DXGI.KeyedMutex _resolvedRTKeyedMutex;
109109
SharpDX.DXGI.KeyedMutex _resolvedRTKeyedMutex_Dev2;
110-
//ShaderResourceView _resolvedSRV;
111110
#endregion
112111

113112
protected override string HookName
@@ -228,16 +227,111 @@ int ResizeTargetHook(IntPtr swapChainPtr, ref ModeDescription newTargetParameter
228227
return DXGISwapChain_ResizeTargetHook.Original(swapChainPtr, ref newTargetParameters);
229228
}
230229

231-
void EnsureResources(SharpDX.Direct3D11.Device device, Texture2DDescription description, Rectangle captureRegion, ScreenshotRequest request)
230+
void EnsureResources(SharpDX.Direct3D11.Device device, Texture2DDescription description, Rectangle captureRegion, ScreenshotRequest request, bool useSameDeviceForResize = false)
232231
{
233-
if (_device != null && request.Resize != null && (_resizedRT == null || (_resizedRT.Device.NativePointer != _device.NativePointer || _resizedRT.Description.Width != request.Resize.Value.Width || _resizedRT.Description.Height != request.Resize.Value.Height)))
232+
var resizeDevice = useSameDeviceForResize ? device : _device;
233+
234+
// Check if _resolvedRT or _finalRT require creation
235+
if (_finalRT != null && (_finalRT.Device.NativePointer == device.NativePointer || _finalRT.Device.NativePointer == _device.NativePointer) &&
236+
_finalRT.Description.Height == captureRegion.Height && _finalRT.Description.Width == captureRegion.Width &&
237+
_resolvedRT != null && _resolvedRT.Description.Height == description.Height && _resolvedRT.Description.Width == description.Width &&
238+
(_resolvedRT.Device.NativePointer == device.NativePointer || _resolvedRT.Device.NativePointer == _device.NativePointer) && _resolvedRT.Description.Format == description.Format
239+
)
240+
{
241+
242+
}
243+
else
244+
{
245+
RemoveAndDispose(ref _query);
246+
RemoveAndDispose(ref _resolvedRT);
247+
RemoveAndDispose(ref _resolvedSRV);
248+
RemoveAndDispose(ref _finalRT);
249+
RemoveAndDispose(ref _resolvedRTShared);
250+
RemoveAndDispose(ref _resolvedRTKeyedMutex);
251+
RemoveAndDispose(ref _resolvedRTKeyedMutex_Dev2);
252+
253+
_query = new Query(resizeDevice, new QueryDescription()
254+
{
255+
Flags = QueryFlags.None,
256+
Type = QueryType.Event
257+
});
258+
_queryIssued = false;
259+
260+
try
261+
{
262+
ResourceOptionFlags resolvedRTOptionFlags = ResourceOptionFlags.None;
263+
264+
if (device != resizeDevice)
265+
resolvedRTOptionFlags |= ResourceOptionFlags.SharedKeyedmutex;
266+
267+
_resolvedRT = ToDispose(new Texture2D(device, new Texture2DDescription()
268+
{
269+
CpuAccessFlags = CpuAccessFlags.None,
270+
Format = description.Format, // for multisampled backbuffer, this must be same format
271+
Height = description.Height,
272+
Usage = ResourceUsage.Default,
273+
Width = description.Width,
274+
ArraySize = 1,
275+
SampleDescription = new SharpDX.DXGI.SampleDescription(1, 0), // Ensure single sample
276+
BindFlags = BindFlags.ShaderResource,
277+
MipLevels = 1,
278+
OptionFlags = resolvedRTOptionFlags
279+
}));
280+
}
281+
catch
282+
{
283+
// Failed to create the shared resource, try again using the same device as game for resize
284+
EnsureResources(device, description, captureRegion, request, true);
285+
return;
286+
}
287+
288+
// Retrieve reference to the keyed mutex
289+
_resolvedRTKeyedMutex = ToDispose(_resolvedRT.QueryInterfaceOrNull<SharpDX.DXGI.KeyedMutex>());
290+
291+
// If the resolvedRT is a shared resource _resolvedRTKeyedMutex will not be null
292+
if (_resolvedRTKeyedMutex != null)
293+
{
294+
using (var resource = _resolvedRT.QueryInterface<SharpDX.DXGI.Resource>())
295+
{
296+
_resolvedRTShared = ToDispose(resizeDevice.OpenSharedResource<Texture2D>(resource.SharedHandle));
297+
_resolvedRTKeyedMutex_Dev2 = ToDispose(_resolvedRTShared.QueryInterfaceOrNull<SharpDX.DXGI.KeyedMutex>());
298+
}
299+
// SRV for use if resizing
300+
_resolvedSRV = ToDispose(new ShaderResourceView(resizeDevice, _resolvedRTShared));
301+
}
302+
else
303+
{
304+
_resolvedSRV = ToDispose(new ShaderResourceView(resizeDevice, _resolvedRT));
305+
}
306+
307+
_finalRT = ToDispose(new Texture2D(resizeDevice, new Texture2DDescription()
308+
{
309+
CpuAccessFlags = CpuAccessFlags.Read,
310+
Format = description.Format,
311+
Height = captureRegion.Height,
312+
Usage = ResourceUsage.Staging,
313+
Width = captureRegion.Width,
314+
ArraySize = 1,
315+
SampleDescription = new SharpDX.DXGI.SampleDescription(1, 0),
316+
BindFlags = BindFlags.None,
317+
MipLevels = 1,
318+
OptionFlags = ResourceOptionFlags.None
319+
}));
320+
_finalRTMapped = false;
321+
}
322+
323+
if (_resolvedRT != null && _resolvedRTKeyedMutex_Dev2 == null && resizeDevice == _device)
324+
resizeDevice = device;
325+
326+
if (resizeDevice != null && request.Resize != null && (_resizedRT == null || (_resizedRT.Device.NativePointer != resizeDevice.NativePointer || _resizedRT.Description.Width != request.Resize.Value.Width || _resizedRT.Description.Height != request.Resize.Value.Height)))
234327
{
235328
// Create/Recreate resources for resizing
236329
RemoveAndDispose(ref _resizedRT);
237330
RemoveAndDispose(ref _resizedRTV);
238331
RemoveAndDispose(ref _saQuad);
239332

240-
_resizedRT = ToDispose(new Texture2D(_device, new Texture2DDescription() {
333+
_resizedRT = ToDispose(new Texture2D(resizeDevice, new Texture2DDescription()
334+
{
241335
Format = SharpDX.DXGI.Format.R8G8B8A8_UNorm, // Supports BMP/PNG/etc
242336
Height = request.Resize.Value.Height,
243337
Width = request.Resize.Value.Width,
@@ -249,74 +343,11 @@ void EnsureResources(SharpDX.Direct3D11.Device device, Texture2DDescription desc
249343
OptionFlags = ResourceOptionFlags.None
250344
}));
251345

252-
_resizedRTV = ToDispose(new RenderTargetView(_device, _resizedRT));
346+
_resizedRTV = ToDispose(new RenderTargetView(resizeDevice, _resizedRT));
253347

254348
_saQuad = ToDispose(new DX11.ScreenAlignedQuadRenderer());
255-
_saQuad.Initialize(new DX11.DeviceManager(_device));
256-
}
257-
258-
// Check if _resolvedRT or _finalRT require creation
259-
if (_finalRT != null && _finalRT.Device.NativePointer == _device.NativePointer &&
260-
_finalRT.Description.Height == captureRegion.Height && _finalRT.Description.Width == captureRegion.Width &&
261-
_resolvedRT != null && _resolvedRT.Description.Height == description.Height && _resolvedRT.Description.Width == description.Width &&
262-
_resolvedRT.Device.NativePointer == device.NativePointer && _resolvedRT.Description.Format == description.Format
263-
)
264-
{
265-
return;
266-
}
267-
268-
RemoveAndDispose(ref _query);
269-
RemoveAndDispose(ref _resolvedRT);
270-
RemoveAndDispose(ref _resolvedSharedSRV);
271-
RemoveAndDispose(ref _finalRT);
272-
RemoveAndDispose(ref _resolvedRTShared);
273-
274-
_query = new Query(_device, new QueryDescription()
275-
{
276-
Flags = QueryFlags.None,
277-
Type = QueryType.Event
278-
});
279-
_queryIssued = false;
280-
281-
_resolvedRT = ToDispose(new Texture2D(device, new Texture2DDescription() {
282-
CpuAccessFlags = CpuAccessFlags.None,
283-
Format = description.Format, // for multisampled backbuffer, this must be same format
284-
Height = description.Height,
285-
Usage = ResourceUsage.Default,
286-
Width = description.Width,
287-
ArraySize = 1,
288-
SampleDescription = new SharpDX.DXGI.SampleDescription(1, 0), // Ensure single sample
289-
BindFlags = BindFlags.ShaderResource,
290-
MipLevels = 1,
291-
OptionFlags = ResourceOptionFlags.SharedKeyedmutex
292-
}));
293-
294-
// Retrieve reference to the keyed mutex
295-
_resolvedRTKeyedMutex = ToDispose(_resolvedRT.QueryInterfaceOrNull<SharpDX.DXGI.KeyedMutex>());
296-
297-
using (var resource = _resolvedRT.QueryInterface<SharpDX.DXGI.Resource>())
298-
{
299-
_resolvedRTShared = ToDispose(_device.OpenSharedResource<Texture2D>(resource.SharedHandle));
300-
_resolvedRTKeyedMutex_Dev2 = ToDispose(_resolvedRTShared.QueryInterfaceOrNull<SharpDX.DXGI.KeyedMutex>());
349+
_saQuad.Initialize(new DX11.DeviceManager(resizeDevice));
301350
}
302-
303-
// SRV for use if resizing
304-
_resolvedSharedSRV = ToDispose(new ShaderResourceView(_device, _resolvedRTShared));
305-
306-
_finalRT = ToDispose(new Texture2D(_device, new Texture2DDescription()
307-
{
308-
CpuAccessFlags = CpuAccessFlags.Read,
309-
Format = description.Format,
310-
Height = captureRegion.Height,
311-
Usage = ResourceUsage.Staging,
312-
Width = captureRegion.Width,
313-
ArraySize = 1,
314-
SampleDescription = new SharpDX.DXGI.SampleDescription(1, 0),
315-
BindFlags = BindFlags.None,
316-
MipLevels = 1,
317-
OptionFlags = ResourceOptionFlags.None
318-
}));
319-
_finalRTMapped = false;
320351
}
321352

322353
/// <summary>
@@ -378,7 +409,7 @@ int PresentHook(IntPtr swapChainPtr, int syncInterval, SharpDX.DXGI.PresentFlags
378409
{
379410
if (_resolvedRTKeyedMutex_Dev2 != null)
380411
_resolvedRTKeyedMutex_Dev2.Acquire(1, int.MaxValue);
381-
_saQuad.ShaderResource = _resolvedSharedSRV;
412+
_saQuad.ShaderResource = _resolvedSRV;
382413
_saQuad.RenderTargetView = _resizedRTV;
383414
_saQuad.RenderTarget = _resizedRT;
384415
_saQuad.Render();
@@ -392,7 +423,10 @@ int PresentHook(IntPtr swapChainPtr, int syncInterval, SharpDX.DXGI.PresentFlags
392423
else
393424
{
394425
// Make sourceTexture be the resolved texture
395-
sourceTexture = _resolvedRTShared;
426+
if (_resolvedRTShared != null)
427+
sourceTexture = _resolvedRTShared;
428+
else
429+
sourceTexture = _resolvedRT;
396430
}
397431
}
398432
else
@@ -401,7 +435,11 @@ int PresentHook(IntPtr swapChainPtr, int syncInterval, SharpDX.DXGI.PresentFlags
401435
if (_resolvedRTKeyedMutex != null) _resolvedRTKeyedMutex.Acquire(0, int.MaxValue);
402436
currentRT.Device.ImmediateContext.CopySubresourceRegion(currentRT, 0, null, _resolvedRT, 0);
403437
if (_resolvedRTKeyedMutex != null) _resolvedRTKeyedMutex.Release(1);
404-
sourceTexture = _resolvedRTShared;
438+
439+
if (_resolvedRTShared != null)
440+
sourceTexture = _resolvedRTShared;
441+
else
442+
sourceTexture = _resolvedRT;
405443
}
406444

407445
// Copy to memory and send back to host process on a background thread so that we do not cause any delay in the rendering pipeline
@@ -412,6 +450,7 @@ int PresentHook(IntPtr swapChainPtr, int syncInterval, SharpDX.DXGI.PresentFlags
412450

413451
bool acquireLock = sourceTexture == _resolvedRTShared;
414452

453+
415454
ThreadPool.QueueUserWorkItem(new WaitCallback((o) =>
416455
{
417456
// Acquire lock on second device

0 commit comments

Comments
 (0)