win-capture: Add DXGI/WGC HDR support
HDR for DXGI/WGC display capture, and WGC window capture. Also add fast SDR paths for BitBlt to skip color conversions.
This commit is contained in:
parent
302862fe33
commit
93fe82d1ce
@ -69,11 +69,20 @@ void dc_capture_init(struct dc_capture *capture, int x, int y, uint32_t width,
|
||||
bih->biHeight = height;
|
||||
bih->biPlanes = 1;
|
||||
|
||||
capture->hdc = CreateCompatibleDC(NULL);
|
||||
capture->bmp =
|
||||
CreateDIBSection(capture->hdc, &bi, DIB_RGB_COLORS,
|
||||
(void **)&capture->bits, NULL, 0);
|
||||
capture->old_bmp = SelectObject(capture->hdc, capture->bmp);
|
||||
const HDC hdc = CreateCompatibleDC(NULL);
|
||||
if (hdc) {
|
||||
const HBITMAP bmp = CreateDIBSection(
|
||||
capture->hdc, &bi, DIB_RGB_COLORS,
|
||||
(void **)&capture->bits, NULL, 0);
|
||||
if (bmp) {
|
||||
capture->hdc = hdc;
|
||||
capture->bmp = bmp;
|
||||
capture->old_bmp = SelectObject(capture->hdc,
|
||||
capture->bmp);
|
||||
} else {
|
||||
DeleteDC(capture->hdc);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -179,48 +188,67 @@ void dc_capture_capture(struct dc_capture *capture, HWND window)
|
||||
capture->texture_written = true;
|
||||
}
|
||||
|
||||
static void draw_texture(struct dc_capture *capture, bool texcoords_centered)
|
||||
{
|
||||
gs_effect_t *effect = obs_get_base_effect(OBS_EFFECT_OPAQUE);
|
||||
gs_technique_t *tech = gs_effect_get_technique(effect, "Draw");
|
||||
gs_eparam_t *image = gs_effect_get_param_by_name(effect, "image");
|
||||
|
||||
gs_texture_t *texture = capture->texture;
|
||||
const bool compatibility = capture->compatibility;
|
||||
bool linear_sample = compatibility;
|
||||
if (!linear_sample && !texcoords_centered) {
|
||||
gs_texture_t *const extra_texture = capture->extra_texture;
|
||||
gs_copy_texture(extra_texture, texture);
|
||||
texture = extra_texture;
|
||||
linear_sample = true;
|
||||
}
|
||||
|
||||
const bool previous = gs_framebuffer_srgb_enabled();
|
||||
gs_enable_framebuffer_srgb(linear_sample);
|
||||
gs_enable_blending(false);
|
||||
|
||||
if (linear_sample)
|
||||
gs_effect_set_texture_srgb(image, texture);
|
||||
else
|
||||
gs_effect_set_texture(image, texture);
|
||||
|
||||
const uint32_t flip = compatibility ? GS_FLIP_V : 0;
|
||||
const size_t passes = gs_technique_begin(tech);
|
||||
for (size_t i = 0; i < passes; i++) {
|
||||
if (gs_technique_begin_pass(tech, i)) {
|
||||
gs_draw_sprite(texture, flip, 0, 0);
|
||||
|
||||
gs_technique_end_pass(tech);
|
||||
}
|
||||
}
|
||||
gs_technique_end(tech);
|
||||
|
||||
gs_enable_blending(true);
|
||||
gs_enable_framebuffer_srgb(previous);
|
||||
}
|
||||
|
||||
void dc_capture_render(struct dc_capture *capture, bool texcoords_centered)
|
||||
{
|
||||
if (capture->valid && capture->texture_written)
|
||||
draw_texture(capture, texcoords_centered);
|
||||
if (capture->valid && capture->texture_written) {
|
||||
gs_texture_t *texture = capture->texture;
|
||||
const bool compatibility = capture->compatibility;
|
||||
bool linear_sample = compatibility;
|
||||
if (!linear_sample && !texcoords_centered) {
|
||||
gs_texture_t *const extra_texture =
|
||||
capture->extra_texture;
|
||||
gs_copy_texture(extra_texture, texture);
|
||||
texture = extra_texture;
|
||||
linear_sample = true;
|
||||
}
|
||||
|
||||
const char *tech_name = "Draw";
|
||||
float multiplier = 1.f;
|
||||
switch (gs_get_color_space()) {
|
||||
case GS_CS_SRGB_16F:
|
||||
case GS_CS_709_EXTENDED:
|
||||
if (!linear_sample)
|
||||
tech_name = "DrawSrgbDecompress";
|
||||
break;
|
||||
case GS_CS_709_SCRGB:
|
||||
if (linear_sample)
|
||||
tech_name = "DrawMultiply";
|
||||
else
|
||||
tech_name = "DrawSrgbDecompressMultiply";
|
||||
multiplier = obs_get_video_sdr_white_level() / 80.f;
|
||||
}
|
||||
|
||||
gs_effect_t *effect = obs_get_base_effect(OBS_EFFECT_OPAQUE);
|
||||
gs_technique_t *tech =
|
||||
gs_effect_get_technique(effect, tech_name);
|
||||
gs_eparam_t *image =
|
||||
gs_effect_get_param_by_name(effect, "image");
|
||||
|
||||
const bool previous = gs_framebuffer_srgb_enabled();
|
||||
gs_enable_framebuffer_srgb(linear_sample);
|
||||
gs_enable_blending(false);
|
||||
|
||||
if (linear_sample)
|
||||
gs_effect_set_texture_srgb(image, texture);
|
||||
else
|
||||
gs_effect_set_texture(image, texture);
|
||||
|
||||
gs_eparam_t *multiplier_param =
|
||||
gs_effect_get_param_by_name(effect, "multiplier");
|
||||
gs_effect_set_float(multiplier_param, multiplier);
|
||||
|
||||
const uint32_t flip = compatibility ? GS_FLIP_V : 0;
|
||||
const size_t passes = gs_technique_begin(tech);
|
||||
for (size_t i = 0; i < passes; i++) {
|
||||
if (gs_technique_begin_pass(tech, i)) {
|
||||
gs_draw_sprite(texture, flip, 0, 0);
|
||||
|
||||
gs_technique_end_pass(tech);
|
||||
}
|
||||
}
|
||||
gs_technique_end(tech);
|
||||
|
||||
gs_enable_blending(true);
|
||||
gs_enable_framebuffer_srgb(previous);
|
||||
}
|
||||
}
|
||||
|
@ -39,6 +39,8 @@ typedef struct winrt_capture *(*PFN_winrt_capture_init_monitor)(
|
||||
typedef void (*PFN_winrt_capture_free)(struct winrt_capture *capture);
|
||||
|
||||
typedef BOOL (*PFN_winrt_capture_active)(const struct winrt_capture *capture);
|
||||
typedef enum gs_color_space (*PFN_winrt_capture_get_color_space)(
|
||||
const struct winrt_capture *capture);
|
||||
typedef void (*PFN_winrt_capture_render)(struct winrt_capture *capture);
|
||||
typedef uint32_t (*PFN_winrt_capture_width)(const struct winrt_capture *capture);
|
||||
typedef uint32_t (*PFN_winrt_capture_height)(
|
||||
@ -51,6 +53,7 @@ struct winrt_exports {
|
||||
PFN_winrt_capture_init_monitor winrt_capture_init_monitor;
|
||||
PFN_winrt_capture_free winrt_capture_free;
|
||||
PFN_winrt_capture_active winrt_capture_active;
|
||||
PFN_winrt_capture_get_color_space winrt_capture_get_color_space;
|
||||
PFN_winrt_capture_render winrt_capture_render;
|
||||
PFN_winrt_capture_width winrt_capture_width;
|
||||
PFN_winrt_capture_height winrt_capture_height;
|
||||
@ -299,6 +302,7 @@ static bool load_winrt_imports(struct winrt_exports *exports, void *module,
|
||||
WINRT_IMPORT(winrt_capture_init_monitor);
|
||||
WINRT_IMPORT(winrt_capture_free);
|
||||
WINRT_IMPORT(winrt_capture_active);
|
||||
WINRT_IMPORT(winrt_capture_get_color_space);
|
||||
WINRT_IMPORT(winrt_capture_render);
|
||||
WINRT_IMPORT(winrt_capture_width);
|
||||
WINRT_IMPORT(winrt_capture_height);
|
||||
@ -541,13 +545,37 @@ static void duplicator_capture_render(void *data, gs_effect_t *unused)
|
||||
gs_matrix_rotaa4f(0.0f, 0.0f, 1.0f, RAD((float)rot));
|
||||
}
|
||||
|
||||
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:
|
||||
tech_name = "DrawMultiply";
|
||||
multiplier =
|
||||
80.f / obs_get_video_sdr_white_level();
|
||||
}
|
||||
} else if (current_space == GS_CS_709_SCRGB) {
|
||||
tech_name = "DrawMultiply";
|
||||
multiplier = obs_get_video_sdr_white_level() / 80.f;
|
||||
}
|
||||
|
||||
gs_effect_t *const opaque_effect =
|
||||
obs_get_base_effect(OBS_EFFECT_OPAQUE);
|
||||
while (gs_effect_loop(opaque_effect, "Draw")) {
|
||||
gs_eparam_t *image = gs_effect_get_param_by_name(
|
||||
opaque_effect, "image");
|
||||
gs_effect_set_texture_srgb(image, texture);
|
||||
gs_eparam_t *multiplier_param = gs_effect_get_param_by_name(
|
||||
opaque_effect, "multiplier");
|
||||
gs_effect_set_float(multiplier_param, multiplier);
|
||||
gs_eparam_t *image_param =
|
||||
gs_effect_get_param_by_name(opaque_effect, "image");
|
||||
gs_effect_set_texture_srgb(image_param, texture);
|
||||
|
||||
while (gs_effect_loop(opaque_effect, tech_name)) {
|
||||
gs_draw_sprite(texture, 0, 0, 0);
|
||||
}
|
||||
|
||||
@ -673,6 +701,43 @@ static obs_properties_t *duplicator_capture_properties(void *data)
|
||||
return props;
|
||||
}
|
||||
|
||||
enum gs_color_space
|
||||
duplicator_capture_get_color_space(void *data, size_t count,
|
||||
const enum gs_color_space *preferred_spaces)
|
||||
{
|
||||
enum gs_color_space capture_space = GS_CS_SRGB;
|
||||
|
||||
struct duplicator_capture *capture = data;
|
||||
if (capture->method == METHOD_WGC) {
|
||||
if (capture->capture_winrt) {
|
||||
capture_space =
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
enum gs_color_space space = capture_space;
|
||||
for (size_t i = 0; i < count; ++i) {
|
||||
const enum gs_color_space preferred_space = preferred_spaces[i];
|
||||
space = preferred_space;
|
||||
if (preferred_space == capture_space)
|
||||
break;
|
||||
}
|
||||
|
||||
return space;
|
||||
}
|
||||
|
||||
struct obs_source_info duplicator_capture_info = {
|
||||
.id = "monitor_capture",
|
||||
.type = OBS_SOURCE_TYPE_INPUT,
|
||||
@ -689,4 +754,5 @@ struct obs_source_info duplicator_capture_info = {
|
||||
.get_defaults = duplicator_capture_defaults,
|
||||
.get_properties = duplicator_capture_properties,
|
||||
.icon_type = OBS_ICON_TYPE_DESKTOP_CAPTURE,
|
||||
.video_get_color_space = duplicator_capture_get_color_space,
|
||||
};
|
||||
|
@ -37,6 +37,8 @@ typedef void (*PFN_winrt_capture_free)(struct winrt_capture *capture);
|
||||
typedef BOOL (*PFN_winrt_capture_active)(const struct winrt_capture *capture);
|
||||
typedef BOOL (*PFN_winrt_capture_show_cursor)(struct winrt_capture *capture,
|
||||
BOOL visible);
|
||||
typedef enum gs_color_space (*PFN_winrt_capture_get_color_space)(
|
||||
const struct winrt_capture *capture);
|
||||
typedef void (*PFN_winrt_capture_render)(struct winrt_capture *capture);
|
||||
typedef uint32_t (*PFN_winrt_capture_width)(const struct winrt_capture *capture);
|
||||
typedef uint32_t (*PFN_winrt_capture_height)(
|
||||
@ -50,6 +52,7 @@ struct winrt_exports {
|
||||
PFN_winrt_capture_free winrt_capture_free;
|
||||
PFN_winrt_capture_active winrt_capture_active;
|
||||
PFN_winrt_capture_show_cursor winrt_capture_show_cursor;
|
||||
PFN_winrt_capture_get_color_space winrt_capture_get_color_space;
|
||||
PFN_winrt_capture_render winrt_capture_render;
|
||||
PFN_winrt_capture_width winrt_capture_width;
|
||||
PFN_winrt_capture_height winrt_capture_height;
|
||||
@ -238,6 +241,7 @@ static bool load_winrt_imports(struct winrt_exports *exports, void *module,
|
||||
WINRT_IMPORT(winrt_capture_free);
|
||||
WINRT_IMPORT(winrt_capture_active);
|
||||
WINRT_IMPORT(winrt_capture_show_cursor);
|
||||
WINRT_IMPORT(winrt_capture_get_color_space);
|
||||
WINRT_IMPORT(winrt_capture_render);
|
||||
WINRT_IMPORT(winrt_capture_width);
|
||||
WINRT_IMPORT(winrt_capture_height);
|
||||
@ -644,6 +648,30 @@ static void wc_render(void *data, gs_effect_t *effect)
|
||||
UNUSED_PARAMETER(effect);
|
||||
}
|
||||
|
||||
enum gs_color_space
|
||||
wc_get_color_space(void *data, size_t count,
|
||||
const enum gs_color_space *preferred_spaces)
|
||||
{
|
||||
struct window_capture *wc = data;
|
||||
|
||||
enum gs_color_space capture_space = GS_CS_SRGB;
|
||||
|
||||
if ((wc->method == METHOD_WGC) && wc->capture_winrt) {
|
||||
capture_space = wc->exports.winrt_capture_get_color_space(
|
||||
wc->capture_winrt);
|
||||
}
|
||||
|
||||
enum gs_color_space space = capture_space;
|
||||
for (size_t i = 0; i < count; ++i) {
|
||||
const enum gs_color_space preferred_space = preferred_spaces[i];
|
||||
space = preferred_space;
|
||||
if (preferred_space == capture_space)
|
||||
break;
|
||||
}
|
||||
|
||||
return space;
|
||||
}
|
||||
|
||||
struct obs_source_info window_capture_info = {
|
||||
.id = "window_capture",
|
||||
.type = OBS_SOURCE_TYPE_INPUT,
|
||||
@ -661,4 +689,5 @@ struct obs_source_info window_capture_info = {
|
||||
.get_defaults = wc_defaults,
|
||||
.get_properties = wc_properties,
|
||||
.icon_type = OBS_ICON_TYPE_WINDOW_CAPTURE,
|
||||
.video_get_color_space = wc_get_color_space,
|
||||
};
|
||||
|
Loading…
x
Reference in New Issue
Block a user