0
0
mirror of https://github.com/obsproject/obs-studio.git synced 2024-09-19 20:32:15 +02:00

Merge pull request #7978 from jpark37/dxgi-display-sdr-on-hdr

libobs-d3d11,win-capture: Add Force SDR for DXGI duplicator
This commit is contained in:
Jim 2023-03-20 01:43:14 -07:00 committed by GitHub
commit e9ef38e3d3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 158 additions and 90 deletions

View File

@ -45,6 +45,8 @@ void gs_duplicator::Start()
throw "Invalid monitor index";
hr = output->QueryInterface(IID_PPV_ARGS(output5.Assign()));
hdr = false;
sdr_white_nits = 80.f;
if (SUCCEEDED(hr)) {
constexpr DXGI_FORMAT supportedFormats[]{
DXGI_FORMAT_R16G16B16A16_FLOAT,
@ -56,6 +58,13 @@ void gs_duplicator::Start()
duplicator.Assign());
if (FAILED(hr))
throw HRError("Failed to DuplicateOutput1", hr);
DXGI_OUTPUT_DESC desc;
if (SUCCEEDED(output->GetDesc(&desc))) {
gs_monitor_color_info info =
device->GetMonitorColorInfo(desc.Monitor);
hdr = info.hdr;
sdr_white_nits = (float)info.sdr_white_nits;
}
} else {
hr = output->QueryInterface(IID_PPV_ARGS(output1.Assign()));
if (FAILED(hr))
@ -238,6 +247,11 @@ static inline void copy_texture(gs_duplicator_t *d, ID3D11Texture2D *tex)
delete d->texture;
d->texture = (gs_texture_2d *)gs_texture_create(
desc.Width, desc.Height, general_format, 1, nullptr, 0);
d->color_space = d->hdr ? GS_CS_709_SCRGB
: ((desc.Format ==
DXGI_FORMAT_R16G16B16A16_FLOAT)
? GS_CS_SRGB_16F
: GS_CS_SRGB);
}
if (d->texture)
@ -294,4 +308,15 @@ EXPORT gs_texture_t *gs_duplicator_get_texture(gs_duplicator_t *duplicator)
{
return duplicator->texture;
}
EXPORT enum gs_color_space
gs_duplicator_get_color_space(gs_duplicator_t *duplicator)
{
return duplicator->color_space;
}
EXPORT float gs_duplicator_get_sdr_white_level(gs_duplicator_t *duplicator)
{
return duplicator->sdr_white_nits;
}
}

View File

@ -67,53 +67,6 @@ gs_obj::~gs_obj()
next->prev_next = prev_next;
}
static gs_monitor_color_info get_monitor_color_info(gs_device_t *device,
HMONITOR hMonitor)
{
IDXGIFactory1 *factory1 = device->factory;
if (!factory1->IsCurrent()) {
device->InitFactory();
factory1 = device->factory;
device->monitor_to_hdr.clear();
}
for (const std::pair<HMONITOR, gs_monitor_color_info> &pair :
device->monitor_to_hdr) {
if (pair.first == hMonitor)
return pair.second;
}
ComPtr<IDXGIAdapter> adapter;
ComPtr<IDXGIOutput> output;
ComPtr<IDXGIOutput6> output6;
for (UINT adapterIndex = 0;
SUCCEEDED(factory1->EnumAdapters(adapterIndex, &adapter));
++adapterIndex) {
for (UINT outputIndex = 0;
SUCCEEDED(adapter->EnumOutputs(outputIndex, &output));
++outputIndex) {
if (SUCCEEDED(output->QueryInterface(&output6))) {
DXGI_OUTPUT_DESC1 desc1;
if (SUCCEEDED(output6->GetDesc1(&desc1)) &&
(desc1.Monitor == hMonitor)) {
const bool hdr =
desc1.ColorSpace ==
DXGI_COLOR_SPACE_RGB_FULL_G2084_NONE_P2020;
return device->monitor_to_hdr
.emplace_back(
hMonitor,
gs_monitor_color_info(
hdr,
desc1.BitsPerColor))
.second;
}
}
}
}
return gs_monitor_color_info(false, 8);
}
static enum gs_color_space get_next_space(gs_device_t *device, HWND hwnd,
DXGI_SWAP_EFFECT effect)
{
@ -123,7 +76,7 @@ static enum gs_color_space get_next_space(gs_device_t *device, HWND hwnd,
MonitorFromWindow(hwnd, MONITOR_DEFAULTTONEAREST);
if (hMonitor) {
const gs_monitor_color_info info =
get_monitor_color_info(device, hMonitor);
device->GetMonitorColorInfo(hMonitor);
if (info.hdr)
next_space = GS_CS_709_SCRGB;
else if (info.bits_per_color > 8)
@ -1170,9 +1123,9 @@ static HRESULT GetPathInfo(HMONITOR hMonitor,
return hr;
}
static ULONG GetSdrWhiteNits(HMONITOR monitor)
static ULONG GetSdrMaxNits(HMONITOR monitor)
{
ULONG nits = 0;
ULONG nits = 80;
DISPLAYCONFIG_PATH_INFO info;
if (SUCCEEDED(GetPathInfo(monitor, &info))) {
@ -1192,6 +1145,51 @@ static ULONG GetSdrWhiteNits(HMONITOR monitor)
return nits;
}
gs_monitor_color_info gs_device::GetMonitorColorInfo(HMONITOR hMonitor)
{
IDXGIFactory1 *factory1 = factory;
if (!factory1->IsCurrent()) {
InitFactory();
factory1 = factory;
monitor_to_hdr.clear();
}
for (const std::pair<HMONITOR, gs_monitor_color_info> &pair :
monitor_to_hdr) {
if (pair.first == hMonitor)
return pair.second;
}
ComPtr<IDXGIAdapter> adapter;
ComPtr<IDXGIOutput> output;
ComPtr<IDXGIOutput6> output6;
for (UINT adapterIndex = 0;
SUCCEEDED(factory1->EnumAdapters(adapterIndex, &adapter));
++adapterIndex) {
for (UINT outputIndex = 0;
SUCCEEDED(adapter->EnumOutputs(outputIndex, &output));
++outputIndex) {
DXGI_OUTPUT_DESC1 desc1;
if (SUCCEEDED(output->QueryInterface(&output6)) &&
SUCCEEDED(output6->GetDesc1(&desc1)) &&
(desc1.Monitor == hMonitor)) {
const bool hdr =
desc1.ColorSpace ==
DXGI_COLOR_SPACE_RGB_FULL_G2084_NONE_P2020;
const UINT bits = desc1.BitsPerColor;
const ULONG nits = GetSdrMaxNits(desc1.Monitor);
return monitor_to_hdr
.emplace_back(hMonitor,
gs_monitor_color_info(
hdr, bits, nits))
.second;
}
}
}
return gs_monitor_color_info(false, 8, 80);
}
static void PopulateMonitorIds(HMONITOR handle, char *id, char *alt_id,
size_t capacity)
{
@ -1286,7 +1284,7 @@ static inline void LogAdapterMonitors(IDXGIAdapter1 *adapter)
}
const RECT &rect = desc.DesktopCoordinates;
const ULONG nits = GetSdrWhiteNits(desc.Monitor);
const ULONG nits = GetSdrMaxNits(desc.Monitor);
char *friendly_name;
os_wcs_to_utf8_ptr(target.monitorFriendlyDeviceName, 0,
@ -2098,10 +2096,9 @@ bool device_framebuffer_srgb_enabled(gs_device_t *device)
return device->curFramebufferSrgb;
}
inline void gs_device::CopyTex(ID3D11Texture2D *dst, uint32_t dst_x,
uint32_t dst_y, gs_texture_t *src,
uint32_t src_x, uint32_t src_y, uint32_t src_w,
uint32_t src_h)
void gs_device::CopyTex(ID3D11Texture2D *dst, uint32_t dst_x, uint32_t dst_y,
gs_texture_t *src, uint32_t src_x, uint32_t src_y,
uint32_t src_w, uint32_t src_h)
{
if (src->type != GS_TEXTURE_2D)
throw "Source texture must be a 2D texture";
@ -3090,7 +3087,7 @@ extern "C" EXPORT bool device_p010_available(gs_device_t *device)
extern "C" EXPORT bool device_is_monitor_hdr(gs_device_t *device, void *monitor)
{
const HMONITOR hMonitor = static_cast<HMONITOR>(monitor);
return get_monitor_color_info(device, hMonitor).hdr;
return device->GetMonitorColorInfo(hMonitor).hdr;
}
extern "C" EXPORT void device_debug_marker_begin(gs_device_t *,

View File

@ -779,6 +779,9 @@ struct gs_vertex_shader : gs_shader {
struct gs_duplicator : gs_obj {
ComPtr<IDXGIOutputDuplication> duplicator;
gs_texture_2d *texture;
bool hdr = false;
enum gs_color_space color_space = GS_CS_SRGB;
float sdr_white_nits = 80.f;
int idx;
long refs;
bool updated;
@ -982,9 +985,13 @@ struct mat4float {
struct gs_monitor_color_info {
bool hdr;
UINT bits_per_color;
ULONG sdr_white_nits;
gs_monitor_color_info(bool hdr, int bits_per_color)
: hdr(hdr), bits_per_color(bits_per_color)
gs_monitor_color_info(bool hdr, int bits_per_color,
ULONG sdr_white_nits)
: hdr(hdr),
bits_per_color(bits_per_color),
sdr_white_nits(sdr_white_nits)
{
}
};
@ -1061,9 +1068,9 @@ struct gs_device {
void LoadVertexBufferData();
inline void CopyTex(ID3D11Texture2D *dst, uint32_t dst_x,
uint32_t dst_y, gs_texture_t *src, uint32_t src_x,
uint32_t src_y, uint32_t src_w, uint32_t src_h);
void CopyTex(ID3D11Texture2D *dst, uint32_t dst_x, uint32_t dst_y,
gs_texture_t *src, uint32_t src_x, uint32_t src_y,
uint32_t src_w, uint32_t src_h);
void UpdateViewProjMatrix();
@ -1073,6 +1080,8 @@ struct gs_device {
bool HasBadNV12Output();
gs_monitor_color_info GetMonitorColorInfo(HMONITOR hMonitor);
gs_device(uint32_t adapterIdx);
~gs_device();
};

View File

@ -218,6 +218,8 @@ bool load_graphics_imports(struct gs_exports *exports, void *module,
GRAPHICS_IMPORT_OPTIONAL(gs_duplicator_destroy);
GRAPHICS_IMPORT_OPTIONAL(gs_duplicator_update_frame);
GRAPHICS_IMPORT_OPTIONAL(gs_duplicator_get_texture);
GRAPHICS_IMPORT_OPTIONAL(gs_duplicator_get_color_space);
GRAPHICS_IMPORT_OPTIONAL(gs_duplicator_get_sdr_white_level);
GRAPHICS_IMPORT_OPTIONAL(gs_get_adapter_count);
GRAPHICS_IMPORT_OPTIONAL(device_texture_create_gdi);
GRAPHICS_IMPORT_OPTIONAL(gs_texture_get_dc);

View File

@ -307,6 +307,9 @@ struct gs_exports {
bool (*gs_duplicator_update_frame)(gs_duplicator_t *duplicator);
gs_texture_t *(*gs_duplicator_get_texture)(gs_duplicator_t *duplicator);
enum gs_color_space (*gs_duplicator_get_color_space)(
gs_duplicator_t *duplicator);
float (*gs_duplicator_get_sdr_white_level)(gs_duplicator_t *duplicator);
uint32_t (*gs_get_adapter_count)(void);

View File

@ -3050,6 +3050,28 @@ gs_texture_t *gs_duplicator_get_texture(gs_duplicator_t *duplicator)
return thread_graphics->exports.gs_duplicator_get_texture(duplicator);
}
enum gs_color_space gs_duplicator_get_color_space(gs_duplicator_t *duplicator)
{
if (!gs_valid_p("gs_duplicator_get_color_space", duplicator))
return GS_CS_SRGB;
if (!thread_graphics->exports.gs_duplicator_get_color_space)
return GS_CS_SRGB;
return thread_graphics->exports.gs_duplicator_get_color_space(
duplicator);
}
float gs_duplicator_get_sdr_white_level(gs_duplicator_t *duplicator)
{
if (!gs_valid_p("gs_duplicator_get_sdr_white_level", duplicator))
return 80.f;
if (!thread_graphics->exports.gs_duplicator_get_sdr_white_level)
return 80.f;
return thread_graphics->exports.gs_duplicator_get_sdr_white_level(
duplicator);
}
/** creates a windows GDI-lockable texture */
gs_texture_t *gs_texture_create_gdi(uint32_t width, uint32_t height)
{

View File

@ -919,6 +919,9 @@ EXPORT void gs_duplicator_destroy(gs_duplicator_t *duplicator);
EXPORT bool gs_duplicator_update_frame(gs_duplicator_t *duplicator);
EXPORT gs_texture_t *gs_duplicator_get_texture(gs_duplicator_t *duplicator);
EXPORT enum gs_color_space
gs_duplicator_get_color_space(gs_duplicator_t *duplicator);
EXPORT float gs_duplicator_get_sdr_white_level(gs_duplicator_t *duplicator);
EXPORT uint32_t gs_get_adapter_count(void);

View File

@ -265,10 +265,11 @@ static void log_settings(struct duplicator_capture *capture,
"\tmethod: %s\n"
"\tid: %s\n"
"\talt_id: %s\n"
"\tsetting_id: %s",
"\tsetting_id: %s\n"
"\tforce SDR: %s",
monitor, width, height, capture->capture_cursor ? "true" : "false",
get_method_name(capture->method), capture->id, capture->alt_id,
capture->monitor_id);
capture->monitor_id, capture->force_sdr ? "true" : "false");
}
static enum display_capture_method
@ -734,18 +735,32 @@ static void duplicator_capture_render(void *data, gs_effect_t *unused)
const char *tech_name = "Draw";
float multiplier = 1.f;
const enum gs_color_space current_space = gs_get_color_space();
if (gs_texture_get_color_format(texture) == GS_RGBA16F) {
switch (current_space) {
case GS_CS_SRGB:
case GS_CS_SRGB_16F:
tech_name = "DrawMultiplyTonemap";
multiplier =
80.f / obs_get_video_sdr_white_level();
break;
case GS_CS_709_EXTENDED:
if (gs_duplicator_get_color_space(capture->duplicator) ==
GS_CS_709_SCRGB) {
if (capture->force_sdr) {
tech_name = "DrawMultiply";
multiplier =
80.f / obs_get_video_sdr_white_level();
const float target_nits =
(current_space == GS_CS_709_SCRGB)
? obs_get_video_sdr_white_level()
: 80.f;
multiplier = target_nits /
gs_duplicator_get_sdr_white_level(
capture->duplicator);
} else {
switch (current_space) {
case GS_CS_SRGB:
case GS_CS_SRGB_16F:
tech_name = "DrawMultiplyTonemap";
multiplier =
80.f /
obs_get_video_sdr_white_level();
break;
case GS_CS_709_EXTENDED:
tech_name = "DrawMultiply";
multiplier =
80.f /
obs_get_video_sdr_white_level();
}
}
} else if (current_space == GS_CS_709_SCRGB) {
tech_name = "DrawMultiply";
@ -844,9 +859,6 @@ static void update_settings_visibility(obs_properties_t *props,
obs_property_t *p = obs_properties_get(props, "cursor");
obs_property_set_visible(p, dxgi_options || wgc_cursor_toggle);
p = obs_properties_get(props, "force_sdr");
obs_property_set_visible(p, wgc_options);
pthread_mutex_unlock(&capture->update_mutex);
}
@ -909,17 +921,9 @@ duplicator_capture_get_color_space(void *data, size_t count,
capture->exports.winrt_capture_get_color_space(
capture->capture_winrt);
}
} else {
if (capture->duplicator) {
gs_texture_t *const texture =
gs_duplicator_get_texture(capture->duplicator);
if (texture) {
capture_space = (gs_texture_get_color_format(
texture) == GS_RGBA16F)
? GS_CS_709_EXTENDED
: GS_CS_SRGB;
}
}
} else if (capture->duplicator && !capture->force_sdr) {
capture_space =
gs_duplicator_get_color_space(capture->duplicator);
}
enum gs_color_space space = capture_space;

View File

@ -181,9 +181,12 @@ static void log_settings(struct window_capture *wc, obs_data_t *s)
"[window-capture: '%s'] update settings:\n"
"\texecutable: %s\n"
"\tmethod selected: %s\n"
"\tmethod chosen: %s\n",
"\tmethod chosen: %s\n"
"\tforce SDR: %s",
obs_source_get_name(wc->source), wc->executable,
get_method_name(method), get_method_name(wc->method));
get_method_name(method), get_method_name(wc->method),
(wc->force_sdr && (wc->method == METHOD_WGC)) ? "true"
: "false");
blog(LOG_DEBUG, "\tclass: %s", wc->class);
}
}