-
-
Notifications
You must be signed in to change notification settings - Fork 7.6k
/
obs-qsv-test.cpp
206 lines (163 loc) · 5.22 KB
/
obs-qsv-test.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
#include <vpl/mfxstructures.h>
#include <vpl/mfxadapter.h>
#include <vpl/mfxvideo++.h>
#include "../common_utils.h"
#include <util/windows/ComPtr.hpp>
#include <dxgi.h>
#include <d3d11.h>
#include <d3d11_1.h>
#include <vector>
#include <string>
#include <map>
#ifdef _MSC_VER
extern "C" __declspec(dllexport) DWORD NvOptimusEnablement = 1;
extern "C" __declspec(dllexport) int AmdPowerXpressRequestHighPerformance = 1;
#endif
struct adapter_caps {
bool is_intel = false;
bool is_dgpu = false;
bool supports_av1 = false;
bool supports_hevc = false;
};
static std::vector<uint64_t> luid_order;
static std::map<uint32_t, adapter_caps> adapter_info;
static bool has_encoder(mfxSession m_session, mfxU32 codec_id)
{
MFXVideoENCODE *session = new MFXVideoENCODE(m_session);
mfxVideoParam video_param;
memset(&video_param, 0, sizeof(video_param));
video_param.mfx.CodecId = codec_id;
video_param.mfx.FrameInfo.FourCC = MFX_FOURCC_NV12;
video_param.mfx.FrameInfo.ChromaFormat = MFX_CHROMAFORMAT_YUV420;
video_param.mfx.FrameInfo.Width = MSDK_ALIGN16(1280);
video_param.mfx.FrameInfo.Height = MSDK_ALIGN16(720);
mfxStatus sts = session->Query(&video_param, &video_param);
session->Close();
return sts == MFX_ERR_NONE;
}
static inline uint32_t get_adapter_idx(uint32_t adapter_idx, LUID luid)
{
for (size_t i = 0; i < luid_order.size(); i++) {
if (luid_order[i] == *(uint64_t *)&luid) {
return (uint32_t)i;
}
}
return adapter_idx;
}
static bool get_adapter_caps(IDXGIFactory *factory, mfxLoader loader,
mfxSession m_session, uint32_t adapter_idx)
{
HRESULT hr;
static uint32_t idx_adjustment = 0;
ComPtr<IDXGIAdapter> adapter;
hr = factory->EnumAdapters(adapter_idx, &adapter);
if (FAILED(hr))
return false;
DXGI_ADAPTER_DESC desc;
adapter->GetDesc(&desc);
uint32_t luid_idx = get_adapter_idx(adapter_idx, desc.AdapterLuid);
adapter_caps &caps = adapter_info[luid_idx];
if (desc.VendorId != INTEL_VENDOR_ID) {
idx_adjustment++;
return true;
}
caps.is_intel = true;
mfxImplDescription *idesc;
mfxStatus sts =
MFXEnumImplementations(loader, adapter_idx - idx_adjustment,
MFX_IMPLCAPS_IMPLDESCSTRUCTURE,
reinterpret_cast<mfxHDL *>(&idesc));
if (sts != MFX_ERR_NONE)
return false;
caps.is_dgpu = false;
if (idesc->Dev.MediaAdapterType == MFX_MEDIA_DISCRETE)
caps.is_dgpu = true;
caps.supports_av1 = false;
caps.supports_hevc = false;
mfxEncoderDescription *enc = &idesc->Enc;
if (enc->NumCodecs != 0) {
for (int codec = 0; codec < enc->NumCodecs; codec++) {
if (enc->Codecs[codec].CodecID == MFX_CODEC_AV1)
caps.supports_av1 = true;
#if ENABLE_HEVC
if (enc->Codecs[codec].CodecID == MFX_CODEC_HEVC)
caps.supports_hevc = true;
#endif
}
} else {
// Encoder information is not available before TGL for VPL, so the MSDK legacy approach is taken
caps.supports_av1 = has_encoder(m_session, MFX_CODEC_AV1);
#if ENABLE_HEVC
caps.supports_hevc = has_encoder(m_session, MFX_CODEC_HEVC);
#endif
}
MFXDispReleaseImplDescription(loader, idesc);
return true;
}
#define CHECK_TIMEOUT_MS 10000
DWORD WINAPI TimeoutThread(LPVOID param)
{
HANDLE hMainThread = (HANDLE)param;
DWORD ret = WaitForSingleObject(hMainThread, CHECK_TIMEOUT_MS);
if (ret == WAIT_TIMEOUT)
TerminateProcess(GetCurrentProcess(), STATUS_TIMEOUT);
CloseHandle(hMainThread);
return 0;
}
int main(int argc, char *argv[])
try {
ComPtr<IDXGIFactory> factory;
HRESULT hr;
HANDLE hMainThread;
DuplicateHandle(GetCurrentProcess(), GetCurrentThread(),
GetCurrentProcess(), &hMainThread, 0, FALSE,
DUPLICATE_SAME_ACCESS);
DWORD threadId;
HANDLE hThread;
hThread =
CreateThread(NULL, 0, TimeoutThread, hMainThread, 0, &threadId);
CloseHandle(hThread);
/* --------------------------------------------------------- */
/* parse expected LUID order */
for (int i = 1; i < argc; i++) {
luid_order.push_back(strtoull(argv[i], NULL, 16));
}
/* --------------------------------------------------------- */
/* query qsv support */
hr = CreateDXGIFactory1(__uuidof(IDXGIFactory), (void **)&factory);
if (FAILED(hr))
throw "CreateDXGIFactory1 failed";
mfxLoader loader = MFXLoad();
if (!loader)
throw "MFXLoad failed";
mfxConfig cfg = MFXCreateConfig(loader);
if (!cfg)
throw "MFXCreateConfig failed";
mfxVariant impl;
// Low latency is disabled due to encoding capabilities not being provided before TGL for VPL
impl.Type = MFX_VARIANT_TYPE_U32;
impl.Data.U32 = MFX_IMPL_TYPE_HARDWARE;
MFXSetConfigFilterProperty(
cfg, (const mfxU8 *)"mfxImplDescription.Impl", impl);
mfxSession m_session = nullptr;
mfxStatus sts = MFXCreateSession(loader, 0, &m_session);
uint32_t idx = 0;
while (get_adapter_caps(factory, loader, m_session, idx++) == true)
;
if (m_session)
MFXClose(m_session);
MFXUnload(loader);
for (auto &[idx, caps] : adapter_info) {
printf("[%u]\n", idx);
printf("is_intel=%s\n", caps.is_intel ? "true" : "false");
printf("is_dgpu=%s\n", caps.is_dgpu ? "true" : "false");
printf("supports_av1=%s\n",
caps.supports_av1 ? "true" : "false");
printf("supports_hevc=%s\n",
caps.supports_hevc ? "true" : "false");
}
return 0;
} catch (const char *text) {
printf("[error]\nstring=%s\n", text);
return 0;
}