diff --git a/libobs-opengl/gl-subsystem.c b/libobs-opengl/gl-subsystem.c index 0fd554497..249a68ea8 100644 --- a/libobs-opengl/gl-subsystem.c +++ b/libobs-opengl/gl-subsystem.c @@ -1519,6 +1519,18 @@ void gs_swapchain_destroy(gs_swapchain_t *swapchain) bfree(swapchain); } +bool device_nv12_available(gs_device_t *device) +{ + UNUSED_PARAMETER(device); + return true; // always a split R8,R8G8 texture. +} + +bool device_p010_available(gs_device_t *device) +{ + UNUSED_PARAMETER(device); + return true; // always a split R16,R16G16 texture. +} + uint32_t gs_voltexture_get_width(const gs_texture_t *voltex) { /* TODO */ diff --git a/libobs/graphics/graphics-imports.c b/libobs/graphics/graphics-imports.c index f0e5c433f..e27cc6a17 100644 --- a/libobs/graphics/graphics-imports.c +++ b/libobs/graphics/graphics-imports.c @@ -195,6 +195,8 @@ bool load_graphics_imports(struct gs_exports *exports, void *module, GRAPHICS_IMPORT_OPTIONAL(device_nv12_available); GRAPHICS_IMPORT_OPTIONAL(device_p010_available); + GRAPHICS_IMPORT_OPTIONAL(device_texture_create_nv12); + GRAPHICS_IMPORT_OPTIONAL(device_texture_create_p010); GRAPHICS_IMPORT(device_is_monitor_hdr); @@ -231,8 +233,6 @@ bool load_graphics_imports(struct gs_exports *exports, void *module, GRAPHICS_IMPORT_OPTIONAL(device_texture_wrap_obj); GRAPHICS_IMPORT_OPTIONAL(device_texture_acquire_sync); GRAPHICS_IMPORT_OPTIONAL(device_texture_release_sync); - GRAPHICS_IMPORT_OPTIONAL(device_texture_create_nv12); - GRAPHICS_IMPORT_OPTIONAL(device_texture_create_p010); GRAPHICS_IMPORT_OPTIONAL(device_stagesurface_create_nv12); GRAPHICS_IMPORT_OPTIONAL(device_stagesurface_create_p010); GRAPHICS_IMPORT_OPTIONAL(device_register_loss_callbacks); diff --git a/libobs/graphics/graphics-internal.h b/libobs/graphics/graphics-internal.h index 4801acaf0..e2bcb90bf 100644 --- a/libobs/graphics/graphics-internal.h +++ b/libobs/graphics/graphics-internal.h @@ -273,6 +273,16 @@ struct gs_exports { bool (*device_nv12_available)(gs_device_t *device); bool (*device_p010_available)(gs_device_t *device); + bool (*device_texture_create_nv12)(gs_device_t *device, + gs_texture_t **tex_y, + gs_texture_t **tex_uv, + uint32_t width, uint32_t height, + uint32_t flags); + bool (*device_texture_create_p010)(gs_device_t *device, + gs_texture_t **tex_y, + gs_texture_t **tex_uv, + uint32_t width, uint32_t height, + uint32_t flags); bool (*device_is_monitor_hdr)(gs_device_t *device, void *monitor); @@ -331,16 +341,6 @@ struct gs_exports { int (*device_texture_acquire_sync)(gs_texture_t *tex, uint64_t key, uint32_t ms); int (*device_texture_release_sync)(gs_texture_t *tex, uint64_t key); - bool (*device_texture_create_nv12)(gs_device_t *device, - gs_texture_t **tex_y, - gs_texture_t **tex_uv, - uint32_t width, uint32_t height, - uint32_t flags); - bool (*device_texture_create_p010)(gs_device_t *device, - gs_texture_t **tex_y, - gs_texture_t **tex_uv, - uint32_t width, uint32_t height, - uint32_t flags); gs_stagesurf_t *(*device_stagesurface_create_nv12)(gs_device_t *device, uint32_t width, diff --git a/libobs/graphics/graphics.c b/libobs/graphics/graphics.c index bedc69590..7cdedf806 100644 --- a/libobs/graphics/graphics.c +++ b/libobs/graphics/graphics.c @@ -2908,6 +2908,84 @@ void gs_debug_marker_end(void) thread_graphics->device); } +bool gs_texture_create_nv12(gs_texture_t **tex_y, gs_texture_t **tex_uv, + uint32_t width, uint32_t height, uint32_t flags) +{ + graphics_t *graphics = thread_graphics; + bool success = false; + + if (!gs_valid("gs_texture_create_nv12")) + return false; + + if ((width & 1) == 1 || (height & 1) == 1) { + blog(LOG_ERROR, "NV12 textures must have dimensions " + "divisible by 2."); + return false; + } + + if (graphics->exports.device_texture_create_nv12) { + success = graphics->exports.device_texture_create_nv12( + graphics->device, tex_y, tex_uv, width, height, flags); + if (success) + return true; + } + + *tex_y = gs_texture_create(width, height, GS_R8, 1, NULL, flags); + *tex_uv = gs_texture_create(width / 2, height / 2, GS_R8G8, 1, NULL, + flags); + + if (!*tex_y || !*tex_uv) { + if (*tex_y) + gs_texture_destroy(*tex_y); + if (*tex_uv) + gs_texture_destroy(*tex_uv); + *tex_y = NULL; + *tex_uv = NULL; + return false; + } + + return true; +} + +bool gs_texture_create_p010(gs_texture_t **tex_y, gs_texture_t **tex_uv, + uint32_t width, uint32_t height, uint32_t flags) +{ + graphics_t *graphics = thread_graphics; + bool success = false; + + if (!gs_valid("gs_texture_create_p010")) + return false; + + if ((width & 1) == 1 || (height & 1) == 1) { + blog(LOG_ERROR, "P010 textures must have dimensions " + "divisible by 2."); + return false; + } + + if (graphics->exports.device_texture_create_p010) { + success = graphics->exports.device_texture_create_p010( + graphics->device, tex_y, tex_uv, width, height, flags); + if (success) + return true; + } + + *tex_y = gs_texture_create(width, height, GS_R16, 1, NULL, flags); + *tex_uv = gs_texture_create(width / 2, height / 2, GS_RG16, 1, NULL, + flags); + + if (!*tex_y || !*tex_uv) { + if (*tex_y) + gs_texture_destroy(*tex_y); + if (*tex_uv) + gs_texture_destroy(*tex_uv); + *tex_y = NULL; + *tex_uv = NULL; + return false; + } + + return true; +} + #ifdef __APPLE__ /** Platform specific functions */ @@ -3186,84 +3264,6 @@ int gs_texture_release_sync(gs_texture_t *tex, uint64_t key) return -1; } -bool gs_texture_create_nv12(gs_texture_t **tex_y, gs_texture_t **tex_uv, - uint32_t width, uint32_t height, uint32_t flags) -{ - graphics_t *graphics = thread_graphics; - bool success = false; - - if (!gs_valid("gs_texture_create_nv12")) - return false; - - if ((width & 1) == 1 || (height & 1) == 1) { - blog(LOG_ERROR, "NV12 textures must have dimensions " - "divisible by 2."); - return false; - } - - if (graphics->exports.device_texture_create_nv12) { - success = graphics->exports.device_texture_create_nv12( - graphics->device, tex_y, tex_uv, width, height, flags); - if (success) - return true; - } - - *tex_y = gs_texture_create(width, height, GS_R8, 1, NULL, flags); - *tex_uv = gs_texture_create(width / 2, height / 2, GS_R8G8, 1, NULL, - flags); - - if (!*tex_y || !*tex_uv) { - if (*tex_y) - gs_texture_destroy(*tex_y); - if (*tex_uv) - gs_texture_destroy(*tex_uv); - *tex_y = NULL; - *tex_uv = NULL; - return false; - } - - return true; -} - -bool gs_texture_create_p010(gs_texture_t **tex_y, gs_texture_t **tex_uv, - uint32_t width, uint32_t height, uint32_t flags) -{ - graphics_t *graphics = thread_graphics; - bool success = false; - - if (!gs_valid("gs_texture_create_p010")) - return false; - - if ((width & 1) == 1 || (height & 1) == 1) { - blog(LOG_ERROR, "P010 textures must have dimensions " - "divisible by 2."); - return false; - } - - if (graphics->exports.device_texture_create_p010) { - success = graphics->exports.device_texture_create_p010( - graphics->device, tex_y, tex_uv, width, height, flags); - if (success) - return true; - } - - *tex_y = gs_texture_create(width, height, GS_R16, 1, NULL, flags); - *tex_uv = gs_texture_create(width / 2, height / 2, GS_RG16, 1, NULL, - flags); - - if (!*tex_y || !*tex_uv) { - if (*tex_y) - gs_texture_destroy(*tex_y); - if (*tex_uv) - gs_texture_destroy(*tex_uv); - *tex_y = NULL; - *tex_uv = NULL; - return false; - } - - return true; -} - gs_stagesurf_t *gs_stagesurface_create_nv12(uint32_t width, uint32_t height) { graphics_t *graphics = thread_graphics; diff --git a/libobs/graphics/graphics.h b/libobs/graphics/graphics.h index 365b1575e..21c25cc17 100644 --- a/libobs/graphics/graphics.h +++ b/libobs/graphics/graphics.h @@ -857,6 +857,12 @@ EXPORT bool gs_timer_range_get_data(gs_timer_range_t *range, bool *disjoint, EXPORT bool gs_nv12_available(void); EXPORT bool gs_p010_available(void); +EXPORT bool gs_texture_create_nv12(gs_texture_t **tex_y, gs_texture_t **tex_uv, + uint32_t width, uint32_t height, + uint32_t flags); +EXPORT bool gs_texture_create_p010(gs_texture_t **tex_y, gs_texture_t **tex_uv, + uint32_t width, uint32_t height, + uint32_t flags); EXPORT bool gs_is_monitor_hdr(void *monitor); @@ -956,13 +962,6 @@ EXPORT int gs_texture_acquire_sync(gs_texture_t *tex, uint64_t key, */ EXPORT int gs_texture_release_sync(gs_texture_t *tex, uint64_t key); -EXPORT bool gs_texture_create_nv12(gs_texture_t **tex_y, gs_texture_t **tex_uv, - uint32_t width, uint32_t height, - uint32_t flags); -EXPORT bool gs_texture_create_p010(gs_texture_t **tex_y, gs_texture_t **tex_uv, - uint32_t width, uint32_t height, - uint32_t flags); - EXPORT gs_stagesurf_t *gs_stagesurface_create_nv12(uint32_t width, uint32_t height); EXPORT gs_stagesurf_t *gs_stagesurface_create_p010(uint32_t width, diff --git a/libobs/obs-encoder.h b/libobs/obs-encoder.h index 8504bd439..26d35a872 100644 --- a/libobs/obs-encoder.h +++ b/libobs/obs-encoder.h @@ -29,6 +29,9 @@ extern "C" { #endif +struct obs_encoder; +typedef struct obs_encoder obs_encoder_t; + #define OBS_ENCODER_CAP_DEPRECATED (1 << 0) #define OBS_ENCODER_CAP_PASS_TEXTURE (1 << 1) #define OBS_ENCODER_CAP_DYN_BITRATE (1 << 2) diff --git a/libobs/obs-internal.h b/libobs/obs-internal.h index c797520fa..0fc114b07 100644 --- a/libobs/obs-internal.h +++ b/libobs/obs-internal.h @@ -269,9 +269,9 @@ struct obs_core_video_mix { gs_stagesurf_t *active_copy_surfaces[NUM_TEXTURES][NUM_CHANNELS]; gs_stagesurf_t *copy_surfaces[NUM_TEXTURES][NUM_CHANNELS]; gs_texture_t *convert_textures[NUM_CHANNELS]; + gs_texture_t *convert_textures_encode[NUM_CHANNELS]; #ifdef _WIN32 gs_stagesurf_t *copy_surfaces_encode[NUM_TEXTURES]; - gs_texture_t *convert_textures_encode[NUM_CHANNELS]; #endif gs_texture_t *render_texture; gs_texture_t *output_texture; diff --git a/libobs/obs-video-gpu-encode.c b/libobs/obs-video-gpu-encode.c index 020fc34b2..4edfb2c53 100644 --- a/libobs/obs-video-gpu-encode.c +++ b/libobs/obs-video-gpu-encode.c @@ -17,8 +17,11 @@ #include "obs-internal.h" -static void *gpu_encode_thread(struct obs_core_video_mix *video) +#define NBSP "\xC2\xA0" +static const char *gpu_encode_frame_name = "gpu_encode_frame"; +static void *gpu_encode_thread(void *data) { + struct obs_core_video_mix *video = data; uint64_t interval = video_output_get_frame_time(video->video); DARRAY(obs_encoder_t *) encoders; int wait_frames = NUM_ENCODE_TEXTURE_FRAMES_TO_WAIT; @@ -26,6 +29,10 @@ static void *gpu_encode_thread(struct obs_core_video_mix *video) da_init(encoders); os_set_thread_name("obs gpu encode thread"); + const char *gpu_encode_thread_name = profile_store_name( + obs_get_profiler_name_store(), + "obs_gpu_encode_thread(%g" NBSP "ms)", interval / 1000000.); + profile_register_root(gpu_encode_thread_name, interval); while (os_sem_wait(video->gpu_encode_semaphore) == 0) { struct obs_tex_frame tf; @@ -42,6 +49,8 @@ static void *gpu_encode_thread(struct obs_core_video_mix *video) continue; } + profile_start(gpu_encode_thread_name); + os_event_reset(video->gpu_encode_inactive); /* -------------- */ @@ -125,6 +134,7 @@ static void *gpu_encode_thread(struct obs_core_video_mix *video) else next_key++; + profile_start(gpu_encode_frame_name); if (encoder->info.encode_texture2) { struct encoder_texture tex = {0}; @@ -142,6 +152,8 @@ static void *gpu_encode_thread(struct obs_core_video_mix *video) encoder->cur_pts, lock_key, &next_key, &pkt, &received); } + profile_end(gpu_encode_frame_name); + send_off_encoder_packet(encoder, success, received, &pkt); @@ -178,6 +190,9 @@ static void *gpu_encode_thread(struct obs_core_video_mix *video) obs_encoder_release(encoders.array[i]); da_resize(encoders, 0); + + profile_end(gpu_encode_thread_name); + profile_reenable_thread(); } da_free(encoders); @@ -186,7 +201,6 @@ static void *gpu_encode_thread(struct obs_core_video_mix *video) bool init_gpu_encoding(struct obs_core_video_mix *video) { -#ifdef _WIN32 const struct video_output_info *info = video_output_get_info(video->video); @@ -210,7 +224,11 @@ bool init_gpu_encoding(struct obs_core_video_mix *video) return false; } +#ifdef _WIN32 uint32_t handle = gs_texture_get_shared_handle(tex); +#else + uint32_t handle = (uint32_t)-1; +#endif struct obs_tex_frame frame = {.tex = tex, .tex_uv = tex_uv, @@ -233,10 +251,6 @@ bool init_gpu_encoding(struct obs_core_video_mix *video) video->gpu_encode_thread_initialized = true; return true; -#else - UNUSED_PARAMETER(video); - return false; -#endif } void stop_gpu_encoding_thread(struct obs_core_video_mix *video) diff --git a/libobs/obs-video.c b/libobs/obs-video.c index 11eefca60..c5ea9a3db 100644 --- a/libobs/obs-video.c +++ b/libobs/obs-video.c @@ -477,7 +477,6 @@ stage_output_texture(struct obs_core_video_mix *video, int cur_texture, profile_end(stage_output_texture_name); } -#ifdef _WIN32 static inline bool queue_frame(struct obs_core_video_mix *video, bool raw_active, struct obs_vframe_info *vframe_info) @@ -505,7 +504,9 @@ static inline bool queue_frame(struct obs_core_video_mix *video, deque_pop_front(&video->gpu_encoder_avail_queue, &tf, sizeof(tf)); if (tf.released) { +#ifdef _WIN32 gs_texture_acquire_sync(tf.tex, tf.lock_key, GS_WAIT_INFINITE); +#endif tf.released = false; } @@ -529,8 +530,10 @@ static inline bool queue_frame(struct obs_core_video_mix *video, tf.count = 1; tf.timestamp = vframe_info->timestamp; tf.released = true; +#ifdef _WIN32 tf.handle = gs_texture_get_shared_handle(tf.tex); gs_texture_release_sync(tf.tex, ++tf.lock_key); +#endif deque_push_back(&video->gpu_encoder_queue, &tf, sizeof(tf)); os_sem_post(video->gpu_encode_semaphore); @@ -570,7 +573,6 @@ static void output_gpu_encoders(struct obs_core_video_mix *video, end: profile_end(output_gpu_encoders_name); } -#endif static inline void render_video(struct obs_core_video_mix *video, bool raw_active, const bool gpu_active, @@ -590,26 +592,24 @@ static inline void render_video(struct obs_core_video_mix *video, size_t channel_count = NUM_CHANNELS; gs_texture_t *output_texture = render_output_texture(video); -#ifdef _WIN32 if (gpu_active) { convert_textures = video->convert_textures_encode; +#ifdef _WIN32 copy_surfaces = video->copy_surfaces_encode; channel_count = 1; +#endif gs_flush(); } -#endif if (video->gpu_conversion) { render_convert_texture(video, convert_textures, output_texture); } -#ifdef _WIN32 if (gpu_active) { gs_flush(); output_gpu_encoders(video, raw_active); } -#endif if (raw_active) { stage_output_texture(video, cur_texture, @@ -1014,12 +1014,10 @@ static void clear_raw_frame_data(struct obs_core_video_mix *video) deque_free(&video->vframe_info_buffer); } -#ifdef _WIN32 static void clear_gpu_frame_data(struct obs_core_video_mix *video) { deque_free(&video->vframe_info_buffer_gpu); } -#endif extern THREAD_LOCAL bool is_graphics_thread; @@ -1127,30 +1125,22 @@ static const char *output_frame_name = "output_frame"; static inline void update_active_state(struct obs_core_video_mix *video) { const bool raw_was_active = video->raw_was_active; -#ifdef _WIN32 const bool gpu_was_active = video->gpu_was_active; -#endif const bool was_active = video->was_active; bool raw_active = os_atomic_load_long(&video->raw_active) > 0; -#ifdef _WIN32 const bool gpu_active = os_atomic_load_long(&video->gpu_encoder_active) > 0; const bool active = raw_active || gpu_active; -#else - const bool active = raw_active; -#endif if (!was_active && active) clear_base_frame_data(video); if (!raw_was_active && raw_active) clear_raw_frame_data(video); -#ifdef _WIN32 if (!gpu_was_active && gpu_active) clear_gpu_frame_data(video); video->gpu_was_active = gpu_active; -#endif video->raw_was_active = raw_active; video->was_active = active; } diff --git a/libobs/obs.c b/libobs/obs.c index 105de98a0..4a8856eb3 100644 --- a/libobs/obs.c +++ b/libobs/obs.c @@ -179,7 +179,6 @@ static bool obs_init_gpu_conversion(struct obs_core_video_mix *video) video->convert_textures[0] = NULL; video->convert_textures[1] = NULL; video->convert_textures[2] = NULL; -#ifdef _WIN32 video->convert_textures_encode[0] = NULL; video->convert_textures_encode[1] = NULL; video->convert_textures_encode[2] = NULL; @@ -200,7 +199,6 @@ static bool obs_init_gpu_conversion(struct obs_core_video_mix *video) return false; } } -#endif bool success = true; @@ -297,13 +295,11 @@ static bool obs_init_gpu_conversion(struct obs_core_video_mix *video) gs_texture_destroy(video->convert_textures[c]); video->convert_textures[c] = NULL; } -#ifdef _WIN32 if (video->convert_textures_encode[c]) { gs_texture_destroy( video->convert_textures_encode[c]); video->convert_textures_encode[c] = NULL; } -#endif } } @@ -830,12 +826,10 @@ static void obs_free_render_textures(struct obs_core_video_mix *video) gs_texture_destroy(video->convert_textures[c]); video->convert_textures[c] = NULL; } -#ifdef _WIN32 if (video->convert_textures_encode[c]) { gs_texture_destroy(video->convert_textures_encode[c]); video->convert_textures_encode[c] = NULL; } -#endif } gs_texture_destroy(video->output_texture);