HDR prep work (#808)
This commit is contained in:
@@ -10,7 +10,7 @@
|
||||
#include <d3dcommon.h>
|
||||
#include <dwmapi.h>
|
||||
#include <dxgi.h>
|
||||
#include <dxgi1_2.h>
|
||||
#include <dxgi1_6.h>
|
||||
|
||||
#include "src/platform/common.h"
|
||||
#include "src/utility.h"
|
||||
@@ -37,6 +37,7 @@ using adapter_t = util::safe_ptr<IDXGIAdapter1, Release<IDXGIAdapter
|
||||
using output_t = util::safe_ptr<IDXGIOutput, Release<IDXGIOutput>>;
|
||||
using output1_t = util::safe_ptr<IDXGIOutput1, Release<IDXGIOutput1>>;
|
||||
using output5_t = util::safe_ptr<IDXGIOutput5, Release<IDXGIOutput5>>;
|
||||
using output6_t = util::safe_ptr<IDXGIOutput6, Release<IDXGIOutput6>>;
|
||||
using dup_t = util::safe_ptr<IDXGIOutputDuplication, Release<IDXGIOutputDuplication>>;
|
||||
using texture2d_t = util::safe_ptr<ID3D11Texture2D, Release<ID3D11Texture2D>>;
|
||||
using texture1d_t = util::safe_ptr<ID3D11Texture1D, Release<ID3D11Texture1D>>;
|
||||
@@ -115,7 +116,7 @@ public:
|
||||
|
||||
class display_base_t : public display_t {
|
||||
public:
|
||||
int init(int framerate, const std::string &display_name);
|
||||
int init(const ::video::config_t &config, const std::string &display_name);
|
||||
capture_e capture(snapshot_cb_t &&snapshot_cb, std::shared_ptr<img_t> img, bool *cursor) override;
|
||||
|
||||
std::chrono::nanoseconds delay;
|
||||
@@ -141,6 +142,9 @@ public:
|
||||
|
||||
typedef NTSTATUS WINAPI (*PD3DKMTSetProcessSchedulingPriorityClass)(HANDLE, D3DKMT_SCHEDULINGPRIORITYCLASS);
|
||||
|
||||
virtual bool is_hdr() override;
|
||||
virtual bool get_hdr_metadata(SS_HDR_METADATA &metadata) override;
|
||||
|
||||
protected:
|
||||
int get_pixel_pitch() {
|
||||
return (capture_format == DXGI_FORMAT_R16G16B16A16_FLOAT) ? 8 : 4;
|
||||
@@ -151,6 +155,7 @@ protected:
|
||||
virtual capture_e snapshot(img_t *img, std::chrono::milliseconds timeout, bool cursor_visible) = 0;
|
||||
virtual int complete_img(img_t *img, bool dummy) = 0;
|
||||
virtual std::vector<DXGI_FORMAT> get_supported_sdr_capture_formats() = 0;
|
||||
virtual std::vector<DXGI_FORMAT> get_supported_hdr_capture_formats() = 0;
|
||||
};
|
||||
|
||||
class display_ram_t : public display_base_t {
|
||||
@@ -161,8 +166,9 @@ public:
|
||||
int dummy_img(img_t *img) override;
|
||||
int complete_img(img_t *img, bool dummy) override;
|
||||
std::vector<DXGI_FORMAT> get_supported_sdr_capture_formats() override;
|
||||
std::vector<DXGI_FORMAT> get_supported_hdr_capture_formats() override;
|
||||
|
||||
int init(int framerate, const std::string &display_name);
|
||||
int init(const ::video::config_t &config, const std::string &display_name);
|
||||
|
||||
cursor_t cursor;
|
||||
D3D11_MAPPED_SUBRESOURCE img_info;
|
||||
@@ -177,8 +183,9 @@ public:
|
||||
int dummy_img(img_t *img_base) override;
|
||||
int complete_img(img_t *img_base, bool dummy) override;
|
||||
std::vector<DXGI_FORMAT> get_supported_sdr_capture_formats() override;
|
||||
std::vector<DXGI_FORMAT> get_supported_hdr_capture_formats() override;
|
||||
|
||||
int init(int framerate, const std::string &display_name);
|
||||
int init(const ::video::config_t &config, const std::string &display_name);
|
||||
|
||||
std::shared_ptr<platf::hwdevice_t> make_hwdevice(pix_fmt_e pix_fmt) override;
|
||||
|
||||
|
||||
@@ -17,6 +17,7 @@ typedef long NTSTATUS;
|
||||
#include "src/config.h"
|
||||
#include "src/main.h"
|
||||
#include "src/platform/common.h"
|
||||
#include "src/video.h"
|
||||
|
||||
namespace platf {
|
||||
using namespace std::literals;
|
||||
@@ -106,10 +107,16 @@ capture_e display_base_t::capture(snapshot_cb_t &&snapshot_cb, std::shared_ptr<:
|
||||
});
|
||||
|
||||
while(img) {
|
||||
auto wait_time_us = std::chrono::duration_cast<std::chrono::microseconds>(next_frame - std::chrono::steady_clock::now()).count();
|
||||
// This will return false if the HDR state changes or for any number of other
|
||||
// display or GPU changes. We should reinit to examine the updated state of
|
||||
// the display subsystem. It is recommended to call this once per frame.
|
||||
if(!factory->IsCurrent()) {
|
||||
return platf::capture_e::reinit;
|
||||
}
|
||||
|
||||
// If the wait time is between 1 us and 1 second, wait the specified time
|
||||
// and offset the next frame time from the exact current frame time target.
|
||||
auto wait_time_us = std::chrono::duration_cast<std::chrono::microseconds>(next_frame - std::chrono::steady_clock::now()).count();
|
||||
if(wait_time_us > 0 && wait_time_us < 1000000) {
|
||||
LARGE_INTEGER due_time { .QuadPart = -10LL * wait_time_us };
|
||||
SetWaitableTimer(timer, &due_time, 0, nullptr, nullptr, false);
|
||||
@@ -276,7 +283,7 @@ bool test_dxgi_duplication(adapter_t &adapter, output_t &output) {
|
||||
return false;
|
||||
}
|
||||
|
||||
int display_base_t::init(int framerate, const std::string &display_name) {
|
||||
int display_base_t::init(const ::video::config_t &config, const std::string &display_name) {
|
||||
std::once_flag windows_cpp_once_flag;
|
||||
|
||||
std::call_once(windows_cpp_once_flag, []() {
|
||||
@@ -296,7 +303,7 @@ int display_base_t::init(int framerate, const std::string &display_name) {
|
||||
// Ensure we can duplicate the current display
|
||||
syncThreadDesktop();
|
||||
|
||||
delay = std::chrono::nanoseconds { 1s } / framerate;
|
||||
delay = std::chrono::nanoseconds { 1s } / config.framerate;
|
||||
|
||||
// Get rectangle of full desktop for absolute mouse coordinates
|
||||
env_width = GetSystemMetrics(SM_CXVIRTUALSCREEN);
|
||||
@@ -421,7 +428,7 @@ int display_base_t::init(int framerate, const std::string &display_name) {
|
||||
<< "Virtual Desktop : "sv << env_width << 'x' << env_height;
|
||||
|
||||
// Enable DwmFlush() only if the current refresh rate can match the client framerate.
|
||||
auto refresh_rate = framerate;
|
||||
auto refresh_rate = config.framerate;
|
||||
DWM_TIMING_INFO timing_info;
|
||||
timing_info.cbSize = sizeof(timing_info);
|
||||
|
||||
@@ -433,7 +440,7 @@ int display_base_t::init(int framerate, const std::string &display_name) {
|
||||
refresh_rate = std::round((double)timing_info.rateRefresh.uiNumerator / (double)timing_info.rateRefresh.uiDenominator);
|
||||
}
|
||||
|
||||
dup.use_dwmflush = config::video.dwmflush && !(framerate > refresh_rate) ? true : false;
|
||||
dup.use_dwmflush = config::video.dwmflush && !(config.framerate > refresh_rate) ? true : false;
|
||||
|
||||
// Bump up thread priority
|
||||
{
|
||||
@@ -502,7 +509,7 @@ int display_base_t::init(int framerate, const std::string &display_name) {
|
||||
status = output->QueryInterface(IID_IDXGIOutput5, (void **)&output5);
|
||||
if(SUCCEEDED(status)) {
|
||||
// Ask the display implementation which formats it supports
|
||||
auto supported_formats = get_supported_sdr_capture_formats();
|
||||
auto supported_formats = config.dynamicRange ? get_supported_hdr_capture_formats() : get_supported_sdr_capture_formats();
|
||||
if(supported_formats.empty()) {
|
||||
BOOST_LOG(warning) << "No compatible capture formats for this encoder"sv;
|
||||
return -1;
|
||||
@@ -562,6 +569,57 @@ int display_base_t::init(int framerate, const std::string &display_name) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool display_base_t::is_hdr() {
|
||||
dxgi::output6_t output6 {};
|
||||
|
||||
auto status = output->QueryInterface(IID_IDXGIOutput6, (void **)&output6);
|
||||
if(FAILED(status)) {
|
||||
BOOST_LOG(warning) << "Failed to query IDXGIOutput6 from the output"sv;
|
||||
return false;
|
||||
}
|
||||
|
||||
DXGI_OUTPUT_DESC1 desc1;
|
||||
output6->GetDesc1(&desc1);
|
||||
|
||||
return desc1.ColorSpace == DXGI_COLOR_SPACE_RGB_FULL_G2084_NONE_P2020;
|
||||
}
|
||||
|
||||
bool display_base_t::get_hdr_metadata(SS_HDR_METADATA &metadata) {
|
||||
dxgi::output6_t output6 {};
|
||||
|
||||
std::memset(&metadata, 0, sizeof(metadata));
|
||||
|
||||
auto status = output->QueryInterface(IID_IDXGIOutput6, (void **)&output6);
|
||||
if(FAILED(status)) {
|
||||
BOOST_LOG(warning) << "Failed to query IDXGIOutput6 from the output"sv;
|
||||
return false;
|
||||
}
|
||||
|
||||
DXGI_OUTPUT_DESC1 desc1;
|
||||
output6->GetDesc1(&desc1);
|
||||
|
||||
metadata.displayPrimaries[0].x = desc1.RedPrimary[0] * 50000;
|
||||
metadata.displayPrimaries[0].y = desc1.RedPrimary[1] * 50000;
|
||||
metadata.displayPrimaries[1].x = desc1.GreenPrimary[0] * 50000;
|
||||
metadata.displayPrimaries[1].y = desc1.GreenPrimary[1] * 50000;
|
||||
metadata.displayPrimaries[2].x = desc1.BluePrimary[0] * 50000;
|
||||
metadata.displayPrimaries[2].y = desc1.BluePrimary[1] * 50000;
|
||||
|
||||
metadata.whitePoint.x = desc1.WhitePoint[0] * 50000;
|
||||
metadata.whitePoint.y = desc1.WhitePoint[1] * 50000;
|
||||
|
||||
metadata.maxDisplayLuminance = desc1.MaxLuminance;
|
||||
metadata.minDisplayLuminance = desc1.MinLuminance * 10000;
|
||||
|
||||
// These are content-specific metadata parameters that this interface doesn't give us
|
||||
metadata.maxContentLightLevel = 0;
|
||||
metadata.maxFrameAverageLightLevel = 0;
|
||||
|
||||
metadata.maxFullFrameLuminance = desc1.MaxFullFrameLuminance;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
const char *format_str[] = {
|
||||
"DXGI_FORMAT_UNKNOWN",
|
||||
"DXGI_FORMAT_R32G32B32A32_TYPELESS",
|
||||
@@ -694,18 +752,18 @@ const char *display_base_t::dxgi_format_to_string(DXGI_FORMAT format) {
|
||||
} // namespace platf::dxgi
|
||||
|
||||
namespace platf {
|
||||
std::shared_ptr<display_t> display(mem_type_e hwdevice_type, const std::string &display_name, int framerate) {
|
||||
std::shared_ptr<display_t> display(mem_type_e hwdevice_type, const std::string &display_name, const video::config_t &config) {
|
||||
if(hwdevice_type == mem_type_e::dxgi) {
|
||||
auto disp = std::make_shared<dxgi::display_vram_t>();
|
||||
|
||||
if(!disp->init(framerate, display_name)) {
|
||||
if(!disp->init(config, display_name)) {
|
||||
return disp;
|
||||
}
|
||||
}
|
||||
else if(hwdevice_type == mem_type_e::system) {
|
||||
auto disp = std::make_shared<dxgi::display_ram_t>();
|
||||
|
||||
if(!disp->init(framerate, display_name)) {
|
||||
if(!disp->init(config, display_name)) {
|
||||
return disp;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -349,11 +349,16 @@ int display_ram_t::dummy_img(platf::img_t *img) {
|
||||
}
|
||||
|
||||
std::vector<DXGI_FORMAT> display_ram_t::get_supported_sdr_capture_formats() {
|
||||
return std::vector { DXGI_FORMAT_B8G8R8A8_UNORM };
|
||||
return { DXGI_FORMAT_B8G8R8A8_UNORM };
|
||||
}
|
||||
|
||||
int display_ram_t::init(int framerate, const std::string &display_name) {
|
||||
if(display_base_t::init(framerate, display_name)) {
|
||||
std::vector<DXGI_FORMAT> display_ram_t::get_supported_hdr_capture_formats() {
|
||||
// HDR is unsupported
|
||||
return {};
|
||||
}
|
||||
|
||||
int display_ram_t::init(const ::video::config_t &config, const std::string &display_name) {
|
||||
if(display_base_t::init(config, display_name)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
@@ -952,8 +952,8 @@ capture_e display_vram_t::snapshot(platf::img_t *img_base, std::chrono::millisec
|
||||
return capture_e::ok;
|
||||
}
|
||||
|
||||
int display_vram_t::init(int framerate, const std::string &display_name) {
|
||||
if(display_base_t::init(framerate, display_name)) {
|
||||
int display_vram_t::init(const ::video::config_t &config, const std::string &display_name) {
|
||||
if(display_base_t::init(config, display_name)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -1104,7 +1104,11 @@ int display_vram_t::dummy_img(platf::img_t *img_base) {
|
||||
}
|
||||
|
||||
std::vector<DXGI_FORMAT> display_vram_t::get_supported_sdr_capture_formats() {
|
||||
return std::vector { DXGI_FORMAT_B8G8R8A8_UNORM, DXGI_FORMAT_R8G8B8A8_UNORM };
|
||||
return { DXGI_FORMAT_B8G8R8A8_UNORM, DXGI_FORMAT_R8G8B8A8_UNORM };
|
||||
}
|
||||
|
||||
std::vector<DXGI_FORMAT> display_vram_t::get_supported_hdr_capture_formats() {
|
||||
return { DXGI_FORMAT_R10G10B10A2_UNORM };
|
||||
}
|
||||
|
||||
std::shared_ptr<platf::hwdevice_t> display_vram_t::make_hwdevice(pix_fmt_e pix_fmt) {
|
||||
|
||||
Reference in New Issue
Block a user