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:
commit
e9ef38e3d3
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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 *,
|
||||
|
@ -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();
|
||||
};
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user