obs-qsv-test.cpp 5.2 KB

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