浏览代码

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

libobs-d3d11,win-capture: Add Force SDR for DXGI duplicator
Jim 2 年之前
父节点
当前提交
e9ef38e3d3

+ 25 - 0
libobs-d3d11/d3d11-duplicator.cpp

@@ -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;
+}
 }

+ 53 - 56
libobs-d3d11/d3d11-subsystem.cpp

@@ -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 *,

+ 14 - 5
libobs-d3d11/d3d11-subsystem.hpp

@@ -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();
 };

+ 2 - 0
libobs/graphics/graphics-imports.c

@@ -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);

+ 3 - 0
libobs/graphics/graphics-internal.h

@@ -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);
 

+ 22 - 0
libobs/graphics/graphics.c

@@ -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)
 {

+ 3 - 0
libobs/graphics/graphics.h

@@ -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);
 

+ 31 - 27
plugins/win-capture/duplicator-monitor-capture.c

@@ -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;

+ 5 - 2
plugins/win-capture/window-capture.c

@@ -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);
 	}
 }