From c8412bbedae0fce38db96833732e8ce904721e4c Mon Sep 17 00:00:00 2001 From: Andrew Opalach Date: Sun, 30 Nov 2025 14:32:51 -0500 Subject: Build cleanup and fixes from sink testing Signed-off-by: Andrew Opalach --- src/render/meson.build | 56 +++++++++++++++------- src/render/queue_libplacebo.c | 15 +++--- src/render/renderer.h | 5 +- src/render/renderer_libplacebo.c | 100 +++++++++++++++++++++++---------------- src/render/renderer_libplacebo.h | 2 +- src/render/renderer_momo.c | 3 +- 6 files changed, 113 insertions(+), 68 deletions(-) (limited to 'src/render') diff --git a/src/render/meson.build b/src/render/meson.build index 157cd63..a7ccb58 100644 --- a/src/render/meson.build +++ b/src/render/meson.build @@ -9,11 +9,9 @@ if get_option('renderer') == 'momo' render_args += ['-DCAMU_RENDERER_MOMO'] elif get_option('renderer') == 'libplacebo' libplacebo_found = false - if 'libplacebo' not in get_option('force_fallback_for') + if 'libplacebo' not in get_option('force_fallback_for') and get_option('wrap_mode') != 'forcefallback' libplacebo = dependency('libplacebo', required: false, allow_fallback: false) - if libplacebo.found() - libplacebo_found = true - endif + libplacebo_found = libplacebo.found() endif if not libplacebo_found libplacebo_opts = ['warning_level=2', 'demos=false', 'tests=false', 'bench=false', 'fuzz=false', @@ -28,7 +26,7 @@ elif get_option('renderer') == 'libplacebo' if get_option('renderer-api') == 'vulkan' or get_option('renderer-api') == 'dx11' if get_option('renderer-compiler') == 'shaderc' shaderc_found = false - if 'shaderc' not in get_option('force_fallback_for') + if 'shaderc' not in get_option('force_fallback_for') and get_option('wrap_mode') != 'forcefallback' if is_windows shaderc = dependency('shaderc_combined', required: false, allow_fallback: false) else @@ -47,11 +45,14 @@ elif get_option('renderer') == 'libplacebo' shaderc_opts.add_cmake_defines({ 'SHADERC_SKIP_TESTS': true }) shaderc_opts.add_cmake_defines({ 'SHADERC_SKIP_EXAMPLES': true }) shaderc_opts.add_cmake_defines({ 'SHADERC_SKIP_COPYRIGHT_CHECK': true }) + # glslang shaderc_opts.add_cmake_defines({ 'ENABLE_GLSLANG_BINARIES': false }) - shaderc_opts.add_cmake_defines({ 'ENABLE_SPVREMAPPER': false }) shaderc_opts.add_cmake_defines({ 'ENABLE_HLSL': false }) + shaderc_opts.add_cmake_defines({ 'ENABLE_SPVREMAPPER': false }) + shaderc_opts.add_cmake_defines({ 'ENABLE_EXCEPTIONS': false }) spirv_optimizer = true shaderc_opts.add_cmake_defines({ 'ENABLE_OPT': spirv_optimizer }) + # spirv-tools shaderc_opts.add_cmake_defines({ 'ENABLE_EXCEPTIONS_ON_MSVC': false }) shaderc_proj = cmake.subproject('shaderc', options: shaderc_opts) shaderc = shaderc_proj.dependency('shaderc') @@ -66,9 +67,7 @@ elif get_option('renderer') == 'libplacebo' shaderc_proj.dependency('SPIRV-Tools-static') ] if spirv_optimizer - render_deps += [ - shaderc_proj.dependency('SPIRV-Tools-opt'), - ] + render_deps += [shaderc_proj.dependency('SPIRV-Tools-opt')] endif endif libplacebo_opts += ['shaderc=enabled', 'glslang=disabled'] @@ -77,19 +76,36 @@ elif get_option('renderer') == 'libplacebo' if glslang.found() render_deps += [glslang] else + # Currently does not build. + prefer_static = get_option('prefer_static') + spirv_optimizer = false + if spirv_optimizer + spirv_headers_proj = cmake.subproject('SPIRV-Headers') + spirv_headers = spirv_headers_proj.dependency('SPIRV-Headers') + spirv_tools_opts = cmake.subproject_options() + spirv_tools_opts.add_cmake_defines({ 'SPIRV-Headers_SOURCE_DIR': meson.source_root() + '/subprojects/SPIRV-Headers-b824a46' }) + spirv_tools_opts.add_cmake_defines({ 'ENABLE_EXCEPTIONS_ON_MSVC': false }) + spirv_tools_proj = cmake.subproject('SPIRV-Tools', options: spirv_tools_opts) + spirv_tools = spirv_tools_proj.dependency('SPIRV-Tools-static') + spirv_tools_opt = spirv_tools_proj.dependency('SPIRV-Tools-opt') + endif glslang_opts = cmake.subproject_options() glslang_opts.set_override_option('warning_level', '0') reltype = is_minsize ? 'MinSizeRel' : 'Release' glslang_opts.add_cmake_defines({ 'CMAKE_BUILD_TYPE': is_debug ? 'Debug' : reltype }) - spirv_optimizer = false + glslang_opts.add_cmake_defines({ 'ENABLE_GLSLANG_BINARIES': false }) + glslang_opts.add_cmake_defines({ 'ENABLE_HLSL': false }) + glslang_opts.add_cmake_defines({ 'ENABLE_SPVREMAPPER': false }) + glslang_opts.add_cmake_defines({ 'ENABLE_EXCEPTIONS': false }) glslang_opts.add_cmake_defines({ 'ENABLE_OPT': spirv_optimizer }) + glslang_opts.add_cmake_defines({ 'ALLOW_EXTERNAL_SPIRV_TOOLS': spirv_optimizer }) glslang_proj = cmake.subproject('glslang', options: glslang_opts) spirv = glslang_proj.dependency('SPIRV') glslang = glslang_proj.dependency('glslang') glslang_default_resource_limits = glslang_proj.dependency('glslang-default-resource-limits') - meson.override_dependency('SPIRV', spirv) - meson.override_dependency('glslang', glslang) - meson.override_dependency('glslang-default-resource-limits', glslang_default_resource_limits) + meson.override_dependency('SPIRV', spirv, static: prefer_static) + meson.override_dependency('glslang', glslang, static: prefer_static) + meson.override_dependency('glslang-default-resource-limits', glslang_default_resource_limits, static: prefer_static) render_deps += [ glslang_proj.dependency('MachineIndependent'), glslang_proj.dependency('OSDependent'), @@ -98,6 +114,13 @@ elif get_option('renderer') == 'libplacebo' glslang, glslang_default_resource_limits ] + if spirv_optimizer + render_deps += [ + spirv_tools, + spirv_headers, + spirv_tools_opt + ] + endif endif libplacebo_opts += ['glslang=enabled', 'shaderc=disabled'] endif @@ -140,11 +163,9 @@ endif if get_option('subtitles').enabled() libass_found = false - if 'libass' not in get_option('force_fallback_for') + if 'libass' not in get_option('force_fallback_for') and get_option('wrap_mode') != 'forcefallback' libass = dependency('libass', required: false, allow_fallback: false) - if libass.found() - libass_found = true - endif + libass_found = libass.found() endif if not libass_found libass_opts = ['test=disabled'] @@ -191,6 +212,7 @@ if get_option('subtitles').enabled() 'gobject=disabled', 'cairo=disabled', 'chafa=disabled', + 'icu=disabled', 'freetype=disabled', # This does not override yield, and yielding breaks the build if tests=enabled. # https://github.com/mesonbuild/meson/issues/5214 diff --git a/src/render/queue_libplacebo.c b/src/render/queue_libplacebo.c index c78562c..e3540c3 100644 --- a/src/render/queue_libplacebo.c +++ b/src/render/queue_libplacebo.c @@ -164,12 +164,12 @@ static struct camu_overlay *first_nonref_overlay(struct camu_frame_queue_lp *lq, static struct camu_overlay *create_subtitle_overlay(struct camu_overlay *prev, pl_gpu gpu, ASS_Image *ass_frame) { - u32 frame_count = 1; + u16 frame_count = 1; ASS_Image *head_ass_frame = ass_frame; - while (ass_frame->next) { frame_count++; ass_frame = ass_frame->next; } + while (ass_frame->next) { al_assert(frame_count < UINT16_MAX); frame_count++; ass_frame = ass_frame->next; } ass_frame = head_ass_frame; - u32 prev_alloc = prev ? prev->alloc : 0; + u16 prev_alloc = prev ? prev->alloc : 0; struct camu_overlay *overlay = camu_overlay_alloc(prev, frame_count, sizeof(struct pl_overlay) + sizeof(struct pl_overlay_part)); if (frame_count > prev_alloc) { @@ -225,9 +225,9 @@ static struct camu_overlay *create_subtitle_overlay(struct camu_overlay *prev, p }; u32 c = ass_frame->color; current_part->color[0] = (c >> 24) / 255.0; - current_part->color[1] = ((c >> 16) & 0xFF) / 255.0; - current_part->color[2] = ((c >> 8) & 0xFF) / 255.0; - current_part->color[3] = 1.0 - (c & 0xFF) / 255.0; + current_part->color[1] = ((c >> 16) & 0xff) / 255.0; + current_part->color[2] = ((c >> 8) & 0xff) / 255.0; + current_part->color[3] = 1.0 - (c & 0xff) / 255.0; current->parts = current_part; current->num_parts = 1; @@ -317,8 +317,9 @@ static bool map_av_frame(pl_gpu gpu, pl_tex *tex, const struct pl_source_frame * if (overlay) { overlay->ref++; out_frame->overlays = CAMU_OVERLAY_OFFSET(overlay, 0); - out_frame->num_overlays = overlay->num; ((struct pl_source_frame *)src)->frame_data = overlay; + } else { + out_frame->overlays = NULL; } } nn_mutex_unlock(&lq->subtitle_lock); diff --git a/src/render/renderer.h b/src/render/renderer.h index 3331baa..0eae5cb 100644 --- a/src/render/renderer.h +++ b/src/render/renderer.h @@ -30,12 +30,13 @@ enum { struct camu_overlay { u16 ref; - u32 alloc; + u16 alloc; s32 num; struct nn_mutex *lock; }; #define CAMU_OVERLAY_OFFSET(overlay, n) ((void *)(((u8 *)(overlay)) + sizeof(struct camu_overlay) + (n))) +#define CAMU_OVERLAY_FROM_HEAD(p) (struct camu_overlay *)(((u8 *)p) - sizeof(struct camu_overlay)) struct camu_frame_queue; struct camu_codec_stream; @@ -67,7 +68,7 @@ struct camu_renderer { u32 (*get_latency)(struct camu_renderer *); void (*resize)(struct camu_renderer *, u32 *, u32 *); void (*set)(struct camu_renderer *, u8, u8); - void (*render)(struct camu_renderer *, struct camu_screen *, bool); + bool (*render)(struct camu_renderer *, struct camu_screen *, bool); #ifdef CAMU_HAVE_FFMPEG s32 (*get_buffer2)(struct AVCodecContext *s, AVFrame *frame, s32 flags); void *opaque; diff --git a/src/render/renderer_libplacebo.c b/src/render/renderer_libplacebo.c index 3b69c64..01aa764 100644 --- a/src/render/renderer_libplacebo.c +++ b/src/render/renderer_libplacebo.c @@ -13,7 +13,8 @@ #include "queue_libplacebo.h" #ifdef AL_DEBUG -#define RENDERER_DEBUG 1 +// vkQueueSubmit2: VK_ERROR_VALIDATION_FAILED_EXT leads to an annoying deadlock. +#define RENDERER_DEBUG 0 #else #define RENDERER_DEBUG 0 #endif @@ -37,8 +38,11 @@ static void renderer_lp_resize(struct camu_renderer *renderer, u32 *width, u32 * struct camu_renderer_lp *lr = (struct camu_renderer_lp *)renderer; if (lr->swapchain) { if (lr->have_frame) { - pl_swapchain_submit_frame(lr->swapchain); - lr->have_frame = false; + if (pl_swapchain_submit_frame(lr->swapchain)) { + lr->have_frame = false; + } else { + log_error("Failed to submit frame on resize."); + } } pl_swapchain_resize_compat(lr->swapchain, width, height); } @@ -365,7 +369,9 @@ static inline intptr_t float_64_hash(f64 value) return hash; } -static void renderer_lp_render(struct camu_renderer *renderer, struct camu_screen *scr, bool force) + + +static bool renderer_lp_render(struct camu_renderer *renderer, struct camu_screen *scr, bool force) { struct camu_renderer_lp *lr = (struct camu_renderer_lp *)renderer; @@ -377,15 +383,14 @@ static void renderer_lp_render(struct camu_renderer *renderer, struct camu_scree if (!lr->have_frame) { struct pl_swapchain_frame frame; - if (!pl_swapchain_start_frame(lr->swapchain, &frame)) { - if (force) { - pl_swapchain_swap_buffers(lr->swapchain); - } - return; + if (pl_swapchain_start_frame(lr->swapchain, &frame)) { + pl_frame_from_swapchain(&lr->target, &frame); + pl_frame_clear_rgba(lr->gpu, &lr->target, clear_color); + lr->have_frame = true; + } else { + log_error("Failed to start frame, fatal."); + return false; } - pl_frame_from_swapchain(&lr->target, &frame); - pl_frame_clear_rgba(lr->gpu, &lr->target, clear_color); - lr->have_frame = true; } f64 mouse_x, mouse_y; @@ -405,11 +410,14 @@ static void renderer_lp_render(struct camu_renderer *renderer, struct camu_scree lr->params.hooks[0]->parameters[1].data->f = (f32)mouse_y; } + enum { + RESULT_SUBMIT = 1, + RESULT_SUBMIT_AND_WAIT = 1 << 1 + }; + + u8 result = 0; struct pl_frame *target = &lr->target; struct pl_frame_mix mix; - - bool do_gpu_finish = false; - struct camu_screen_video *video; while (scr->videos.count > 0) { bool any_eof = false; @@ -419,7 +427,7 @@ static void renderer_lp_render(struct camu_renderer *renderer, struct camu_scree // If mix.frames is NULL, read() returned QUEUE_MORE. if (mix.frames) { // weighted is only set when read() returns QUEUE_OK. - do_gpu_finish |= weighted; + result |= (1 | 1 << weighted); // Terrible hack. Lets us distinguish single frames with the same dimensions. // Tied to a libplacebo patch to consider info_priv in the hash. intptr_t hash = (intptr_t)video->buf; @@ -431,15 +439,22 @@ static void renderer_lp_render(struct camu_renderer *renderer, struct camu_scree hash += float_64_hash(video->view.fov); lr->params.hooks[0]->parameters[2].data->f = (f32)video->view.fov; } - lr->params.info_priv = (void *)hash; - target->crop = mix.frames[0]->crop; - if (!scr->subtitles_enabled) { - // This basically discards the subtitles of each frame before it's rendered. - // So, toggling the subtitles of a single frame (paused) won't work. - for (s32 j = 0; j < mix.num_frames; j++) { - ((struct pl_frame *)mix.frames[j])->num_overlays = 0; +#ifdef CAMU_HAVE_SUBTITLES + for (u32 j = 0; j < (u32)mix.num_frames; j++) { + struct pl_frame *mix_frame = (struct pl_frame *)mix.frames[j]; + if (!mix_frame->overlays) continue; + struct camu_overlay *overlay = CAMU_OVERLAY_FROM_HEAD(mix_frame->overlays); + if (!overlay->num) continue; + if (scr->subtitles_enabled) { + mix_frame->num_overlays = overlay->num; + hash += overlay->num; + } else { + mix_frame->num_overlays = 0; } } +#endif + lr->params.info_priv = (void *)hash; + target->crop = mix.frames[0]->crop; target->crop.x1 *= video->view.zoom / video->view.stretch; target->crop.y1 *= video->view.zoom * video->view.stretch; target->crop.x0 += video->view.x_offset; @@ -447,7 +462,14 @@ static void renderer_lp_render(struct camu_renderer *renderer, struct camu_scree target->crop.x1 += video->view.x_offset; target->crop.y1 += video->view.y_offset; target->rotation = video->view.rotation; - //lr->params.color_adjustment = pl_color_adjustment(.saturation = 0.0); + /* + //lr->params.color_map_params = pl_color_map_params(.inverse_tone_mapping = true); + if () { + target->color = pl_color_space_srgb; + target->color.hdr.max_luma = PL_COLOR_SDR_WHITE - 50.f; + target->color.hdr.min_luma = (PL_COLOR_SDR_WHITE - 50.f) / PL_COLOR_SDR_CONTRAST; + } + */ pl_render_image_mix(lr->renderer, &mix, target, &lr->params); } } else { @@ -468,32 +490,30 @@ static void renderer_lp_render(struct camu_renderer *renderer, struct camu_scree lr->params.hooks = NULL; lr->params.num_hooks = 0; - if (!scr->videos.count && !force) { - // Don't spin too hard on a potential error state. + // Considerations about the result of the loop above. + // 1. Any given call to video_buffer_read() may not produce a frame. + // 2. If a buffer signals EOF, by the time run_queue() happens at the bottom of the loop all + // previous buffers could have been queued for removal. Meaning, at this point, videos.count + // would be 0 while there could be data we want to display rendered to the frame. + if (!(result & RESULT_SUBMIT) && !force) { nn_thread_sleep(NNWT_TS_FROM_USEC(192)); - return; + return true; } - if (!pl_swapchain_submit_frame(lr->swapchain)) { + if (pl_swapchain_submit_frame(lr->swapchain)) { + lr->have_frame = false; + } else { log_error("Failed to submit frame, possibly fatal."); + return false; } - lr->have_frame = false; pl_swapchain_swap_buffers(lr->swapchain); - if (do_gpu_finish) { - // Block until render completes. + if (result & RESULT_SUBMIT_AND_WAIT) { pl_gpu_finish(lr->gpu); } -#if 0 - f64 tick = nn_get_tick(); - f64 frame_time = tick - lr->last_render_tick; - if (frame_time > (1.0 / 24.0)) { // 24fps is totally arbitrary. - log_info("FRAME_TIME: %fs (%.2ffps)", frame_time, 1.0 / frame_time); - } - lr->last_render_tick = tick; -#endif + return true; } void renderer_lp_free(struct camu_renderer **renderer) @@ -521,7 +541,7 @@ void renderer_lp_free(struct camu_renderer **renderer) *renderer = NULL; } -struct camu_renderer *camu_renderer_lp_create(void) +struct camu_renderer *camu_renderer_libplacebo_create(void) { struct camu_renderer_lp *lr = al_alloc_object(struct camu_renderer_lp); lr->r.create_renderer = renderer_lp_create_renderer; diff --git a/src/render/renderer_libplacebo.h b/src/render/renderer_libplacebo.h index 5d5cf9b..727e0b3 100644 --- a/src/render/renderer_libplacebo.h +++ b/src/render/renderer_libplacebo.h @@ -42,4 +42,4 @@ struct camu_renderer_lp { #endif }; -struct camu_renderer *camu_renderer_lp_create(void); +struct camu_renderer *camu_renderer_libplacebo_create(void); diff --git a/src/render/renderer_momo.c b/src/render/renderer_momo.c index 3a0e7ed..02ccaee 100644 --- a/src/render/renderer_momo.c +++ b/src/render/renderer_momo.c @@ -85,12 +85,13 @@ static u32 renderer_momo_get_latency(struct camu_renderer *renderer) return 0; } -static void renderer_momo_render(struct camu_renderer *renderer, struct camu_screen *scr, bool force) +static bool renderer_momo_render(struct camu_renderer *renderer, struct camu_screen *scr, bool force) { struct camu_renderer_momo *mr = (struct camu_renderer_momo *)renderer; (void)scr; (void)force; MOMO_Render(&mr->mmr); + return true; } static void renderer_momo_free(struct camu_renderer **renderer) -- cgit v1.2.3-101-g0448