diff options
| author | 2026-08-26 17:56:52 -0400 | |
|---|---|---|
| committer | 2026-08-26 17:56:52 -0400 | |
| commit | 197d41a3e23cab35848f623c6133baccc62aacbe (patch) | |
| tree | 04943c1de9653de53615e10ced1eab07c2562325 /src/render/renderer_libplacebo.c | |
| parent | 6094c907b26e21f13373bae6bf3306dbae40af3c (diff) | |
| download | camu-197d41a3e23cab35848f623c6133baccc62aacbe.tar.gz camu-197d41a3e23cab35848f623c6133baccc62aacbe.tar.bz2 camu-197d41a3e23cab35848f623c6133baccc62aacbe.zip | |
OSD stuff and Android fixes
Signed-off-by: Andrew Opalach <andrew@akon.city>
Diffstat (limited to 'src/render/renderer_libplacebo.c')
| -rw-r--r-- | src/render/renderer_libplacebo.c | 300 |
1 files changed, 265 insertions, 35 deletions
diff --git a/src/render/renderer_libplacebo.c b/src/render/renderer_libplacebo.c index d6f95a8..8c28162 100644 --- a/src/render/renderer_libplacebo.c +++ b/src/render/renderer_libplacebo.c @@ -2,15 +2,21 @@ //#define AL_LOG_ENABLE_TRACE #include <al/log.h> #include <al/lib.h> +#include <al/math.h> #include <nnwt/file.h> #include <nnwt/time.h> +#include <libplacebo/shaders.h> #include "../screen/screen.h" #include "../util/color_palette.h" +#include "../util/print_time.h" #include "renderer_libplacebo.h" #include "queue_libplacebo.h" +#include "shaders/osd_header.h" +#include "shaders/osd.h" +#include "shaders/osd_binds.h" #include "shaders/vr_video.h" #ifdef AL_DEBUG @@ -21,14 +27,18 @@ #endif #define CRT_BACKGROUND -#define CRT_BACKGROUND_COLOR (1.f / 7.5f) -#define CRT_BACKGROUND_COLOR_ON (0.025f) +#define CRT_BACKGROUND_COLOR(c4) do { \ + c4[0] = 0.1333f; c4[1] = 0.1333f; c4[2] = 0.1333f; \ +} while (0) +#define CRT_BACKGROUND_COLOR_ON(lr, c4) do { \ + if (lr->params.background != PL_CLEAR_SKIP) { \ + c4[0] = 0.025f; c4[1] = 0.025f; c4[2] = 0.025f; \ + } else { \ + c4[0] = 0.f; c4[1] = 0.f; c4[2] = 0.f; \ + } \ +} while (0) -#ifdef CRT_BACKGROUND -static f32 clear_color[4] = { CRT_BACKGROUND_COLOR, CRT_BACKGROUND_COLOR, CRT_BACKGROUND_COLOR, 1.f }; -#else static f32 clear_color[4] = { 0.f, 0.f, 0.f, 1.f }; -#endif static struct pl_render_params default_params; @@ -62,13 +72,14 @@ static void renderer_lp_set(struct camu_renderer *renderer, u8 option, u8 value) { struct camu_renderer_lp *lr = (struct camu_renderer_lp *)renderer; switch (option) { - case CAMU_RENDERER_FULLSCREEN: + case CAMU_RENDERER_FULLSCREEN: { #ifdef STELA_API_DX11 IDXGISwapChain *d3d_swapchain = pl_d3d11_swapchain_unwrap(lr->swapchain); IDXGISwapChain_SetFullscreenState(d3d_swapchain, value, NULL); IDXGISwapChain_Release(d3d_swapchain); #endif break; + } case CAMU_RENDERER_SCALING: switch (value) { case CAMU_SCALING_DEFAULT: @@ -106,7 +117,7 @@ static void log_callback(void *userdata, enum pl_log_level level, const char *me // will be shot anyway so allow it. log_info(message); } else { - log_debug(message); + log_info(message); } } @@ -136,7 +147,7 @@ static bool renderer_lp_create_renderer(struct camu_renderer *renderer, u32 *wid VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL (*get_vk_proc_address)(VkInstance, const char *), VkResult (*vk_create_surface)(void *, VkInstance, VkSurfaceKHR *), VkResult (*vk_destroy_surface)(VkInstance, VkSurfaceKHR), - const char *const *(*vk_get_extensions)(u32 *), + const char * const *(*vk_get_extensions)(u32 *), #elif defined STELA_API_DX11 HWND win32_window, #elif defined STELA_API_OPENGL @@ -174,7 +185,7 @@ static bool renderer_lp_create_renderer(struct camu_renderer *renderer, u32 *wid lr->vk_destroy_surface = vk_destroy_surface; u32 num; - const char *const *extensions = vk_get_extensions(&num); + const char * const *extensions = vk_get_extensions(&num); lr->vk_inst = pl_vk_inst_create(lr->logger, pl_vk_inst_params( .debug = RENDERER_DEBUG, .get_proc_addr = get_vk_proc_address, @@ -229,7 +240,7 @@ static bool renderer_lp_create_renderer(struct camu_renderer *renderer, u32 *wid // https://learn.microsoft.com/en-us/windows/win32/api/dxgi/ne-dxgi-dxgi_swap_chain_flag // https://learn.microsoft.com/en-us/windows/win32/api/dxgi/ne-dxgi-dxgi_swap_effect char *FLIP = getenv("SINK_DXGI_FLIP"); - if (!FLIP) FLIP = "0"; + if (!FLIP) FLIP = "1"; lr->swapchain = pl_d3d11_create_swapchain(lr->d3d11, pl_d3d11_swapchain_params( .window = win32_window, .blit = al_strscmp(FLIP, "0") == 0, @@ -280,6 +291,22 @@ static bool renderer_lp_create_renderer(struct camu_renderer *renderer, u32 *wid log_info("Using OpenGL."); #endif +#ifdef USE_LIBPLACEBO_CACHE + lr->cache = pl_cache_create(pl_cache_params( + .log = lr->logger, + .max_total_size = MB(50) + )); + pl_gpu_set_cache(lr->gpu, lr->cache); + FILE *cache_file = fopen("sink.cache", "rb"); + if (cache_file) { + pl_cache_load_file(lr->cache, cache_file); + //p->cache_sig = pl_cache_signature(p->cache); + fclose(cache_file); + } +#endif + + lr->dispatch = pl_dispatch_create(lr->gpu->log, lr->gpu); + lr->renderer = pl_renderer_create(lr->logger, lr->gpu); pl_swapchain_resize_compat(lr->swapchain, width, height); @@ -291,6 +318,7 @@ static bool renderer_lp_create_renderer(struct camu_renderer *renderer, u32 *wid al_memset(&lr->params, 0, sizeof(struct pl_render_params)); lr->params = default_params; + lr->params.deband_params = NULL; //lr->params.frame_mixer = NULL; @@ -302,16 +330,79 @@ static bool renderer_lp_create_renderer(struct camu_renderer *renderer, u32 *wid // Prioritize a more consistent image. lr->params.correct_subpixel_offsets = true; - //lr->params.distort_params = pl_distort_params(.unscaled = false); - lr->vr_emulation_hook[0] = pl_mpv_user_shader_parse(lr->gpu, vr_video_shader, sizeof(vr_video_shader) - 1); - /* + lr->osd.vars[0].var = pl_var_uvec2("screen"); + lr->osd.vars[1].var = pl_var_uint("scale"); + lr->osd.vars[2].var = pl_var_float("time"); + lr->osd.vars[3].var = pl_var_uint("show_osd"); + lr->osd.vars[4].var = pl_var_uint("connecting"); + lr->osd.vars[5].var = pl_var_uint("paused"); + lr->osd.vars[6].var = pl_var_uint("bar_mode"); + lr->osd.vars[7].var = pl_var_float("bar"); + lr->osd.vars[8].var = pl_var_float("dbar"); + lr->osd.vars[9].var = pl_var_float("bbar"); + lr->osd.vars[10].var = pl_var_uint("show_hour"); + lr->osd.vars[11].var = pl_var_uint("negative"); + static const char num_names[9][6] = { + "num1", "num2", "num3", "num4", + "num5", "num6", "num7", "num8", + "num9" + }; + for (u32 i = 0; i < 9; i++) { + lr->osd.vars[12 + i].var = pl_var_uint(num_names[i]); + } + for (u32 i = 0; i < 21; i++) { + lr->osd.vars[i].dynamic = true; + } + + lr->osd.attribs[0] = (struct pl_vertex_attrib){ + .name = "pos", + .offset = 0, + .fmt = pl_find_vertex_fmt(lr->gpu, PL_FMT_FLOAT, 2) + }; + lr->osd.attribs[1] = (struct pl_vertex_attrib){ + .name = "coord", + .offset = sizeof(f32) * 2, + .fmt = pl_find_vertex_fmt(lr->gpu, PL_FMT_FLOAT, 2) + }; + + al_memcpy(lr->osd.vertices, (f32[]){ + 1.f, 1.f, 1.f, 1.f, + -1.f, -1.f, 0.f, 0.f, + -1.f, 1.f, 0.f, 1.f, + -1.f, -1.f, 0.f, 0.f, + 1.f, -1.f, 1.f, 0.f, + 1.f, 1.f, 1.f, 1.f, + }, sizeof(f32) * 24); + + lr->osd.prelude = osd_header_shader; + lr->osd.header = osd_shader; + lr->osd.binds = osd_binds_shader; +#if 0 struct nn_file file; - if (nn_file_open(&file, &al_str_c(""), 0)) { + if (nn_file_open(&file, &al_str_c("../src/render/shaders/osd_header.glsl"), 0)) { + char *c_str; + nn_file_read_as_c_str(&file, &c_str); + lr->osd.prelude = c_str; + nn_file_close(&file); + } + if (nn_file_open(&file, &al_str_c("../src/render/shaders/osd.glsl"), 0)) { char *c_str; - size_t length = nn_file_read_as_c_str(&file, &c_str); - const struct pl_hook *hook = pl_mpv_user_shader_parse(lr->gpu, (const char *)c_str, length); + nn_file_read_as_c_str(&file, &c_str); + lr->osd.header = c_str; + nn_file_close(&file); } - */ + if (nn_file_open(&file, &al_str_c("../src/render/shaders/osd_binds.glsl"), 0)) { + char *c_str; + nn_file_read_as_c_str(&file, &c_str); + lr->osd.binds = c_str; + nn_file_close(&file); + } +#endif + lr->osd.tick_time = -1.0; + lr->osd.logged_fail = false; + + lr->vr_init_failed = false; + lr->vr_emulation_hook[0] = NULL; #ifdef CAMU_HAVE_FFMPEG lr->r.get_buffer2 = pl_get_buffer2; @@ -385,6 +476,125 @@ static inline intptr_t float_64_hash(f64 value) return hash; } +#define ROUND_SECONDS(h, m, s, n) do { \ + if (n >= 50) { \ + if (s == 59) { \ + if (m == 59) { \ + h++; \ + m = 0; \ + } else m++; \ + s = 0; \ + } else s++; \ + } \ +} while (0) + +static inline bool render_osd(struct camu_renderer_lp *lr, struct camu_screen *scr) +{ + f64 duration = scr->osd.duration / 1000000.0; + f32 bar, dbar, bbar; + f32 progress = ((duration != 0) ? scr->osd.pts / duration : 0.f); + if (scr->osd.bar_mode != CAMU_OSD_BAR_VOLUME) { + dbar = progress; + bbar = dbar; // @TODO: Should be buffered, once that's supported in the VCR. + } else { + dbar = 0.f; + bbar = 0.f; + } + bar = (scr->osd.bar_mode == CAMU_OSD_BAR_PROGRESS) ? progress : scr->osd.bar; + lr->osd.screen_size[0] = scr->width; + lr->osd.screen_size[1] = scr->height; + lr->osd.vars[0].data = lr->osd.screen_size; + u32 scale = 1; + lr->osd.vars[1].data = &scale; + f64 tick = nn_get_tick(); + if (lr->osd.tick_time == -1.0) lr->osd.tick_time = tick; + lr->osd.time = (f32)(tick - lr->osd.tick_time); + lr->osd.vars[2].data = &lr->osd.time; + lr->osd.vars[3].data = &scr->osd.show; + lr->osd.vars[4].data = &scr->osd.connecting; + lr->osd.vars[5].data = &scr->osd.paused; + lr->osd.vars[6].data = &scr->osd.bar_mode; + lr->osd.vars[7].data = &bar; + lr->osd.vars[8].data = &dbar; + lr->osd.vars[9].data = &bbar; + u32 hours1, minutes1, seconds1, hundredths; + u32 show_hour; + show_hour = camu_split_time(scr->osd.duration, &hours1, &minutes1, &seconds1, &hundredths); + ROUND_SECONDS(hours1, minutes1, seconds1, hundredths); + lr->osd.vars[10].data = &show_hour; + u32 negative; + negative = scr->osd.pts < 0.0f; + lr->osd.vars[11].data = &negative; + lr->osd.vars[15].data = &hours1; + lr->osd.vars[16].data = &minutes1; + lr->osd.vars[17].data = &seconds1; + u32 hours2, minutes2, seconds2; + camu_split_time(fabs(scr->osd.pts) * 1000000u, &hours2, &minutes2, &seconds2, &hundredths); + // The trade-off of rounding PTS is that if we do, second 0 will be shown for only half a second. + // If we don't, more noticeably, PTS will never equal duration if duration rounds up. + // There's also the option of not rounding either. + ROUND_SECONDS(hours2, minutes2, seconds2, hundredths); + lr->osd.vars[12].data = &hours2; + lr->osd.vars[13].data = &minutes2; + lr->osd.vars[14].data = &seconds2; + u32 zero = 0; + lr->osd.vars[18].data = &zero; + lr->osd.vars[19].data = &zero; + lr->osd.vars[20].data = &zero; + if (scr->osd.bar_mode == CAMU_OSD_BAR_SEEK) { + u32 hours3, minutes3, seconds3; + camu_split_time(fabs(duration * bar) * 1000000u, &hours3, &minutes3, &seconds3, &hundredths); + ROUND_SECONDS(hours3, minutes3, seconds3, hundredths); + lr->osd.vars[18].data = &hours3; + lr->osd.vars[19].data = &minutes3; + lr->osd.vars[20].data = &seconds3; + } else { + f64 whole = floor(bar); + f64 frac = (bar - whole) * 100.0; + u32 num1, num2; + num1 = (u32)whole; + num2 = (u32)round(frac); + lr->osd.vars[19].data = &num1; + lr->osd.vars[20].data = &num2; + } + + lr->osd.sh = pl_dispatch_begin(lr->dispatch); + pl_shader_custom(lr->osd.sh, &(struct pl_custom_shader){ + .description = "osd", + .prelude = lr->osd.prelude, + .header = scr->osd.show_binds ? lr->osd.binds : lr->osd.header, + .body = "color = (show_osd == 0u) ? vec4(0.) : draw_osd();", + .output = PL_SHADER_SIG_COLOR, + .num_variables = 21, + .variables = lr->osd.vars + }); + + struct pl_color_repr repr = lr->frame.color_repr; + pl_shader_color_map_ex(lr->osd.sh, NULL, pl_color_map_args( + .src = pl_color_space_srgb, + .dst = lr->frame.color_space + )); + pl_shader_encode_color(lr->osd.sh, &repr); + + struct pl_dispatch_vertex_params params = { 0 }; + params = *pl_dispatch_vertex_params( + .shader = &lr->osd.sh, + .target = lr->frame.fbo, + .blend_params = &pl_alpha_overlay, + .vertex_attribs = lr->osd.attribs, + .num_vertex_attribs = 2, + .vertex_stride = sizeof(f32) * 4, + .vertex_position_idx = 0, + .vertex_coords = PL_COORDS_NORMALIZED, + .vertex_flipped = lr->frame.flipped, + .vertex_type = PL_PRIM_TRIANGLE_LIST, + .vertex_count = 6, + .vertex_data = lr->osd.vertices + ); + + return pl_dispatch_vertex(lr->dispatch, ¶ms); +} + 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; @@ -396,9 +606,8 @@ static bool renderer_lp_render(struct camu_renderer *renderer, struct camu_scree #endif if (!lr->have_frame) { - struct pl_swapchain_frame frame; - if (pl_swapchain_start_frame(lr->swapchain, &frame)) { - pl_frame_from_swapchain(&lr->target, &frame); + if (pl_swapchain_start_frame(lr->swapchain, &lr->frame)) { + pl_frame_from_swapchain(&lr->target, &lr->frame); lr->have_frame = true; #ifdef CRT_BACKGROUND lr->frame_cleared = false; @@ -413,7 +622,15 @@ static bool renderer_lp_render(struct camu_renderer *renderer, struct camu_scree } f64 mouse_x, mouse_y; - bool vr_emulation = scr->vr_emulation && lr->vr_emulation_hook[0]; + bool vr_emulation = scr->vr_emulation && !lr->vr_init_failed; + if (vr_emulation && !lr->vr_emulation_hook[0]) { + lr->vr_emulation_hook[0] = pl_mpv_user_shader_parse(lr->gpu, vr_video_shader, sizeof(vr_video_shader) - 1); + lr->vr_init_failed = !lr->vr_emulation_hook[0]; + if (lr->vr_init_failed) { + log_error("Failed to compile VR emulation shader."); + vr_emulation = false; + } + } if (vr_emulation) { mouse_x = (scr->last_pointer_x / scr->width) - (scr->vr_calibrate_x - 0.5); mouse_y = (scr->last_pointer_y / scr->height) - (scr->vr_calibrate_y - 0.5); @@ -484,8 +701,8 @@ static bool 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 = mix.frames[0]->rotation - video->view.rotation; - /* //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; @@ -494,15 +711,7 @@ static bool renderer_lp_render(struct camu_renderer *renderer, struct camu_scree */ #ifdef CRT_BACKGROUND if (!lr->frame_cleared) { - if (lr->params.background != PL_CLEAR_SKIP) { - clear_color[0] = CRT_BACKGROUND_COLOR_ON; - clear_color[1] = CRT_BACKGROUND_COLOR_ON; - clear_color[2] = CRT_BACKGROUND_COLOR_ON; - } else { - clear_color[0] = 0.f; - clear_color[1] = 0.f; - clear_color[2] = 0.f; - } + CRT_BACKGROUND_COLOR_ON(lr, clear_color); pl_frame_clear_rgba(lr->gpu, &lr->target, clear_color); lr->frame_cleared = true; } @@ -539,14 +748,20 @@ static bool renderer_lp_render(struct camu_renderer *renderer, struct camu_scree #ifdef CRT_BACKGROUND if (!lr->frame_cleared) { - clear_color[0] = CRT_BACKGROUND_COLOR; - clear_color[1] = CRT_BACKGROUND_COLOR; - clear_color[2] = CRT_BACKGROUND_COLOR; + CRT_BACKGROUND_COLOR(clear_color); pl_frame_clear_rgba(lr->gpu, &lr->target, clear_color); lr->frame_cleared = true; } #endif + if (scr->osd.show || (result & RESULT_WAIT)) { + al_assert(lr->osd.prelude && lr->osd.header && lr->osd.binds); + if (!render_osd(lr, scr) && !lr->osd.logged_fail) { + log_error("Failed to render OSD."); + lr->osd.logged_fail = true; + } + } + if (pl_swapchain_submit_frame(lr->swapchain)) { lr->have_frame = false; } else { @@ -571,10 +786,25 @@ static bool renderer_lp_render(struct camu_renderer *renderer, struct camu_scree void renderer_lp_free(struct camu_renderer **renderer) { struct camu_renderer_lp *lr = (struct camu_renderer_lp *)*renderer; + if (lr->have_frame) { + pl_swapchain_submit_frame(lr->swapchain); + lr->have_frame = false; + } #ifdef CAMU_HAVE_SUBTITLES if (lr->ass) ass_library_done(lr->ass); #endif if (lr->vr_emulation_hook[0]) pl_mpv_user_shader_destroy(&lr->vr_emulation_hook[0]); +#ifdef USE_LIBPLACEBO_CACHE + if (lr->cache) { + FILE *cache_file = fopen("sink.cache", "wb"); + if (cache_file) { + pl_cache_save_file(lr->cache, cache_file); + fclose(cache_file); + } + pl_cache_destroy(&lr->cache); + } +#endif + if (lr->dispatch) pl_dispatch_destroy(&lr->dispatch); if (lr->renderer) pl_renderer_destroy(&lr->renderer); if (lr->swapchain) pl_swapchain_destroy(&lr->swapchain); #if defined STELA_API_VULKAN |