1 /*
2 * Copyright © Microsoft Corporation
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice (including the next
12 * paragraph) shall be included in all copies or substantial portions of the
13 * Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
21 * IN THE SOFTWARE.
22 */
23
24 #include <stdio.h>
25 #include <stdbool.h>
26 #include <va/va_win32.h>
27 #include "va_display.h"
28 #include <directx/dxcore_interface.h>
29
30 extern "C" const char *g_device_name;
31
dxcore_resolve_adapter(const char * adapter_string,bool * ptr_device_found,LUID * ptr_adapter_luid)32 void dxcore_resolve_adapter(const char *adapter_string, /*out*/ bool* ptr_device_found, /*out*/ LUID* ptr_adapter_luid)
33 {
34 int selected_adapter_index = -1;
35 IDXCoreAdapterFactory *factory = nullptr;
36 IDXCoreAdapterList *adapter_list = nullptr;
37 IDXCoreAdapter *adapter = nullptr;
38 typedef HRESULT(WINAPI * PFN_CREATE_DXCORE_ADAPTER_FACTORY)(REFIID riid, void **ppFactory);
39 PFN_CREATE_DXCORE_ADAPTER_FACTORY DXCoreCreateAdapterFactory;
40 HRESULT hr = S_OK;
41
42 memset(ptr_adapter_luid, 0, sizeof(LUID));
43 *ptr_device_found = false;
44
45 HMODULE dxcore_mod = LoadLibrary("DXCore.DLL");
46 if (!dxcore_mod) {
47 fprintf(stderr, "Failed to load DXCore.DLL to enumerate adapters.\n");
48 goto fail;
49 }
50
51 DXCoreCreateAdapterFactory = (PFN_CREATE_DXCORE_ADAPTER_FACTORY)GetProcAddress(dxcore_mod, "DXCoreCreateAdapterFactory");
52 if (!DXCoreCreateAdapterFactory) {
53 fprintf(stderr, "Failed to load DXCoreCreateAdapterFactory from DXCore.DLL.\n");
54 goto fail;
55 }
56
57 hr = DXCoreCreateAdapterFactory(IID_IDXCoreAdapterFactory, (void **)&factory);
58 if (FAILED(hr)) {
59 fprintf(stderr, "DXCoreCreateAdapterFactory failed: %lx\n", hr);
60 goto fail;
61 }
62
63 hr = factory->CreateAdapterList(1, &DXCORE_ADAPTER_ATTRIBUTE_D3D12_GRAPHICS, IID_IDXCoreAdapterList, (void **)&adapter_list);
64 if (FAILED(hr)) {
65 fprintf(stderr, "CreateAdapterList failed: %lx\n", hr);
66 goto fail;
67 }
68
69 if (adapter_string && (sscanf_s(adapter_string, "%d", &selected_adapter_index) != 1)) {
70 fprintf(stderr, "Invalid device index received for -hwaccel_device %s\n", adapter_string ? adapter_string : "");
71 }
72
73 if (!adapter_string) fprintf(stdout, "Available devices for --display win32:\n");
74 for (int i = 0; i < adapter_list->GetAdapterCount(); i++) {
75 if (SUCCEEDED(adapter_list->GetAdapter(i, IID_IDXCoreAdapter, (void **)&adapter))) {
76 size_t desc_size = 0;
77 if (FAILED(adapter->GetPropertySize(DXCoreAdapterProperty::DriverDescription, &desc_size))) {
78 adapter->Release();
79 continue;
80 }
81
82 char *adapter_name = (char*)malloc(desc_size);
83 if (!adapter_name) {
84 adapter->Release();
85 continue;
86 }
87
88 if (FAILED(adapter->GetProperty(DXCoreAdapterProperty::DriverDescription, desc_size, adapter_name))) {
89 free(adapter_name);
90 adapter->Release();
91 continue;
92 }
93
94 LUID cur_adapter_luid = { 0, 0 };
95 if (FAILED(adapter->GetProperty(DXCoreAdapterProperty::InstanceLuid, &cur_adapter_luid))) {
96 free(adapter_name);
97 adapter->Release();
98 continue;
99 }
100
101 if (selected_adapter_index == i) {
102 *ptr_adapter_luid = cur_adapter_luid;
103 *ptr_device_found = true;
104 }
105
106 if (!adapter_string) fprintf(stdout, "\tDevice Index: %d Device LUID: %lu %ld - Device Name: %s\n", i, cur_adapter_luid.LowPart, cur_adapter_luid.HighPart, adapter_name);
107 free(adapter_name);
108 adapter->Release();
109 }
110 }
111
112 fail:
113 if (adapter_list)
114 adapter_list->Release();
115 if (factory)
116 factory->Release();
117 if (dxcore_mod)
118 FreeLibrary(dxcore_mod);
119 }
120
121 static VADisplay
va_open_display_win32(void)122 va_open_display_win32(void)
123 {
124 LUID adapter_luid = {0, 0};
125 bool device_found = false;
126 if (g_device_name) {
127 bool print_devices = (0 == strcmp(g_device_name, "help"));
128 dxcore_resolve_adapter(print_devices ? NULL : g_device_name, &device_found, &adapter_luid);
129 if (print_devices) {
130 exit(0);
131 } else if (g_device_name && !device_found) {
132 fprintf(stderr, "Could not find device %s for --display win32. Please try --device help for a list of available devices.\n", g_device_name);
133 exit(0);
134 }
135 }
136
137 // Adapter automatic selection supported by sending NULL adapter to vaGetDisplayWin32
138 return vaGetDisplayWin32(device_found ? &adapter_luid : NULL);
139 }
140
141 static void
va_close_display_win32(VADisplay va_dpy)142 va_close_display_win32(VADisplay va_dpy)
143 {
144 }
145
146 static VAStatus
va_put_surface_win32(VADisplay va_dpy,VASurfaceID surface,const VARectangle * src_rect,const VARectangle * dst_rect)147 va_put_surface_win32(
148 VADisplay va_dpy,
149 VASurfaceID surface,
150 const VARectangle *src_rect,
151 const VARectangle *dst_rect
152 )
153 {
154 return VA_STATUS_ERROR_OPERATION_FAILED;
155 }
156
157 #ifdef __cplusplus
158 extern "C" {
159 #endif
160
161 extern const VADisplayHooks va_display_hooks_win32 = {
162 "win32",
163 va_open_display_win32,
164 va_close_display_win32,
165 va_put_surface_win32,
166 };
167
168 #ifdef __cplusplus
169 }
170 #endif
171