libobs: Use NV12 textures when available
This commit is contained in:
parent
82848d513e
commit
28d0cc8b97
@ -126,6 +126,16 @@ float4 PSNV12(VertInOut vert_in) : TARGET
|
||||
}
|
||||
}
|
||||
|
||||
float PSNV12_Y(VertInOut vert_in) : TARGET
|
||||
{
|
||||
return image.Sample(def_sampler, vert_in.uv.xy).y;
|
||||
}
|
||||
|
||||
float2 PSNV12_UV(VertInOut vert_in) : TARGET
|
||||
{
|
||||
return image.Sample(def_sampler, vert_in.uv.xy).xz;
|
||||
}
|
||||
|
||||
float4 PSPlanar420(VertInOut vert_in) : TARGET
|
||||
{
|
||||
float v_mul = floor(vert_in.uv.y * input_height);
|
||||
@ -339,6 +349,24 @@ technique NV12
|
||||
}
|
||||
}
|
||||
|
||||
technique NV12_Y
|
||||
{
|
||||
pass
|
||||
{
|
||||
vertex_shader = VSDefault(vert_in);
|
||||
pixel_shader = PSNV12_Y(vert_in);
|
||||
}
|
||||
}
|
||||
|
||||
technique NV12_UV
|
||||
{
|
||||
pass
|
||||
{
|
||||
vertex_shader = VSDefault(vert_in);
|
||||
pixel_shader = PSNV12_UV(vert_in);
|
||||
}
|
||||
}
|
||||
|
||||
technique UYVY_Reverse
|
||||
{
|
||||
pass
|
||||
|
@ -231,10 +231,12 @@ struct obs_core_video {
|
||||
gs_texture_t *render_textures[NUM_TEXTURES];
|
||||
gs_texture_t *output_textures[NUM_TEXTURES];
|
||||
gs_texture_t *convert_textures[NUM_TEXTURES];
|
||||
gs_texture_t *convert_uv_textures[NUM_TEXTURES];
|
||||
bool textures_rendered[NUM_TEXTURES];
|
||||
bool textures_output[NUM_TEXTURES];
|
||||
bool textures_copied[NUM_TEXTURES];
|
||||
bool textures_converted[NUM_TEXTURES];
|
||||
bool using_nv12_tex;
|
||||
struct circlebuf vframe_info_buffer;
|
||||
gs_effect_t *default_effect;
|
||||
gs_effect_t *default_rect_effect;
|
||||
|
@ -310,6 +310,55 @@ end:
|
||||
profile_end(render_convert_texture_name);
|
||||
}
|
||||
|
||||
static void render_nv12(struct obs_core_video *video, gs_texture_t *target,
|
||||
int cur_texture, int prev_texture, const char *tech_name,
|
||||
uint32_t width, uint32_t height)
|
||||
{
|
||||
gs_texture_t *texture = video->output_textures[prev_texture];
|
||||
|
||||
gs_effect_t *effect = video->conversion_effect;
|
||||
gs_eparam_t *image = gs_effect_get_param_by_name(effect, "image");
|
||||
gs_technique_t *tech = gs_effect_get_technique(effect, tech_name);
|
||||
size_t passes, i;
|
||||
|
||||
gs_effect_set_texture(image, texture);
|
||||
|
||||
gs_set_render_target(target, NULL);
|
||||
set_render_size(width, height);
|
||||
|
||||
gs_enable_blending(false);
|
||||
passes = gs_technique_begin(tech);
|
||||
for (i = 0; i < passes; i++) {
|
||||
gs_technique_begin_pass(tech, i);
|
||||
gs_draw_sprite(texture, 0, width, height);
|
||||
gs_technique_end_pass(tech);
|
||||
}
|
||||
gs_technique_end(tech);
|
||||
gs_enable_blending(true);
|
||||
}
|
||||
|
||||
static const char *render_convert_nv12_name = "render_convert_texture_nv12";
|
||||
static void render_convert_texture_nv12(struct obs_core_video *video,
|
||||
int cur_texture, int prev_texture)
|
||||
{
|
||||
profile_start(render_convert_nv12_name);
|
||||
|
||||
if (!video->textures_output[prev_texture])
|
||||
goto end;
|
||||
|
||||
render_nv12(video, video->convert_textures[cur_texture],
|
||||
cur_texture, prev_texture, "NV12_Y",
|
||||
video->output_width, video->output_height);
|
||||
render_nv12(video, video->convert_uv_textures[cur_texture],
|
||||
cur_texture, prev_texture, "NV12_UV",
|
||||
video->output_width / 2, video->output_height / 2);
|
||||
|
||||
video->textures_converted[cur_texture] = true;
|
||||
|
||||
end:
|
||||
profile_end(render_convert_nv12_name);
|
||||
}
|
||||
|
||||
static const char *stage_output_texture_name = "stage_output_texture";
|
||||
static inline void stage_output_texture(struct obs_core_video *video,
|
||||
int cur_texture, int prev_texture)
|
||||
@ -353,8 +402,15 @@ static inline void render_video(struct obs_core_video *video, bool raw_active,
|
||||
|
||||
if (raw_active) {
|
||||
render_output_texture(video, cur_texture, prev_texture);
|
||||
if (video->gpu_conversion)
|
||||
render_convert_texture(video, cur_texture, prev_texture);
|
||||
|
||||
if (video->gpu_conversion) {
|
||||
if (video->using_nv12_tex)
|
||||
render_convert_texture_nv12(video,
|
||||
cur_texture, prev_texture);
|
||||
else
|
||||
render_convert_texture(video,
|
||||
cur_texture, prev_texture);
|
||||
}
|
||||
|
||||
stage_output_texture(video, cur_texture, prev_texture);
|
||||
}
|
||||
@ -455,6 +511,27 @@ static void set_gpu_converted_data(struct obs_core_video *video,
|
||||
|
||||
video_frame_copy(output, &frame, info->format, info->height);
|
||||
|
||||
} else if (video->using_nv12_tex) {
|
||||
int width = (int)info->width;
|
||||
int height = (int)info->height;
|
||||
int width_d2 = width / 2;
|
||||
int height_d2 = height / 2;
|
||||
int height_d4 = height_d2 / 2;
|
||||
uint8_t *out_y = output->data[0];
|
||||
uint8_t *out_uv = output->data[1];
|
||||
uint8_t *in = input->data[0];
|
||||
|
||||
for (size_t y = 0; y < height; y++) {
|
||||
memcpy(out_y, in, width);
|
||||
out_y += output->linesize[0];
|
||||
in += input->linesize[0];
|
||||
}
|
||||
for (size_t y = 0; y < height_d2; y++) {
|
||||
memcpy(out_uv, in, width);
|
||||
out_uv += output->linesize[0];
|
||||
in += input->linesize[0];
|
||||
}
|
||||
|
||||
} else {
|
||||
fix_gpu_converted_alignment(video, output, input);
|
||||
}
|
||||
|
70
libobs/obs.c
70
libobs/obs.c
@ -164,17 +164,42 @@ static bool obs_init_gpu_conversion(struct obs_video_info *ovi)
|
||||
|
||||
calc_gpu_conversion_sizes(ovi);
|
||||
|
||||
video->using_nv12_tex = ovi->output_format == VIDEO_FORMAT_NV12
|
||||
? gs_nv12_available() : false;
|
||||
|
||||
if (!video->conversion_height) {
|
||||
blog(LOG_INFO, "GPU conversion not available for format: %u",
|
||||
(unsigned int)ovi->output_format);
|
||||
video->gpu_conversion = false;
|
||||
video->using_nv12_tex = false;
|
||||
blog(LOG_INFO, "NV12 texture support not available");
|
||||
return true;
|
||||
}
|
||||
|
||||
if (video->using_nv12_tex)
|
||||
blog(LOG_INFO, "NV12 texture support enabled");
|
||||
else
|
||||
blog(LOG_INFO, "NV12 texture support not available");
|
||||
|
||||
for (size_t i = 0; i < NUM_TEXTURES; i++) {
|
||||
video->convert_textures[i] = gs_texture_create(
|
||||
ovi->output_width, video->conversion_height,
|
||||
GS_RGBA, 1, NULL, GS_RENDER_TARGET);
|
||||
#ifdef _WIN32
|
||||
if (video->using_nv12_tex) {
|
||||
gs_texture_create_nv12(
|
||||
&video->convert_textures[i],
|
||||
&video->convert_uv_textures[i],
|
||||
ovi->output_width, ovi->output_height,
|
||||
GS_RENDER_TARGET | GS_SHARED_KM_TEX);
|
||||
if (!video->convert_uv_textures[i])
|
||||
return false;
|
||||
} else {
|
||||
#endif
|
||||
video->convert_textures[i] = gs_texture_create(
|
||||
ovi->output_width,
|
||||
video->conversion_height,
|
||||
GS_RGBA, 1, NULL, GS_RENDER_TARGET);
|
||||
#ifdef _WIN32
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!video->convert_textures[i])
|
||||
return false;
|
||||
@ -191,11 +216,23 @@ static bool obs_init_textures(struct obs_video_info *ovi)
|
||||
size_t i;
|
||||
|
||||
for (i = 0; i < NUM_TEXTURES; i++) {
|
||||
video->copy_surfaces[i] = gs_stagesurface_create(
|
||||
ovi->output_width, output_height, GS_RGBA);
|
||||
#ifdef _WIN32
|
||||
if (video->using_nv12_tex) {
|
||||
video->copy_surfaces[i] = gs_stagesurface_create_nv12(
|
||||
ovi->output_width, ovi->output_height);
|
||||
if (!video->copy_surfaces[i])
|
||||
return false;
|
||||
|
||||
if (!video->copy_surfaces[i])
|
||||
return false;
|
||||
} else {
|
||||
#endif
|
||||
video->copy_surfaces[i] = gs_stagesurface_create(
|
||||
ovi->output_width, output_height,
|
||||
GS_RGBA);
|
||||
if (!video->copy_surfaces[i])
|
||||
return false;
|
||||
#ifdef _WIN32
|
||||
}
|
||||
#endif
|
||||
|
||||
video->render_textures[i] = gs_texture_create(
|
||||
ovi->base_width, ovi->base_height,
|
||||
@ -431,12 +468,14 @@ static void obs_free_video(void)
|
||||
gs_stagesurface_destroy(video->copy_surfaces[i]);
|
||||
gs_texture_destroy(video->render_textures[i]);
|
||||
gs_texture_destroy(video->convert_textures[i]);
|
||||
gs_texture_destroy(video->convert_uv_textures[i]);
|
||||
gs_texture_destroy(video->output_textures[i]);
|
||||
|
||||
video->copy_surfaces[i] = NULL;
|
||||
video->render_textures[i] = NULL;
|
||||
video->convert_textures[i] = NULL;
|
||||
video->output_textures[i] = NULL;
|
||||
video->copy_surfaces[i] = NULL;
|
||||
video->render_textures[i] = NULL;
|
||||
video->convert_textures[i] = NULL;
|
||||
video->convert_uv_textures[i] = NULL;
|
||||
video->output_textures[i] = NULL;
|
||||
}
|
||||
|
||||
gs_leave_context();
|
||||
@ -2267,3 +2306,12 @@ bool obs_video_active(void)
|
||||
|
||||
return os_atomic_load_long(&video->raw_active) > 0;
|
||||
}
|
||||
|
||||
bool obs_nv12_tex_active(void)
|
||||
{
|
||||
struct obs_core_video *video = &obs->video;
|
||||
if (!obs)
|
||||
return false;
|
||||
|
||||
return video->using_nv12_tex;
|
||||
}
|
||||
|
@ -713,6 +713,8 @@ EXPORT uint64_t obs_get_average_frame_time_ns(void);
|
||||
EXPORT uint32_t obs_get_total_frames(void);
|
||||
EXPORT uint32_t obs_get_lagged_frames(void);
|
||||
|
||||
EXPORT bool obs_nv12_tex_active(void);
|
||||
|
||||
EXPORT void obs_apply_private_data(obs_data_t *settings);
|
||||
EXPORT void obs_set_private_data(obs_data_t *settings);
|
||||
EXPORT obs_data_t *obs_get_private_data(void);
|
||||
|
Loading…
x
Reference in New Issue
Block a user