Skip to content
This repository was archived by the owner on Apr 26, 2023. It is now read-only.

Commit 659665a

Browse files
AvasamAlgomancer
andcommitted
Get IDirect3dDevice from LearningModelDevice
Closes Toufool#175 Co-authored-by: Algomancer <[email protected]>
1 parent efc38b0 commit 659665a

File tree

4 files changed

+33
-26
lines changed

4 files changed

+33
-26
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@ This program can be used to automatically start, split, and reset your preferred
8181
The smaller the selected region, the more efficient it is.
8282
- **Windows Graphics Capture** (fast, most compatible, capped at 60fps)
8383
Only available in Windows 10.0.17134 and up.
84-
Due to current technical limitations, it requires having at least one audio or video Capture Device connected and enabled. Even if it won't be used.
84+
Due to current technical limitations, Windows versions below 10.0.0.17763 require having at least one audio or video Capture Device connected and enabled.
8585
Allows recording UWP apps, Hardware Accelerated and Exclusive Fullscreen windows.
8686
Adds a yellow border on Windows 10 (not on Windows 11).
8787
Caps at around 60 FPS.

src/capture_method/WindowsGraphicsCaptureMethod.py

Lines changed: 3 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,9 @@
1111
from winsdk.windows.graphics.capture.interop import create_for_window
1212
from winsdk.windows.graphics.directx import DirectXPixelFormat
1313
from winsdk.windows.graphics.imaging import BitmapBufferAccessMode, SoftwareBitmap
14-
from winsdk.windows.media.capture import MediaCapture
1514

1615
from capture_method.CaptureMethodBase import CaptureMethodBase
17-
from utils import WINDOWS_BUILD_NUMBER, is_valid_hwnd
16+
from utils import WINDOWS_BUILD_NUMBER, get_direct3d_device, is_valid_hwnd
1817

1918
if TYPE_CHECKING:
2019
from AutoSplit import AutoSplit
@@ -33,19 +32,10 @@ def __init__(self, autosplit: AutoSplit):
3332
super().__init__(autosplit)
3433
if not is_valid_hwnd(autosplit.hwnd):
3534
return
36-
# Note: Must create in the same thread (can't use a global) otherwise when ran from LiveSplit it will raise:
37-
# OSError: The application called an interface that was marshalled for a different thread
38-
media_capture = MediaCapture()
39-
item = create_for_window(autosplit.hwnd)
40-
41-
async def coroutine():
42-
await (media_capture.initialize_async() or asyncio.sleep(0))
43-
asyncio.run(coroutine())
4435

45-
if not media_capture.media_capture_settings:
46-
raise OSError("Unable to initialize a Direct3D Device.")
36+
item = create_for_window(autosplit.hwnd)
4737
frame_pool = Direct3D11CaptureFramePool.create_free_threaded(
48-
media_capture.media_capture_settings.direct3_d11_device,
38+
get_direct3d_device(),
4939
DirectXPixelFormat.B8_G8_R8_A8_UINT_NORMALIZED,
5040
1,
5141
item.size,

src/capture_method/__init__.py

Lines changed: 10 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -7,21 +7,22 @@
77
from typing import TYPE_CHECKING, TypedDict
88

99
from pygrabber import dshow_graph
10-
from winsdk.windows.media.capture import MediaCapture
1110

1211
from capture_method.BitBltCaptureMethod import BitBltCaptureMethod
1312
from capture_method.CaptureMethodBase import CaptureMethodBase
1413
from capture_method.DesktopDuplicationCaptureMethod import DesktopDuplicationCaptureMethod
1514
from capture_method.ForceFullContentRenderingCaptureMethod import ForceFullContentRenderingCaptureMethod
1615
from capture_method.VideoCaptureDeviceCaptureMethod import VideoCaptureDeviceCaptureMethod
1716
from capture_method.WindowsGraphicsCaptureMethod import WindowsGraphicsCaptureMethod
18-
from utils import WINDOWS_BUILD_NUMBER
17+
from utils import WINDOWS_BUILD_NUMBER, get_direct3d_device
1918

2019
if TYPE_CHECKING:
2120
from AutoSplit import AutoSplit
2221

2322
WGC_MIN_BUILD = 17134
2423
"""https://docs.microsoft.com/en-us/uwp/api/windows.graphics.capture.graphicscapturepicker#applies-to"""
24+
LEARNING_MODE_DEVICE_BUILD = 17763
25+
"""https://learn.microsoft.com/en-us/uwp/api/windows.ai.machinelearning.learningmodeldevice"""
2526

2627

2728
class Region(TypedDict):
@@ -121,8 +122,8 @@ def __getitem__(self, key: CaptureMethodEnum):
121122
short_description="fast, most compatible, capped at 60fps",
122123
description=(
123124
f"\nOnly available in Windows 10.0.{WGC_MIN_BUILD} and up. "
124-
"\nDue to current technical limitations, it requires having at least one "
125-
"\naudio or video Capture Device connected and enabled. Even if it won't be used. "
125+
f"\nDue to current technical limitations, Windows versions below 10.0.0.{LEARNING_MODE_DEVICE_BUILD}"
126+
"\nrequire having at least one audio or video Capture Device connected and enabled."
126127
"\nAllows recording UWP apps, Hardware Accelerated and Exclusive Fullscreen windows. "
127128
"\nAdds a yellow border on Windows 10 (not on Windows 11)."
128129
"\nCaps at around 60 FPS. "
@@ -166,21 +167,18 @@ def __getitem__(self, key: CaptureMethodEnum):
166167
})
167168

168169

169-
def test_for_media_capture():
170-
async def coroutine():
171-
return await (MediaCapture().initialize_async() or asyncio.sleep(0))
170+
def try_get_direct3d_device():
172171
try:
173-
asyncio.run(coroutine())
174-
return True
172+
return get_direct3d_device()
175173
except OSError:
176-
return False
174+
return None
177175

178176

179177
# Detect and remove unsupported capture methods
180178
if ( # Windows Graphics Capture requires a minimum Windows Build
181179
WINDOWS_BUILD_NUMBER < WGC_MIN_BUILD
182-
# Our current implementation of Windows Graphics Capture requires at least one CaptureDevice
183-
or not test_for_media_capture()
180+
# Our current implementation of Windows Graphics Capture does not ensure we can get an ID3DDevice
181+
or not try_get_direct3d_device()
184182
):
185183
CAPTURE_METHODS.pop(CaptureMethodEnum.WINDOWS_GRAPHICS_CAPTURE)
186184

src/utils.py

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@
1212

1313
import cv2
1414
from win32 import win32gui
15+
from winsdk.windows.ai.machinelearning import LearningModelDevice, LearningModelDeviceKind
16+
from winsdk.windows.media.capture import MediaCapture
1517

1618
from gen.build_vars import AUTOSPLIT_BUILD_NUMBER, AUTOSPLIT_GITHUB_REPOSITORY
1719

@@ -76,6 +78,23 @@ def get_window_bounds(hwnd: int) -> tuple[int, int, int, int]:
7678
return window_left_bounds, window_top_bounds, window_width, window_height
7779

7880

81+
def get_direct3d_device():
82+
direct_3d_device = LearningModelDevice(LearningModelDeviceKind.DIRECT_X_HIGH_PERFORMANCE).direct3_d11_device
83+
if not direct_3d_device:
84+
# Note: Must create in the same thread (can't use a global) otherwise when ran from LiveSplit it will raise:
85+
# OSError: The application called an interface that was marshalled for a different thread
86+
media_capture = MediaCapture()
87+
88+
async def coroutine():
89+
await (media_capture.initialize_async() or asyncio.sleep(0))
90+
asyncio.run(coroutine())
91+
direct_3d_device = media_capture.media_capture_settings and \
92+
media_capture.media_capture_settings.direct3_d11_device
93+
if not direct_3d_device:
94+
raise OSError("Unable to initialize a Direct3D Device.")
95+
return direct_3d_device
96+
97+
7998
def fire_and_forget(func: Callable[..., Any]):
8099
"""
81100
Runs synchronous function asynchronously without waiting for a response

0 commit comments

Comments
 (0)