Skip to content

Commit e70416e

Browse files
committed
Make HDR work with VK_COLOR_SPACE_EXTENDED_SRGB_LINEAR_EXT
1 parent 6e31778 commit e70416e

File tree

2 files changed

+121
-37
lines changed

2 files changed

+121
-37
lines changed

src/vkcapture.c

Lines changed: 120 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,10 @@ static wl_cursor_t *wlcursor = NULL;
5353
static uint8_t gl_device_uuid[16];
5454
void (*p_glGetUnsignedBytei_vEXT)(unsigned int target, unsigned int index, unsigned char *data) = NULL;
5555

56+
#define VK_COLOR_SPACE_SRGB_NONLINEAR_KHR 0
57+
#define VK_COLOR_SPACE_EXTENDED_SRGB_LINEAR_EXT 1000104002
58+
#define VK_COLOR_SPACE_HDR10_ST2084_EXT 1000104008
59+
5660
enum vkcapture_import_attempt {
5761
IMPORT_DEFAULT = 0,
5862
IMPORT_NO_MODIFIERS = 1,
@@ -562,23 +566,105 @@ static void vkcapture_source_render(void *data, gs_effect_t *effect)
562566
ioctl(fd, DMA_BUF_IOCTL_SYNC, &sync);
563567
}
564568

565-
const enum gs_color_space color_space = gs_get_color_space();
566-
const bool linear_srgb = gs_get_linear_srgb();
567-
const char *tech_name = linear_srgb ? "DrawSrgbDecompress" : "Draw";
569+
enum gs_color_space source_space = GS_CS_SRGB;
570+
const bool is_pq = ctx->tdata.color_space == VK_COLOR_SPACE_HDR10_ST2084_EXT;
571+
if (is_pq)
572+
source_space = GS_CS_709_EXTENDED;
573+
else if (ctx->tdata.color_space == VK_COLOR_SPACE_EXTENDED_SRGB_LINEAR_EXT)
574+
source_space = GS_CS_709_SCRGB;
575+
576+
const enum gs_color_space current_space = gs_get_color_space();
577+
bool linear_sample = !gs_get_linear_srgb();
578+
const char *tech_name = "Draw";
568579
float multiplier = 1.f;
569580

570-
if (color_space == GS_CS_709_EXTENDED) {
571-
tech_name = "DrawPQ";
572-
multiplier = 10000.f / obs_get_video_sdr_white_level();
581+
switch (source_space) {
582+
case GS_CS_SRGB:
583+
switch (current_space) {
584+
case GS_CS_SRGB:
585+
if (ctx->allow_transparency && !linear_sample)
586+
tech_name = "DrawSrgbDecompress";
587+
break;
588+
case GS_CS_SRGB_16F:
589+
case GS_CS_709_EXTENDED:
590+
if (!linear_sample)
591+
tech_name = "DrawSrgbDecompress";
592+
break;
593+
case GS_CS_709_SCRGB:
594+
if (linear_sample)
595+
tech_name = "DrawMultiply";
596+
else
597+
tech_name = "DrawSrgbDecompressMultiply";
598+
multiplier = obs_get_video_sdr_white_level() / 80.f;
599+
}
600+
break;
601+
case GS_CS_SRGB_16F:
602+
linear_sample = true;
603+
switch (current_space) {
604+
case GS_CS_SRGB:
605+
case GS_CS_SRGB_16F:
606+
case GS_CS_709_EXTENDED:
607+
tech_name = is_pq ? "DrawSrgbDecompress" : "Draw";
608+
break;
609+
case GS_CS_709_SCRGB:
610+
tech_name = is_pq ? "DrawSrgbDecompressMultiply" : "DrawMultiply";
611+
multiplier = obs_get_video_sdr_white_level() / 80.f;
612+
}
613+
break;
614+
case GS_CS_709_EXTENDED:
615+
linear_sample = true;
616+
if (is_pq) {
617+
switch (current_space) {
618+
case GS_CS_SRGB:
619+
case GS_CS_SRGB_16F:
620+
tech_name = "DrawTonemapPQ";
621+
multiplier = 10000.f / obs_get_video_sdr_white_level();
622+
break;
623+
case GS_CS_709_EXTENDED:
624+
tech_name = "DrawPQ";
625+
multiplier = 10000.f / obs_get_video_sdr_white_level();
626+
break;
627+
case GS_CS_709_SCRGB:
628+
tech_name = "DrawPQ";
629+
multiplier = 10000.f / 80.f;
630+
}
631+
} else {
632+
switch (current_space) {
633+
case GS_CS_SRGB:
634+
case GS_CS_SRGB_16F:
635+
tech_name = "DrawTonemap";
636+
break;
637+
case GS_CS_709_SCRGB:
638+
tech_name = "DrawMultiply";
639+
multiplier = obs_get_video_sdr_white_level() / 80.f;
640+
default:
641+
break;
642+
}
643+
}
644+
break;
645+
case GS_CS_709_SCRGB:
646+
linear_sample = true;
647+
switch (current_space) {
648+
case GS_CS_SRGB:
649+
case GS_CS_SRGB_16F:
650+
tech_name = "DrawMultiplyTonemap";
651+
multiplier = 80.f / obs_get_video_sdr_white_level();
652+
break;
653+
case GS_CS_709_EXTENDED:
654+
tech_name = "DrawMultiply";
655+
multiplier = 80.f / obs_get_video_sdr_white_level();
656+
default:
657+
break;
658+
}
573659
}
574660

575661
effect = obs_get_base_effect(ctx->allow_transparency ? OBS_EFFECT_DEFAULT : OBS_EFFECT_OPAQUE);
576662

577663
const bool previous = gs_framebuffer_srgb_enabled();
578-
gs_enable_framebuffer_srgb(linear_srgb);
664+
gs_enable_framebuffer_srgb(ctx->allow_transparency || linear_sample);
579665

580666
gs_eparam_t *image = gs_effect_get_param_by_name(effect, "image");
581-
if (linear_srgb)
667+
if (linear_sample)
582668
gs_effect_set_texture_srgb(image, ctx->texture);
583669
else
584670
gs_effect_set_texture(image, ctx->texture);
@@ -591,21 +677,23 @@ static void vkcapture_source_render(void *data, gs_effect_t *effect)
591677
}
592678
}
593679

680+
gs_enable_framebuffer_srgb(previous);
681+
594682
if (!ctx->allow_transparency && ctx->show_cursor) {
595683
effect = obs_get_base_effect(OBS_EFFECT_DEFAULT);
596684
tech_name = "Draw";
597685
multiplier = 1.f;
598-
if (color_space == GS_CS_709_SCRGB) {
686+
if (current_space == GS_CS_709_SCRGB) {
599687
tech_name = "DrawMultiply";
600688
multiplier = obs_get_video_sdr_white_level() / 80.f;
601689
}
602690
while (gs_effect_loop(effect, tech_name)) {
603691
gs_effect_set_float(gs_effect_get_param_by_name(effect, "multiplier"), multiplier);
604692
cursor_render(ctx);
605693
}
606-
}
607694

608-
gs_enable_framebuffer_srgb(previous);
695+
gs_set_linear_srgb(previous);
696+
}
609697
}
610698

611699
static const char *vkcapture_source_get_name(void *data)
@@ -695,15 +783,29 @@ enum gs_color_space vkcapture_get_color_space(void *data, size_t count, const en
695783
{
696784
vkcapture_source_t *ctx = data;
697785

698-
enum gs_color_space color_space = ctx->tdata.color_space;
786+
enum gs_color_space capture_space = GS_CS_SRGB;
787+
uint32_t color_space = ctx->tdata.color_space;
699788

700-
if (ctx->force_hdr) {
701-
color_space = GS_CS_709_EXTENDED;
789+
if (color_space == VK_COLOR_SPACE_HDR10_ST2084_EXT || color_space == VK_COLOR_SPACE_EXTENDED_SRGB_LINEAR_EXT) {
790+
for (size_t i = 0; i < count; ++i) {
791+
if (preferred_spaces[i] == GS_CS_709_SCRGB) {
792+
return GS_CS_709_SCRGB;
793+
}
794+
}
795+
capture_space = GS_CS_709_EXTENDED;
702796
}
703-
704-
UNUSED_PARAMETER(count);
705-
UNUSED_PARAMETER(preferred_spaces);
706-
return color_space;
797+
// TODO: Maybe handle GS_CS_SRGB_16F? SDR for >8 bit format
798+
799+
// Same as win-capture/game-capture.c
800+
enum gs_color_space space = capture_space;
801+
for (size_t i = 0; i < count; ++i) {
802+
const enum gs_color_space preferred_space = preferred_spaces[i];
803+
space = preferred_space;
804+
if (preferred_space == capture_space) {
805+
break;
806+
}
807+
}
808+
return space;
707809
}
708810

709811
static struct obs_source_info vkcapture_input = {

src/vklayer.c

Lines changed: 1 addition & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -588,24 +588,6 @@ static int32_t vk_format_to_drm(VkFormat vk)
588588
return -1;
589589
}
590590

591-
static uint32_t vk_color_space_to_obs(VkColorSpaceKHR vk)
592-
{
593-
const char *force = getenv("OBS_VKCAPTURE_COLOR_SPACE");
594-
if (force) {
595-
int value = atoi(force);
596-
if (value >= 0 && value < 3) {
597-
return value;
598-
}
599-
}
600-
switch (vk) {
601-
case VK_COLOR_SPACE_HDR10_ST2084_EXT:
602-
return 2; // GS_CS_709_EXTENDED
603-
case VK_COLOR_SPACE_SRGB_NONLINEAR_KHR:
604-
default:
605-
return 0; // GS_CS_SRGB
606-
}
607-
}
608-
609591
static inline bool vk_shtex_init_vulkan_tex(struct vk_data *data,
610592
struct vk_swap_data *swap)
611593
{
@@ -907,7 +889,7 @@ static bool vk_shtex_init(struct vk_data *data, struct vk_swap_data *swap)
907889
capture_init_shtex(swap->image_extent.width, swap->image_extent.height,
908890
vk_format_to_drm(swap->export_format),
909891
swap->dmabuf_strides, swap->dmabuf_offsets, swap->dmabuf_modifier,
910-
swap->winid, /*flip*/false, vk_color_space_to_obs(swap->color_space),
892+
swap->winid, /*flip*/false, swap->color_space,
911893
swap->dmabuf_nfd, swap->dmabuf_fds);
912894

913895
hlog("------------------ vulkan capture started ------------------");

0 commit comments

Comments
 (0)