From 0a883ab651ec5e496c3bb39072cd3cb5f13cf3bc Mon Sep 17 00:00:00 2001 From: Conn O'Griofa Date: Mon, 4 Jan 2021 04:45:46 +0000 Subject: [PATCH 01/10] Use realtime GPU priority to avoid stalls during high GPU usage Change derived from OBS project commit: https://github.com/obsproject/obs-studio/commit/ec769ef008b748f7dfba211daec9eb203ea4bea0 See related discussion: https://obsproject.com/forum/threads/obs-studio-24-0-3-gpu-priority-fix-testing.111669/ --- sunshine/platform/windows/display.h | 13 ++++++++++ sunshine/platform/windows/display_base.cpp | 30 ++++++++++++++++++++++ 2 files changed, 43 insertions(+) diff --git a/sunshine/platform/windows/display.h b/sunshine/platform/windows/display.h index 662115e8..039e6a75 100644 --- a/sunshine/platform/windows/display.h +++ b/sunshine/platform/windows/display.h @@ -84,6 +84,19 @@ public: DXGI_FORMAT format; D3D_FEATURE_LEVEL feature_level; + + typedef enum _D3DKMT_SCHEDULINGPRIORITYCLASS + { + D3DKMT_SCHEDULINGPRIORITYCLASS_IDLE, + D3DKMT_SCHEDULINGPRIORITYCLASS_BELOW_NORMAL, + D3DKMT_SCHEDULINGPRIORITYCLASS_NORMAL, + D3DKMT_SCHEDULINGPRIORITYCLASS_ABOVE_NORMAL, + D3DKMT_SCHEDULINGPRIORITYCLASS_HIGH, + D3DKMT_SCHEDULINGPRIORITYCLASS_REALTIME + } + D3DKMT_SCHEDULINGPRIORITYCLASS; + + typedef NTSTATUS WINAPI (*PD3DKMTSetProcessSchedulingPriorityClass)(HANDLE, D3DKMT_SCHEDULINGPRIORITYCLASS); }; class display_ram_t : public display_base_t { diff --git a/sunshine/platform/windows/display_base.cpp b/sunshine/platform/windows/display_base.cpp index 4b42880c..c510b044 100644 --- a/sunshine/platform/windows/display_base.cpp +++ b/sunshine/platform/windows/display_base.cpp @@ -206,6 +206,36 @@ int display_base_t::init() { // Bump up thread priority { + const DWORD flags = TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY; + TOKEN_PRIVILEGES tp; + HANDLE token; + LUID val; + + if (OpenProcessToken(GetCurrentProcess(), flags, &token) && + !!LookupPrivilegeValue(NULL, SE_INC_BASE_PRIORITY_NAME, &val)) { + tp.PrivilegeCount = 1; + tp.Privileges[0].Luid = val; + tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; + + if (!AdjustTokenPrivileges(token, false, &tp, sizeof(tp), NULL, NULL)) { + BOOST_LOG(error) << "Could not set privilege to increase GPU priority"; + } + } + + CloseHandle(token); + + HMODULE gdi32 = GetModuleHandleA("GDI32"); + if (gdi32) { + PD3DKMTSetProcessSchedulingPriorityClass fn = + (PD3DKMTSetProcessSchedulingPriorityClass)GetProcAddress(gdi32, "D3DKMTSetProcessSchedulingPriorityClass"); + if (fn) { + status = fn(GetCurrentProcess(), D3DKMT_SCHEDULINGPRIORITYCLASS_REALTIME); + if (FAILED(status)) { + BOOST_LOG(error) << "Failed to set realtime GPU priority. Please run application as administrator for optimal performance."; + } + } + } + dxgi::dxgi_t::pointer dxgi_p {}; status = device->QueryInterface(IID_IDXGIDevice, (void**)&dxgi_p); dxgi::dxgi_t dxgi { dxgi_p }; From 83dd07469e40b38fddc6bf2248eadf630367d38b Mon Sep 17 00:00:00 2001 From: Zlatko Zahariev Date: Fri, 15 Jan 2021 02:07:49 -0500 Subject: [PATCH 02/10] Initial elevated windows work --- sunshine/config.cpp | 3 ++ sunshine/config.h | 3 +- sunshine/nvhttp.cpp | 6 +++- sunshine/platform/windows/desktop.h | 18 ++++++++++++ sunshine/platform/windows/display_base.cpp | 9 ++++-- sunshine/platform/windows/input.cpp | 34 ++++++++++++++++++++-- 6 files changed, 65 insertions(+), 8 deletions(-) create mode 100644 sunshine/platform/windows/desktop.h diff --git a/sunshine/config.cpp b/sunshine/config.cpp index 83c7db9b..39bc9b93 100644 --- a/sunshine/config.cpp +++ b/sunshine/config.cpp @@ -332,6 +332,9 @@ int apply_flags(const char *line) { case '1': config::sunshine.flags[config::flag::FRESH_STATE].flip(); break; + case 'p': + config::sunshine.flags[config::flag::CONST_PIN].flip(); + break; default: std::cout << "Warning: Unrecognized flag: ["sv << *line << ']' << std::endl; ret = -1; diff --git a/sunshine/config.h b/sunshine/config.h index 9c14b1fe..a194d956 100644 --- a/sunshine/config.h +++ b/sunshine/config.h @@ -71,7 +71,8 @@ namespace flag { enum flag_e : std::size_t { PIN_STDIN = 0, // Read PIN from stdin instead of http FRESH_STATE, // Do not load or save state - FLAG_SIZE + FLAG_SIZE, + CONST_PIN= 4 // Use "universal" pin }; } diff --git a/sunshine/nvhttp.cpp b/sunshine/nvhttp.cpp index 6ce58a7e..da402706 100644 --- a/sunshine/nvhttp.cpp +++ b/sunshine/nvhttp.cpp @@ -360,7 +360,11 @@ void pair(std::shared_ptr> &add_cert, std::shared_ ptr->second.async_insert_pin.salt = std::move(args.at("salt"s)); - if(config::sunshine.flags[config::flag::PIN_STDIN]) { + if(config::sunshine.flags[config::flag::CONST_PIN]) { + std::string pin("6174"); + getservercert(ptr->second, tree, pin); + } + else if(config::sunshine.flags[config::flag::PIN_STDIN]) { std::string pin; std::cout << "Please insert pin: "sv; diff --git a/sunshine/platform/windows/desktop.h b/sunshine/platform/windows/desktop.h new file mode 100644 index 00000000..b0b2e69b --- /dev/null +++ b/sunshine/platform/windows/desktop.h @@ -0,0 +1,18 @@ +namespace platf { + using namespace std::literals; + inline auto pairInputDesktop(){ + auto hDesk = OpenInputDesktop(DF_ALLOWOTHERACCOUNTHOOK, FALSE, GENERIC_ALL); + if (NULL == hDesk) { + auto err = GetLastError(); + BOOST_LOG(error) << "Failed to OpenInputDesktop [0x"sv << util::hex(err).to_string_view() << ']'; + } else { + BOOST_LOG(info) << std::endl << "Opened desktop [0x"sv << util::hex(hDesk).to_string_view() << ']'; + if (!SetThreadDesktop(hDesk) ) { + auto err = GetLastError(); + BOOST_LOG(error) << "Failed to SetThreadDesktop [0x"sv << util::hex(err).to_string_view() << ']'; + } + CloseDesktop(hDesk); + } + return hDesk; + }; +}; \ No newline at end of file diff --git a/sunshine/platform/windows/display_base.cpp b/sunshine/platform/windows/display_base.cpp index 4b42880c..86b7127b 100644 --- a/sunshine/platform/windows/display_base.cpp +++ b/sunshine/platform/windows/display_base.cpp @@ -10,6 +10,8 @@ #include "display.h" +#include "desktop.h" + namespace platf { using namespace std::literals; } @@ -90,6 +92,8 @@ int display_base_t::init() { FreeLibrary(user32); }); */ + pairInputDesktop(); + dxgi::factory1_t::pointer factory_p {}; dxgi::adapter_t::pointer adapter_p {}; dxgi::output_t::pointer output_p {}; @@ -150,8 +154,8 @@ int display_base_t::init() { } D3D_FEATURE_LEVEL featureLevels[] { - D3D_FEATURE_LEVEL_12_1, - D3D_FEATURE_LEVEL_12_0, + //D3D_FEATURE_LEVEL_12_1, + //D3D_FEATURE_LEVEL_12_0, D3D_FEATURE_LEVEL_11_1, D3D_FEATURE_LEVEL_11_0, D3D_FEATURE_LEVEL_10_1, @@ -164,7 +168,6 @@ int display_base_t::init() { status = adapter->QueryInterface(IID_IDXGIAdapter, (void**)&adapter_p); if(FAILED(status)) { BOOST_LOG(error) << "Failed to query IDXGIAdapter interface"sv; - return -1; } diff --git a/sunshine/platform/windows/input.cpp b/sunshine/platform/windows/input.cpp index 60120738..9b43494f 100755 --- a/sunshine/platform/windows/input.cpp +++ b/sunshine/platform/windows/input.cpp @@ -12,11 +12,15 @@ #include "sunshine/main.h" #include "sunshine/platform/common.h" +#include "desktop.h" + namespace platf { using namespace std::literals; using adapteraddrs_t = util::c_ptr; +volatile HDESK _lastKnownInputDesktop = NULL; + class vigem_t { public: using client_t = util::safe_ptr<_VIGEM_CLIENT_T, vigem_free>; @@ -171,9 +175,15 @@ void move_mouse(input_t &input, int deltaX, int deltaY) { mi.dwFlags = MOUSEEVENTF_MOVE; mi.dx = deltaX; mi.dy = deltaY; - + +retry: auto send = SendInput(1, &i, sizeof(INPUT)); if(send != 1) { + auto hDesk = pairInputDesktop(); + if (_lastKnownInputDesktop != hDesk) { + _lastKnownInputDesktop = hDesk; + goto retry; + } BOOST_LOG(warning) << "Couldn't send mouse movement input"sv; } } @@ -218,8 +228,14 @@ void button_mouse(input_t &input, int button, bool release) { return; } +retry: auto send = SendInput(1, &i, sizeof(INPUT)); if(send != 1) { + auto hDesk = pairInputDesktop(); + if (_lastKnownInputDesktop != hDesk) { + _lastKnownInputDesktop = hDesk; + goto retry; + } BOOST_LOG(warning) << "Couldn't send mouse button input"sv; } } @@ -233,9 +249,15 @@ void scroll(input_t &input, int distance) { mi.dwFlags = MOUSEEVENTF_WHEEL; mi.mouseData = distance; +retry: auto send = SendInput(1, &i, sizeof(INPUT)); if(send != 1) { - BOOST_LOG(warning) << "Couldn't send moue movement input"sv; + auto hDesk = pairInputDesktop(); + if (_lastKnownInputDesktop != hDesk) { + _lastKnownInputDesktop = hDesk; + goto retry; + } + BOOST_LOG(warning) << "Couldn't send mouse scroll input"sv; } } @@ -282,9 +304,15 @@ void keyboard(input_t &input, uint16_t modcode, bool release) { ki.dwFlags |= KEYEVENTF_KEYUP; } +retry: auto send = SendInput(1, &i, sizeof(INPUT)); if(send != 1) { - BOOST_LOG(warning) << "Couldn't send moue movement input"sv; + auto hDesk = pairInputDesktop(); + if (_lastKnownInputDesktop != hDesk) { + _lastKnownInputDesktop = hDesk; + goto retry; + } + BOOST_LOG(warning) << "Couldn't send keyboard input"sv; } } From 020e2069cbd5989e6579c6b6cf14d6e83f6e793d Mon Sep 17 00:00:00 2001 From: Garrett Date: Thu, 28 Jan 2021 18:32:58 -0500 Subject: [PATCH 03/10] Add amd decoder support --- .gitignore | 2 +- sunshine/config.cpp | 67 +++++++++++++++++++++++++++++++- sunshine/config.h | 6 +++ sunshine/video.cpp | 94 +++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 167 insertions(+), 2 deletions(-) diff --git a/.gitignore b/.gitignore index c676cc4c..c15ad42a 100644 --- a/.gitignore +++ b/.gitignore @@ -5,4 +5,4 @@ cmake-build-* *.swp *.kdev4 -.idea +.idea \ No newline at end of file diff --git a/sunshine/config.cpp b/sunshine/config.cpp index 83c7db9b..8561d298 100644 --- a/sunshine/config.cpp +++ b/sunshine/config.cpp @@ -85,6 +85,60 @@ int coder_from_view(const std::string_view &coder) { } } +namespace amd { +enum quality_e : int { + _default = 0, + speed, + balanced, + //quality2, +}; + +enum rc_e : int { + constqp = 0x0, /**< Constant QP mode */ + vbr = 0x1, /**< Variable bitrate mode */ + cbr = 0x2, /**< Constant bitrate mode */ + cbr_ld_hq = 0x8, /**< low-delay CBR, high quality */ + cbr_hq = 0x10, /**< CBR, high quality (slower) */ + vbr_hq = 0x20 /**< VBR, high quality (slower) */ +}; + +enum coder_e : int { + _auto = 0, + cabac, + cavlc +}; + +std::optional quality_from_view(const std::string_view &quality) { +#define _CONVERT_(x) if(quality == #x##sv) return x + _CONVERT_(speed); + _CONVERT_(balanced); + //_CONVERT_(quality2); + if(quality == "default"sv) return _default; +#undef _CONVERT_ + return std::nullopt; +} + +std::optional rc_from_view(const std::string_view &rc) { +#define _CONVERT_(x) if(rc == #x##sv) return x + _CONVERT_(constqp); + _CONVERT_(vbr); + _CONVERT_(cbr); + _CONVERT_(cbr_hq); + _CONVERT_(vbr_hq); + _CONVERT_(cbr_ld_hq); +#undef _CONVERT_ + return std::nullopt; +} + +int coder_from_view(const std::string_view &coder) { + if(coder == "auto"sv) return _auto; + if(coder == "cabac"sv || coder == "ac"sv) return cabac; + if(coder == "cavlc"sv || coder == "vlc"sv) return cavlc; + + return -1; +} +} + video_t video { 0, // crf 28, // qp @@ -103,6 +157,12 @@ video_t video { -1 }, // nv + { + amd::balanced, + std::nullopt, + -1 + }, // amd + {}, // encoder {}, // adapter_name {} // output_name @@ -357,8 +417,13 @@ void apply_config(std::unordered_map &&vars) { string_f(vars, "sw_preset", video.sw.preset); string_f(vars, "sw_tune", video.sw.tune); int_f(vars, "nv_preset", video.nv.preset, nv::preset_from_view); - int_f(vars, "nv_rc", video.nv.preset, nv::rc_from_view); + int_f(vars, "nv_rc", video.nv.rc, nv::rc_from_view); int_f(vars, "nv_coder", video.nv.coder, nv::coder_from_view); + + int_f(vars, "amd_quality", video.amd.quality, amd::quality_from_view); + int_f(vars, "amd_rc", video.amd.rc, amd::rc_from_view); + int_f(vars, "amd_coder", video.amd.coder, amd::coder_from_view); + string_f(vars, "encoder", video.encoder); string_f(vars, "adapter_name", video.adapter_name); string_f(vars, "output_name", video.output_name); diff --git a/sunshine/config.h b/sunshine/config.h index 9c14b1fe..f3beb5bd 100644 --- a/sunshine/config.h +++ b/sunshine/config.h @@ -26,6 +26,12 @@ struct video_t { int coder; } nv; + struct { + std::optional quality; + std::optional rc; + int coder; + } amd; + std::string encoder; std::string adapter_name; std::string output_name; diff --git a/sunshine/video.cpp b/sunshine/video.cpp index f32cd60f..1557adbd 100644 --- a/sunshine/video.cpp +++ b/sunshine/video.cpp @@ -58,6 +58,20 @@ enum class profile_hevc_e : int { }; } +namespace amd { + +enum class profile_h264_e : int { + main, + high, + constrained_baseline, + constrained_high, +}; + +enum class profile_hevc_e : int { + main, +}; +} + using ctx_t = util::safe_ptr; using frame_t = util::safe_ptr; using buffer_t = util::safe_ptr; @@ -70,6 +84,8 @@ platf::pix_fmt_e map_pix_fmt(AVPixelFormat fmt); void sw_img_to_frame(const platf::img_t &img, frame_t &frame); void nv_d3d_img_to_frame(const platf::img_t &img, frame_t &frame); util::Either nv_d3d_make_hwdevice_ctx(platf::hwdevice_t *hwdevice_ctx); +void amd_d3d_img_to_frame(const platf::img_t &img, frame_t &frame); +util::Either amd_d3d_make_hwdevice_ctx(platf::hwdevice_t *hwdevice_ctx); util::Either make_hwdevice_ctx(AVHWDeviceType type, void *hwdevice_ctx); int hwframe_ctx(ctx_t &ctx, buffer_t &hwdevice, AVPixelFormat format); @@ -284,6 +300,38 @@ static encoder_t nvenc { nv_d3d_img_to_frame, nv_d3d_make_hwdevice_ctx }; + +static encoder_t amdvce { + "amdvce"sv, + { (int)amd::profile_h264_e::high, (int)amd::profile_hevc_e::main }, + //AV_HWDEVICE_TYPE_D3D11VA, + //AV_PIX_FMT_NONE, + //AV_PIX_FMT_YUV420P, + AV_HWDEVICE_TYPE_D3D11VA, + AV_PIX_FMT_D3D11, + AV_PIX_FMT_NV12, AV_PIX_FMT_YUV420P, + { + { + { "quality"s, &config::video.amd.quality }, + { "rc"s, &config::video.amd.rc } + }, + std::nullopt, std::nullopt, + "hevc_amf"s, + }, + { + { + { "quality"s, &config::video.amd.quality }, + { "rc"s, &config::video.amd.rc } + }, + std::nullopt, std::make_optional({"qp"s, &config::video.qp}), + "h264_amf"s + }, + false, + true, + + amd_d3d_img_to_frame, + amd_d3d_make_hwdevice_ctx +}; #endif static encoder_t software { @@ -323,6 +371,7 @@ static encoder_t software { static std::vector encoders { #ifdef _WIN32 nvenc, + amdvce, #endif software }; @@ -1249,6 +1298,30 @@ void nv_d3d_img_to_frame(const platf::img_t &img, frame_t &frame) { frame->width = img.width; } +void amd_d3d_img_to_frame(const platf::img_t &img, frame_t &frame) { + if(img.data == frame->data[0]) { + return; + } + + // Need to have something refcounted + if(!frame->buf[0]) { + frame->buf[0] = av_buffer_allocz(sizeof(AVD3D11FrameDescriptor)); + } + + auto desc = (AVD3D11FrameDescriptor*)frame->buf[0]->data; + desc->texture = (ID3D11Texture2D*)img.data; + desc->index = 0; + + frame->data[0] = img.data; + frame->data[1] = 0; + + frame->linesize[0] = img.row_pitch; + + frame->height = img.height; + frame->width = img.width; +} + + util::Either nv_d3d_make_hwdevice_ctx(platf::hwdevice_t *hwdevice_ctx) { buffer_t ctx_buf { av_hwdevice_ctx_alloc(AV_HWDEVICE_TYPE_D3D11VA) }; auto ctx = (AVD3D11VADeviceContext*)((AVHWDeviceContext*)ctx_buf->data)->hwctx; @@ -1269,6 +1342,27 @@ util::Either nv_d3d_make_hwdevice_ctx(platf::hwdevice_t *hwdevice return ctx_buf; } + +util::Either amd_d3d_make_hwdevice_ctx(platf::hwdevice_t *hwdevice_ctx) { + buffer_t ctx_buf { av_hwdevice_ctx_alloc(AV_HWDEVICE_TYPE_D3D11VA) }; + auto ctx = (AVD3D11VADeviceContext*)((AVHWDeviceContext*)ctx_buf->data)->hwctx; + + std::fill_n((std::uint8_t*)ctx, sizeof(AVD3D11VADeviceContext), 0); + + auto device = (ID3D11Device*)hwdevice_ctx->data; + device->AddRef(); + ctx->device = device; + + auto err = av_hwdevice_ctx_init(ctx_buf.get()); + if(err) { + char err_str[AV_ERROR_MAX_STRING_SIZE] {0}; + BOOST_LOG(error) << "Failed to create FFMpeg amddech: "sv << av_make_error_string(err_str, AV_ERROR_MAX_STRING_SIZE, err); + + return err; + } + + return ctx_buf; +} #endif int start_capture_async(capture_thread_async_ctx_t &capture_thread_ctx) { From 0828cc3f83118d58dc1f118f0b5cfbfaa06675bd Mon Sep 17 00:00:00 2001 From: Elia Zammuto Date: Mon, 29 Mar 2021 13:16:56 +0200 Subject: [PATCH 04/10] Started work on AMD Hardware Decoding --- .gitmodules | 2 +- CMakeLists.txt | 1 + assets/sunshine.conf | 1 + pre-compiled | 2 +- 4 files changed, 4 insertions(+), 2 deletions(-) diff --git a/.gitmodules b/.gitmodules index 5938843f..db296a31 100644 --- a/.gitmodules +++ b/.gitmodules @@ -9,4 +9,4 @@ url = https://github.com/ViGEm/ViGEmClient [submodule "pre-compiled"] path = pre-compiled - url = https://bitbucket.org/Loki-47-6F-64/pre-compiled.git + url = https://github.com/TheElixZammuto/sunshine-prebuilt.git diff --git a/CMakeLists.txt b/CMakeLists.txt index 01e933ff..24c316a7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -32,6 +32,7 @@ if(WIN32) ${SUNSHINE_PREPARED_BINARIES}/lib/libswscale.a ${SUNSHINE_PREPARED_BINARIES}/lib/libx264.a ${SUNSHINE_PREPARED_BINARIES}/lib/libx265.a + ${SUNSHINE_PREPARED_BINARIES}/lib/libhdr10plus.a z lzma bcrypt C:/msys64/mingw64/lib/libiconv.a) endif() else() diff --git a/assets/sunshine.conf b/assets/sunshine.conf index 3fabb634..f887e45a 100644 --- a/assets/sunshine.conf +++ b/assets/sunshine.conf @@ -126,6 +126,7 @@ # Force a specific encoder, otherwise Sunshine will use the first encoder that is available # supported encoders: # nvenc +# amdvce # software # # encoder = nvenc diff --git a/pre-compiled b/pre-compiled index afd9a9bb..d1684dde 160000 --- a/pre-compiled +++ b/pre-compiled @@ -1 +1 @@ -Subproject commit afd9a9bbfc6ee1a064b0c1f9210bc20b2170c416 +Subproject commit d1684ddea51a9baee94fcef806686de6017e982b From 4daaa1f089a90ae17a7521d51ea126ffde9d38da Mon Sep 17 00:00:00 2001 From: Elia Zammuto Date: Wed, 31 Mar 2021 14:11:21 +0200 Subject: [PATCH 05/10] Added some keyframes --- pre-compiled | 2 +- sunshine/video.cpp | 12 +++++++++--- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/pre-compiled b/pre-compiled index d1684dde..5c1e48af 160000 --- a/pre-compiled +++ b/pre-compiled @@ -1 +1 @@ -Subproject commit d1684ddea51a9baee94fcef806686de6017e982b +Subproject commit 5c1e48af98de9ee415e5c102861eb8115a457204 diff --git a/sunshine/video.cpp b/sunshine/video.cpp index 1557adbd..97148360 100644 --- a/sunshine/video.cpp +++ b/sunshine/video.cpp @@ -321,9 +321,11 @@ static encoder_t amdvce { { { { "quality"s, &config::video.amd.quality }, - { "rc"s, &config::video.amd.rc } + { "rc"s, "1"s }, + {"log_to_dbg"s,"1"s}, + {"gops_per_idr","1"s} }, - std::nullopt, std::make_optional({"qp"s, &config::video.qp}), + std::nullopt, std::nullopt, "h264_amf"s }, false, @@ -769,7 +771,7 @@ void encode_run( if(idr_events->peek()) { session->frame->pict_type = AV_PICTURE_TYPE_I; - + session->frame->key_frame = 1; auto event = idr_events->pop(); if(!event) { return; @@ -781,6 +783,7 @@ void encode_run( } else if(frame_nr == key_frame_nr) { session->frame->pict_type = AV_PICTURE_TYPE_I; + session->frame->key_frame = 1; } std::this_thread::sleep_until(next_frame); @@ -919,6 +922,7 @@ encode_e encode_run_sync(std::vector> &synce if(ctx->idr_events->peek()) { pos->session.frame->pict_type = AV_PICTURE_TYPE_I; + pos->session.frame->key_frame = 1; auto event = ctx->idr_events->pop(); auto end = event->second; @@ -928,6 +932,7 @@ encode_e encode_run_sync(std::vector> &synce } else if(ctx->frame_nr == ctx->key_frame_nr) { pos->session.frame->pict_type = AV_PICTURE_TYPE_I; + pos->session.frame->key_frame = 1; } if(img_tmp) { @@ -1120,6 +1125,7 @@ bool validate_config(std::shared_ptr &disp, const encoder_t &e encoder.img_to_frame(*hwdevice->img, session->frame); session->frame->pict_type = AV_PICTURE_TYPE_I; + session->frame->key_frame = 1; auto packets = std::make_shared(30); if(encode(1, session->ctx, session->frame, packets, nullptr)) { From 99777c8e82702efc6466beddc41c9be4d5833cec Mon Sep 17 00:00:00 2001 From: Elia Zammuto Date: Thu, 1 Apr 2021 14:25:38 +0200 Subject: [PATCH 06/10] Added more params --- pre-compiled | 2 +- sunshine/video.cpp | 11 +++++------ 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/pre-compiled b/pre-compiled index 5c1e48af..36f68727 160000 --- a/pre-compiled +++ b/pre-compiled @@ -1 +1 @@ -Subproject commit 5c1e48af98de9ee415e5c102861eb8115a457204 +Subproject commit 36f687271239e25b2b7085f764194a61e2b9c605 diff --git a/sunshine/video.cpp b/sunshine/video.cpp index 97148360..5fb56a22 100644 --- a/sunshine/video.cpp +++ b/sunshine/video.cpp @@ -304,14 +304,14 @@ static encoder_t nvenc { static encoder_t amdvce { "amdvce"sv, { (int)amd::profile_h264_e::high, (int)amd::profile_hevc_e::main }, - //AV_HWDEVICE_TYPE_D3D11VA, - //AV_PIX_FMT_NONE, - //AV_PIX_FMT_YUV420P, AV_HWDEVICE_TYPE_D3D11VA, AV_PIX_FMT_D3D11, AV_PIX_FMT_NV12, AV_PIX_FMT_YUV420P, { { + { "header_insertion_mode"s, "idr"s }, + { "gops_per_idr"s, 30 }, + { "usage"s, "ultralowlatency"s }, { "quality"s, &config::video.amd.quality }, { "rc"s, &config::video.amd.rc } }, @@ -320,10 +320,10 @@ static encoder_t amdvce { }, { { + { "usage"s, "ultralowlatency"s }, { "quality"s, &config::video.amd.quality }, - { "rc"s, "1"s }, + { "rc"s, &config::video.amd.rc }, {"log_to_dbg"s,"1"s}, - {"gops_per_idr","1"s} }, std::nullopt, std::nullopt, "h264_amf"s @@ -1125,7 +1125,6 @@ bool validate_config(std::shared_ptr &disp, const encoder_t &e encoder.img_to_frame(*hwdevice->img, session->frame); session->frame->pict_type = AV_PICTURE_TYPE_I; - session->frame->key_frame = 1; auto packets = std::make_shared(30); if(encode(1, session->ctx, session->frame, packets, nullptr)) { From bb5b003dd572ae80701892f4e97eda4aada0f90a Mon Sep 17 00:00:00 2001 From: Elia Zammuto Date: Thu, 1 Apr 2021 20:27:59 +0200 Subject: [PATCH 07/10] Disabled key frames when not needed --- sunshine/video.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/sunshine/video.cpp b/sunshine/video.cpp index 5fb56a22..90e1ded5 100644 --- a/sunshine/video.cpp +++ b/sunshine/video.cpp @@ -315,7 +315,7 @@ static encoder_t amdvce { { "quality"s, &config::video.amd.quality }, { "rc"s, &config::video.amd.rc } }, - std::nullopt, std::nullopt, + std::nullopt, std::make_optional({"qp"s, &config::video.qp}), "hevc_amf"s, }, { @@ -325,7 +325,7 @@ static encoder_t amdvce { { "rc"s, &config::video.amd.rc }, {"log_to_dbg"s,"1"s}, }, - std::nullopt, std::nullopt, + std::nullopt, std::make_optional({"qp"s, &config::video.qp}), "h264_amf"s }, false, @@ -810,6 +810,7 @@ void encode_run( } session->frame->pict_type = AV_PICTURE_TYPE_NONE; + session->frame->key_frame = 0; } } @@ -971,6 +972,7 @@ encode_e encode_run_sync(std::vector> &synce } pos->session.frame->pict_type = AV_PICTURE_TYPE_NONE; + pos->session.frame->key_frame = 0; ++pos; }) From 6112c81db7ba3102aa04fe38bec382ee5c495d93 Mon Sep 17 00:00:00 2001 From: loki Date: Sat, 24 Apr 2021 12:07:26 +0200 Subject: [PATCH 08/10] =?UTF-8?q?Fix=20=C2=96undefined=20reference=20to=20?= =?UTF-8?q?=5F=5Fmemcpy=5Fchk=20when=20building=20on=20msys64?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index 01e933ff..554344b3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -69,6 +69,7 @@ if(WIN32) ViGEmClient/include/ViGEm/Util.h ViGEmClient/include/ViGEm/km/BusShared.h) list(PREPEND PLATFORM_LIBRARIES + ssp winmm ksuser wsock32 From 0cfb440cf683f9479bb279ab1e91dbea5e02dfdc Mon Sep 17 00:00:00 2001 From: loki Date: Sat, 24 Apr 2021 14:23:12 +0200 Subject: [PATCH 09/10] Added config examples to the config file --- assets/sunshine.conf | 27 ++++++++++++++++++++++++++- sunshine/video.cpp | 4 +++- 2 files changed, 29 insertions(+), 2 deletions(-) diff --git a/assets/sunshine.conf b/assets/sunshine.conf index f887e45a..08b1b209 100644 --- a/assets/sunshine.conf +++ b/assets/sunshine.conf @@ -126,7 +126,7 @@ # Force a specific encoder, otherwise Sunshine will use the first encoder that is available # supported encoders: # nvenc -# amdvce +# amdvce # NOTE: alpha stage. The cursor is not yet displayed # software # # encoder = nvenc @@ -171,6 +171,31 @@ ########################## # nv_coder = auto +##################################### AMD ##################################### +###### presets ########### +# default +# speed +# balanced +########################## +# amd_preset = balanced +# +####### rate control ##### +# auto -- let ffmpeg decide rate control +# constqp -- constant QP mode +# vbr -- variable bitrate +# cbr -- constant bitrate +# cbr_hq -- cbr high quality +# cbr_ld_hq -- cbr low delay high quality +# vbr_hq -- vbr high quality +########################## +# amd_rc = auto + +###### h264 entropy ###### +# auto -- let ffmpeg nvenc decide the entropy encoding +# cabac +# cavlc +########################## +# amd_coder = auto ############################################## # Some configurable parameters, are merely toggles for specific features diff --git a/sunshine/video.cpp b/sunshine/video.cpp index 90e1ded5..d5ba02ed 100644 --- a/sunshine/video.cpp +++ b/sunshine/video.cpp @@ -373,9 +373,11 @@ static encoder_t software { static std::vector encoders { #ifdef _WIN32 nvenc, +#endif + software, +#ifdef _WIN32 amdvce, #endif - software }; void reset_display(std::shared_ptr &disp, AVHWDeviceType type) { From 438ae6a7615d1b9731d04dfef80f0b3ff4907fd7 Mon Sep 17 00:00:00 2001 From: loki Date: Sat, 24 Apr 2021 15:53:48 +0200 Subject: [PATCH 10/10] Don't stop streaming when UAC is running --- sunshine/platform/windows/display_base.cpp | 2 -- sunshine/video.cpp | 20 ++++++++++++++++++-- 2 files changed, 18 insertions(+), 4 deletions(-) diff --git a/sunshine/platform/windows/display_base.cpp b/sunshine/platform/windows/display_base.cpp index c510b044..dbddf29a 100644 --- a/sunshine/platform/windows/display_base.cpp +++ b/sunshine/platform/windows/display_base.cpp @@ -150,8 +150,6 @@ int display_base_t::init() { } D3D_FEATURE_LEVEL featureLevels[] { - D3D_FEATURE_LEVEL_12_1, - D3D_FEATURE_LEVEL_12_0, D3D_FEATURE_LEVEL_11_1, D3D_FEATURE_LEVEL_11_0, D3D_FEATURE_LEVEL_10_1, diff --git a/sunshine/video.cpp b/sunshine/video.cpp index d5ba02ed..b2e23855 100644 --- a/sunshine/video.cpp +++ b/sunshine/video.cpp @@ -469,7 +469,14 @@ void captureThread( std::this_thread::sleep_for(100ms); } - reset_display(disp, encoder.dev_type); + while(capture_ctx_queue->running()) { + reset_display(disp, encoder.dev_type); + + if(disp) { + break; + } + std::this_thread::sleep_for(200ms); + } if(!disp) { return; } @@ -846,7 +853,16 @@ encode_e encode_run_sync(std::vector> &synce const auto &encoder = encoders.front(); std::shared_ptr disp; - reset_display(disp, encoder.dev_type); + + while(encode_session_ctx_queue.running()) { + reset_display(disp, encoder.dev_type); + if(disp) { + break; + } + + std::this_thread::sleep_for(200ms); + } + if(!disp) { return encode_e::error; }