From a48a68cfb04b2020737c0adfb0e7667451a22b5c Mon Sep 17 00:00:00 2001 From: Andrew Opalach Date: Mon, 6 Nov 2023 11:54:08 -0500 Subject: Add camu - Subprojects temporarily omitted Signed-off-by: Andrew Opalach --- src/render/meson.build | 35 +++++ src/render/queue_libplacebo.c | 195 +++++++++++++++++++++++++ src/render/queue_libplacebo.h | 17 +++ src/render/queue_tiger.c | 92 ++++++++++++ src/render/queue_tiger.h | 13 ++ src/render/renderer.h | 45 ++++++ src/render/renderer_libplacebo.c | 237 ++++++++++++++++++++++++++++++ src/render/renderer_libplacebo.h | 38 +++++ src/render/renderer_tiger.c | 305 +++++++++++++++++++++++++++++++++++++++ src/render/renderer_tiger.h | 31 ++++ 10 files changed, 1008 insertions(+) create mode 100644 src/render/meson.build create mode 100644 src/render/queue_libplacebo.c create mode 100644 src/render/queue_libplacebo.h create mode 100644 src/render/queue_tiger.c create mode 100644 src/render/queue_tiger.h create mode 100644 src/render/renderer.h create mode 100644 src/render/renderer_libplacebo.c create mode 100644 src/render/renderer_libplacebo.h create mode 100644 src/render/renderer_tiger.c create mode 100644 src/render/renderer_tiger.h (limited to 'src/render') diff --git a/src/render/meson.build b/src/render/meson.build new file mode 100644 index 0000000..cc11eea --- /dev/null +++ b/src/render/meson.build @@ -0,0 +1,35 @@ +render_src = [] +render_deps = [common_deps] + +#linmath = subproject('linmath.h').get_variable('linmath') +#libm = compiler.find_library('m', required: false) +#if libm.found() +# render_deps += [libm] +#endif +#render_src += ['renderer_tiger.c', 'queue_tiger.c'] +#render_deps += [linmath] + +libplacebo = dependency('libplacebo', + default_options: [ + 'warning_level=2', + 'demos=false', + 'tests=false', + 'bench=false', + 'fuzz=false', + 'shaderc=enabled', + 'glslang=disabled', + 'opengl=enabled', + 'vulkan=disabled', + 'd3d11=disabled', + 'gl-proc-addr=disabled', + 'vk-proc-addr=disabled', + 'lcms=disabled', + 'dovi=disabled', + 'libdovi=disabled' + ], required: false, allow_fallback: true) +if libplacebo.found() + render_src += ['renderer_libplacebo.c', 'queue_libplacebo.c'] + render_deps += [libplacebo] +endif + +render = declare_dependency(sources: render_src, dependencies: render_deps) diff --git a/src/render/queue_libplacebo.c b/src/render/queue_libplacebo.c new file mode 100644 index 0000000..ee64920 --- /dev/null +++ b/src/render/queue_libplacebo.c @@ -0,0 +1,195 @@ +#include +#include + +#include "../buffer/video.h" + +#include "queue_libplacebo.h" + +static bool map_frame(pl_gpu gpu, pl_tex *tex, const struct pl_source_frame *src, + struct pl_frame *out_frame) +{ + struct camu_frame *frame = src->frame_data; + + u64 masks[4] = { 0x000000ff, 0x0000ff00, 0x00ff0000, 0xff000000 }; + s32 pixel_stride = 4; + + /* + switch (frame->fmt) { + case CAMU_PIXEL_FMT_RGBA: + break; + default: + al_log_error("frame_queue_libplacebo", "Unsuppored pixel format."); + return false; + } + */ + + struct pl_plane_data data = { + .type = PL_FMT_UNORM, + .width = frame->width, + .height = frame->height, + .pixel_stride = pixel_stride, + .row_stride = frame->width * pixel_stride, + .pixels = frame->data + }; + + pl_plane_data_from_mask(&data, masks); + + struct pl_plane plane = { 0 }; + bool ok = pl_upload_plane(gpu, &plane, tex, &data); + + al_free(frame); + + if (!ok) { + al_log_error("frame_queue_libplacebo", "Failed to upload texture."); + return false; + } + + out_frame->num_planes = 1; + out_frame->planes[0] = plane; + out_frame->repr = pl_color_repr_unknown; + out_frame->color = pl_color_space_unknown; + out_frame->crop = (pl_rect2df){ 0, 0, frame->width, frame->height }; + //out_frame->profile = + + return true; +} + +static void unmap_frame(pl_gpu gpu, struct pl_frame *frame, const struct pl_source_frame *src) +{ + (void)gpu; + (void)frame; + (void)src; +} + +static void discard_frame(const struct pl_source_frame *src) +{ + struct camu_frame *frame = src->frame_data; + al_free(frame); +} + +static void queue_lp_push(struct camu_frame_queue *queue, struct camu_frame *frame, f64 pts) +{ + struct camu_frame_queue_lp *lq = (struct camu_frame_queue_lp *)queue; + pl_queue_push(lq->queue, &(struct pl_source_frame){ + .pts = pts, + .duration = 0.0, + .map = map_frame, + .unmap = unmap_frame, + .discard = discard_frame, + .frame_data = frame, + }); +} + +#ifdef HAVE_FFMPEG +static bool map_av_frame(pl_gpu gpu, pl_tex *tex, const struct pl_source_frame *src, + struct pl_frame *out_frame) +{ + AVFrame *frame = src->frame_data; + struct camu_video_buffer *buf = frame->opaque; + AVStream *stream = buf->stream->av.stream; + + bool ok = pl_map_avframe_ex(gpu, out_frame, pl_avframe_params( + .frame = frame, + .tex = tex, + .map_dovi = false + )); + + av_frame_free(&frame); + + if (!ok) { + al_log_error("frame_queue_libplacebo", "Failed to map AVFrame."); + return false; + } + + pl_frame_copy_stream_props(out_frame, stream); + + return true; +} + +static void unmap_av_frame(pl_gpu gpu, struct pl_frame *frame, const struct pl_source_frame *src) +{ + (void)src; + pl_unmap_avframe(gpu, frame); +} + +static void discard_av_frame(const struct pl_source_frame *src) +{ + AVFrame *frame = src->frame_data; + av_frame_free(&frame); + al_log_info("frame_queue_libplacebo", "Dropped frame with PTS %.3f.", src->pts); +} + +static void queue_lp_push_av_frame(struct camu_frame_queue *queue, AVFrame *frame, f64 pts) +{ + struct camu_frame_queue_lp *lq = (struct camu_frame_queue_lp *)queue; + struct camu_video_buffer *buf = frame->opaque; + pl_queue_push(lq->queue, &(struct pl_source_frame){ + .pts = pts, + .duration = buf->avg_frame_duration, + .map = map_av_frame, + .unmap = unmap_av_frame, + .discard = discard_av_frame, + .frame_data = frame, + .first_field = pl_field_from_avframe(frame) + }); +} +#endif + +static void queue_lp_flush(struct camu_frame_queue *queue) +{ + struct camu_frame_queue_lp *lq = (struct camu_frame_queue_lp *)queue; + pl_queue_push(lq->queue, NULL); +} + +static s32 queue_lp_count(struct camu_frame_queue *queue) +{ + struct camu_frame_queue_lp *lq = (struct camu_frame_queue_lp *)queue; + return pl_queue_num_frames(lq->queue); +} + +static u8 queue_lp_read(struct camu_frame_queue *queue, f64 pts, void *out) +{ + struct camu_frame_queue_lp *lq = (struct camu_frame_queue_lp *)queue; + lq->params.pts = pts; + switch (pl_queue_update(lq->queue, (struct pl_frame_mix *)out, &lq->params)) { + case PL_QUEUE_OK: + return CAMU_QUEUE_OK; + case PL_QUEUE_MORE: + return CAMU_QUEUE_MORE; + case PL_QUEUE_EOF: + return CAMU_QUEUE_EOF; + case PL_QUEUE_ERR: + default: + return CAMU_QUEUE_ERR; + } +} + +static void queue_lp_reset(struct camu_frame_queue *queue) +{ + struct camu_frame_queue_lp *lq = (struct camu_frame_queue_lp *)queue; + pl_queue_push(lq->queue, NULL); + pl_queue_reset(lq->queue); +} + +static void queue_lp_free(struct camu_frame_queue **queue) +{ + struct camu_frame_queue_lp *lq = (struct camu_frame_queue_lp *)*queue; + pl_queue_destroy(&lq->queue); + al_free(lq); + *queue = NULL; +} + +struct camu_frame_queue *camu_frame_queue_lp_create(void) +{ + struct camu_frame_queue_lp *lq = al_alloc_object(struct camu_frame_queue_lp); + lq->q.push = queue_lp_push; +#ifdef HAVE_FFMPEG + lq->q.push_av_frame = queue_lp_push_av_frame; +#endif + lq->q.flush = queue_lp_flush; + lq->q.count = queue_lp_count; + lq->q.read = queue_lp_read; + lq->q.reset = queue_lp_reset; + lq->q.free = queue_lp_free; + return (struct camu_frame_queue *)lq; +} diff --git a/src/render/queue_libplacebo.h b/src/render/queue_libplacebo.h new file mode 100644 index 0000000..7da99ca --- /dev/null +++ b/src/render/queue_libplacebo.h @@ -0,0 +1,17 @@ +#pragma once + +#include "../buffer/frame_queue.h" + +#include +#include +#ifdef HAVE_FFMPEG +#include +#endif + +struct camu_frame_queue_lp { + struct camu_frame_queue q; + pl_queue queue; + struct pl_queue_params params; +}; + +struct camu_frame_queue *camu_frame_queue_lp_create(void); diff --git a/src/render/queue_tiger.c b/src/render/queue_tiger.c new file mode 100644 index 0000000..575b826 --- /dev/null +++ b/src/render/queue_tiger.c @@ -0,0 +1,92 @@ +#include + +#include "renderer_tiger.h" +#include "queue_tiger.h" + +static void upload_texture(struct camu_frame_queue_tiger *tq, s32 width, s32 height, + u8 *data, s32 linesize) +{ + glGenTextures(1, &tq->texture_id); + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D, tq->texture_id); + //glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 0); + //glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + //if (frame->flags & CAMU_FRAME_DEVICE_ALLOCATED) { + // glBindBuffer(GL_PIXEL_UNPACK_BUFFER, tq->tr->texture_buffer); + //} + //if (linesize) { + // glPixelStorei(GL_UNPACK_ROW_LENGTH, linesize); + //} + (void)linesize; + //glPixelStorei(GL_UNPACK_ROW_LENGTH, linesize); + glPixelStorei(GL_UNPACK_ALIGNMENT, 1); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, data); + //glGenerateMipmap(GL_TEXTURE_2D); +} + +static void queue_tiger_push(struct camu_frame_queue *queue, struct camu_frame *frame, f64 pts) +{ + struct camu_frame_queue_tiger *tq = (struct camu_frame_queue_tiger *)queue; + (void)pts; + upload_texture(tq, frame->width, frame->height, frame->data, 0); +} + +#ifdef HAVE_FFMPEG +static void queue_tiger_push_av_frame(struct camu_frame_queue *queue, AVFrame *frame, f64 pts) +{ + struct camu_frame_queue_tiger *tq = (struct camu_frame_queue_tiger *)queue; + (void)pts; + upload_texture(tq, frame->width, frame->height, frame->data[0], frame->linesize[0]); +} +#endif + +static void queue_tiger_flush(struct camu_frame_queue *queue) +{ + (void)queue; +} + +static s32 queue_tiger_count(struct camu_frame_queue *queue) +{ + struct camu_frame_queue_tiger *tq = (struct camu_frame_queue_tiger *)queue; + (void)tq; + return 1; +} + +static u8 queue_tiger_read(struct camu_frame_queue *queue, f64 pts, void *out) +{ + struct camu_frame_queue_tiger *tq = (struct camu_frame_queue_tiger *)queue; + (void)pts; + *((GLuint *)out) = tq->texture_id; + return CAMU_QUEUE_OK; +} + +static void queue_tiger_reset(struct camu_frame_queue *queue) +{ + struct camu_frame_queue_tiger *tq = (struct camu_frame_queue_tiger *)queue; + (void)tq; +} + +static void queue_tiger_free(struct camu_frame_queue **queue) +{ + struct camu_frame_queue_tiger *tq = (struct camu_frame_queue_tiger *)*queue; + glDeleteTextures(1, &tq->texture_id); + al_free(tq); + *queue = NULL; +} + +struct camu_frame_queue *camu_frame_queue_tiger_create(void) +{ + struct camu_frame_queue_tiger *tq = al_alloc_object(struct camu_frame_queue_tiger); + tq->q.push = queue_tiger_push; +#ifdef HAVE_FFMPEG + tq->q.push_av_frame = queue_tiger_push_av_frame; +#endif + tq->q.flush = queue_tiger_flush; + tq->q.count = queue_tiger_count; + tq->q.read = queue_tiger_read; + tq->q.reset = queue_tiger_reset; + tq->q.free = queue_tiger_free; + return (struct camu_frame_queue *)tq; +} diff --git a/src/render/queue_tiger.h b/src/render/queue_tiger.h new file mode 100644 index 0000000..1524a29 --- /dev/null +++ b/src/render/queue_tiger.h @@ -0,0 +1,13 @@ +#pragma once + +#include + +#include "../buffer/frame_queue.h" + +struct camu_frame_queue_tiger { + struct camu_frame_queue q; + GLuint texture_id; + struct camu_renderer_tiger *tr; +}; + +struct camu_frame_queue *camu_frame_queue_tiger_create(void); diff --git a/src/render/renderer.h b/src/render/renderer.h new file mode 100644 index 0000000..61965ed --- /dev/null +++ b/src/render/renderer.h @@ -0,0 +1,45 @@ +#pragma once + +#include +#include +#ifdef HAVE_FFMPEG +#include +#endif + +#include "../buffer/frame_queue.h" + +#if defined SEKIHI_API_OPENGL +#define CAMU_RENDERER_OPENGL +#elif defined SEKIHI_API_VULKAN +#define CAMU_RENDERER_VULKAN +#endif + +struct camu_screen; +struct camu_renderer { + bool (*create_renderer)( + struct camu_renderer *, s32 *, s32 *, + bool (*poll)(struct skh_window *, bool), +#if defined CAMU_RENDERER_VULKAN + VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL (*get_vk_proc_address)(VkInstance, const char *), + VkResult (*vk_create_surface)(void *, VkInstance, VkSurfaceKHR *), + const char *const *(*vk_get_extensions)(u32 *), +#elif defined CAMU_RENDERER_OPENGL + void (*get_gl_proc_address(char const *procname))(void), + bool (*gl_load_loader)(void *), + bool (*gl_make_current)(void *), + void (*gl_release_current)(void *), + void (*gl_swap_buffers)(void *), +#elif defined CAMU_RENDERER_DX11 +#endif + void *priv); + struct camu_frame_queue *(*create_queue)(struct camu_renderer *); + void (*resize)(struct camu_renderer *, s32 *, s32 *); + void (*render)(struct camu_renderer *, struct camu_screen *); +#ifdef HAVE_FFMPEG + s32 (*get_buffer2)(struct AVCodecContext *s, AVFrame *frame, s32 flags); + void *opaque; +#endif + void *(*get_device_ptr)(struct camu_renderer *, size_t); + void (*commit_device_ptr)(struct camu_renderer *); + void (*free)(struct camu_renderer **); +}; diff --git a/src/render/renderer_libplacebo.c b/src/render/renderer_libplacebo.c new file mode 100644 index 0000000..019a5ce --- /dev/null +++ b/src/render/renderer_libplacebo.c @@ -0,0 +1,237 @@ +#include +#include +#include + +#include "../screen/screen.h" +#include "../util/color_palette.h" + +#include "renderer_libplacebo.h" +#include "queue_libplacebo.h" + +static f32 clear_color[4] = { 0.0f, 0.0f, 0.0f, 1.f }; + +static void renderer_lp_resize(struct camu_renderer *renderer, s32 *width, s32 *height) +{ + struct camu_renderer_lp *lr = (struct camu_renderer_lp *)renderer; + if (lr->swapchain) pl_swapchain_resize(lr->swapchain, width, height); +} + +static bool renderer_lp_create_renderer(struct camu_renderer *renderer, s32 *width, s32 *height, + bool (*poll)(struct skh_window *, bool), +#if defined CAMU_RENDERER_VULKAN + VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL (*get_vk_proc_address)(VkInstance, const char *), + VkResult (*vk_create_surface)(void *, VkInstance, VkSurfaceKHR *), + const char *const *(*vk_get_extensions)(u32 *), +#elif defined CAMU_RENDERER_OPENGL + void (*get_gl_proc_address(char const *procname))(void), + bool (*gl_load_loader)(void *), + bool (*gl_make_current)(void *), + void (*gl_release_current)(void *), + void (*gl_swap_buffers)(void *), +#endif + void *priv) +{ + struct camu_renderer_lp *lr = (struct camu_renderer_lp *)renderer; + + clear_color[0] = ((global_color_palette.colors[0] >> 16) & 0xff) / 255.f; + clear_color[1] = ((global_color_palette.colors[0] >> 8) & 0xff) / 255.f; + clear_color[2] = ((global_color_palette.colors[0]) & 0xff) / 255.f; + + lr->logger = pl_log_create(PL_API_VER, pl_log_params( + .log_cb = pl_log_color, + .log_level = PL_LOG_NONE, +// .log_level = PL_LOG_INFO, + )); + +#if defined CAMU_RENDERER_VULKAN + VkResult err; + + u32 num; + lr->vk_inst = pl_vk_inst_create(lr->logger, pl_vk_inst_params( + .get_proc_addr = get_vk_proc_address, + .debug = false, + .extensions = vk_get_extensions(&num), + .num_extensions = num, + )); + + if (!lr->vk_inst) { + al_log_error("render_libplacebo", "Failed to create vulkan instance."); + } + + err = vk_create_surface(priv, lr->vk_inst->instance, &lr->surface); + if (err != VK_SUCCESS) { + al_log_error("render_libplacebo", "Failed to create vulkan surface."); + } + + lr->vk = pl_vulkan_create(lr->logger, pl_vulkan_params( + .allow_software = true, + .instance = lr->vk_inst->instance, + .get_proc_addr = lr->vk_inst->get_proc_addr, + .surface = lr->surface + )); + + if (!lr->vk) { + al_log_error("render_libplacebo", "Failed to create vulkan device."); + } + + lr->swapchain = pl_vulkan_create_swapchain(lr->vk, pl_vulkan_swapchain_params( + .surface = lr->surface, + .present_mode = VK_PRESENT_MODE_FIFO_KHR + )); + + if (!lr->swapchain) { + al_log_error("render_libplacebo", "Failed to create vulkan swapchain."); + } + + lr->gpu = lr->vk->gpu; +#elif defined CAMU_RENDERER_OPENGL + (void)gl_load_loader; + lr->gl = pl_opengl_create(lr->logger, pl_opengl_params( + .allow_software = true, + .debug = false, + .make_current = gl_make_current, + .release_current = gl_release_current, + .get_proc_addr = get_gl_proc_address, + .get_proc_addr_ex = NULL, + .priv = priv, + )); + + if (!lr->gl) { + al_log_error("render_libplacebo", "Failed to create GL device."); + } + + lr->swapchain = pl_opengl_create_swapchain(lr->gl, pl_opengl_swapchain_params( + .swap_buffers = gl_swap_buffers, + .priv = priv + )); + + if (!lr->swapchain) { + al_log_error("render_libplacebo", "Failed to create GL swapchain."); + } + + lr->gpu = lr->gl->gpu; +#endif + + lr->renderer = pl_renderer_create(lr->logger, lr->gpu); + + renderer_lp_resize(renderer, width, height); + +#define PRE_SWAPS 2 + // See renderer_tiger.c:122. + for (u32 i = 0; i < PRE_SWAPS; i++) { + poll(priv, true); + struct pl_swapchain_frame frame; + pl_swapchain_start_frame(lr->swapchain, &frame); + struct pl_frame target; + pl_frame_from_swapchain(&target, &frame); + pl_frame_clear_rgba(lr->gpu, &target, clear_color); + pl_swapchain_submit_frame(lr->swapchain); + pl_swapchain_swap_buffers(lr->swapchain); + } + + al_memset(&lr->params, 0, sizeof(struct pl_render_params)); + lr->params = pl_render_default_params; + //lr->params = pl_render_high_quality_params; + lr->params.upscaler = &pl_filter_bicubic; + // Clear manually so we can draw multiple images per frame. + lr->params.skip_target_clearing = true; + lr->params.skip_caching_single_frame = true; + +#if 0 + struct aki_file file; + if (aki_file_open(&file, al_str_c(""))) { + char *str; + size_t len = aki_file_read_as_c_str(&file, &str); + const struct pl_hook *hook = pl_mpv_user_shader_parse(lr->gpu, (const char *)str, len); + const struct pl_hook **hooks = al_malloc(sizeof(struct pl_hook *)); + hooks[0] = al_malloc(sizeof(struct pl_hook)); + al_memcpy((void *)hooks[0], (void *)hook, sizeof(struct pl_hook)); + lr->params.hooks = hooks; + lr->params.num_hooks = 1; + } +#endif + +#ifdef HAVE_FFMPEG + //lr->r.get_buffer2 = pl_get_buffer2; + //lr->r.opaque = &lr->gpu; +#endif + + return true; +} + +static struct camu_frame_queue *renderer_lp_create_queue(struct camu_renderer *renderer) +{ + struct camu_renderer_lp *lr = (struct camu_renderer_lp *)renderer; + struct camu_frame_queue *queue = camu_frame_queue_lp_create(); + struct camu_frame_queue_lp *lq = (struct camu_frame_queue_lp *)queue; + lq->queue = pl_queue_create(lr->gpu); + al_memset(&lq->params, 0, sizeof(struct pl_queue_params)); + lq->params.interpolation_threshold = 0.01; + lq->params.radius = pl_frame_mix_radius(&lr->params); + lq->params.timeout = 0; // vsync + return queue; +} + +static void renderer_lp_render(struct camu_renderer *renderer, struct camu_screen *scr) +{ + struct camu_renderer_lp *lr = (struct camu_renderer_lp *)renderer; + + struct pl_swapchain_frame frame; + pl_swapchain_start_frame(lr->swapchain, &frame); + + struct pl_frame target; + pl_frame_from_swapchain(&target, &frame); + +#ifdef CAMU_SCREEN_THREADED + if (al_atomic_bool_load(&scr->queued, AL_ATOMIC_RELAXED)) { + camu_screen_run_queue(scr); + } +#endif + + pl_frame_clear_rgba(lr->gpu, &target, clear_color); + + struct pl_frame_mix mix; + if (scr->videos.size > 0) { + struct camu_screen_video *video = &al_array_last(scr->videos); + //al_array_foreach_ptr(scr->videos, i, video) { + if (camu_video_buffer_read(video->buf, &mix) && mix.frames) { + target.crop = mix.frames[0]->crop; + target.crop.x1 *= video->view.zoom; + target.crop.y1 *= video->view.zoom; + target.crop.x0 += video->view.x_offset; + target.crop.y0 += video->view.y_offset; + target.crop.x1 += video->view.x_offset; + target.crop.y1 += video->view.y_offset; + pl_render_image_mix(lr->renderer, &mix, &target, &lr->params); + } + //} + } + + pl_swapchain_submit_frame(lr->swapchain); + pl_swapchain_swap_buffers(lr->swapchain); +} + +static void renderer_lp_free(struct camu_renderer **renderer) +{ + struct camu_renderer_lp *lr = (struct camu_renderer_lp *)*renderer; + if (lr->renderer) pl_renderer_destroy(&lr->renderer); + if (lr->swapchain) pl_swapchain_destroy(&lr->swapchain); +#if defined CAMU_RENDERER_VULKAN +#elif defined CAMU_RENDERER_OPENGL + if (lr->gl) pl_opengl_destroy(&lr->gl); +#endif + if (lr->logger) pl_log_destroy(&lr->logger); + al_free(lr); + *renderer = NULL; +} + +struct camu_renderer *camu_renderer_lp_create(void) +{ + struct camu_renderer_lp *lr = al_alloc_object(struct camu_renderer_lp); + lr->r.create_renderer = renderer_lp_create_renderer; + lr->r.create_queue = renderer_lp_create_queue; + lr->r.resize = renderer_lp_resize; + lr->r.render = renderer_lp_render; + lr->r.free = renderer_lp_free; + return (struct camu_renderer *)lr; +} diff --git a/src/render/renderer_libplacebo.h b/src/render/renderer_libplacebo.h new file mode 100644 index 0000000..661faff --- /dev/null +++ b/src/render/renderer_libplacebo.h @@ -0,0 +1,38 @@ +#pragma once + +#include +#include +#include +#include +#include + +#include "renderer.h" + +#if defined CAMU_RENDERER_VULKAN +#include +#endif + +struct camu_renderer_lp_resource { + pl_tex tex; + struct pl_plane plane; +}; + +struct camu_renderer_lp { + struct camu_renderer r; +#if defined CAMU_RENDERER_VULKAN + VkSurfaceKHR surface; + pl_vulkan vk; + pl_vk_inst vk_inst; +#elif defined CAMU_RENDERER_OPENGL + pl_opengl gl; +#endif + pl_gpu gpu; + pl_log logger; + pl_swapchain swapchain; + pl_renderer renderer; + struct pl_render_params params; + struct pl_overlay overlays[10]; + s32 overlay_count; +}; + +struct camu_renderer *camu_renderer_lp_create(void); diff --git a/src/render/renderer_tiger.c b/src/render/renderer_tiger.c new file mode 100644 index 0000000..7cbbbb9 --- /dev/null +++ b/src/render/renderer_tiger.c @@ -0,0 +1,305 @@ +#include +#include +#include + +#include "../screen/view.h" +#include "../screen/screen.h" +#include "../util/color_palette.h" + +#include "renderer_tiger.h" +#include "queue_tiger.h" + +#ifdef CAMU_RENDERER_OPENGL +static const GLfloat default_vertices[] = { + 0.f, 0.f, 0.f, 0.f, 0.f, + 0.f, 1.f, 0.f, 0.f, 1.f, + 1.f, 0.f, 0.f, 1.f, 0.f, + 1.f, 0.f, 0.f, 1.f, 0.f, + 0.f, 1.f, 0.f, 0.f, 1.f, + 1.f, 1.f, 0.f, 1.f, 1.f +}; + +static f32 clear_color[4] = { 0.0f, 0.0f, 0.0f, 1.f }; + +static const GLchar *default_vs = \ + "#version 100\n" \ + "attribute vec3 a_Position;\n" \ + "attribute vec2 a_TexCoord;\n" \ + "varying vec2 v_TexCoord;\n" \ + "uniform mat4 g_ModelViewProjectionMatrix;\n" \ + "void main() {\n" \ + " gl_Position = g_ModelViewProjectionMatrix * vec4(a_Position, 1.0);\n" \ + " v_TexCoord = a_TexCoord;\n" \ + "}"; + +static const GLchar *default_fs = \ + "#version 100\n" \ + "precision mediump float;\n" \ + "varying vec2 v_TexCoord;\n" \ + "uniform sampler2D g_Texture0;\n" \ + "void main() {\n" \ + " gl_FragColor = texture2D(g_Texture0, v_TexCoord);\n" \ + "}"; + +static bool compile(GLuint shader, const GLchar *source, GLchar *error) +{ + glShaderSource(shader, 1, &source, 0); + glCompileShader(shader); + + GLint status; + + glGetShaderiv(shader, GL_COMPILE_STATUS, &status); + + if (status == GL_FALSE) { + glGetShaderInfoLog(shader, 256, NULL, error); + return false; + } + + return true; +} + +static bool compile_shaders(struct camu_renderer_tiger *tr) +{ + tr->program = glCreateProgram(); + + GLchar error[256]; + + GLuint vs_shader = glCreateShader(GL_VERTEX_SHADER); + if (!compile(vs_shader, default_vs, error)) { + al_log_error("render_tiger", "Failed to compile vertex shader (%.*s)", + sizeof(error), error); + return false; + } + + GLuint fs_shader = glCreateShader(GL_FRAGMENT_SHADER); + if (!compile(fs_shader, default_fs, error)) { + al_log_error("render_tiger", "Failed to compile fragment shader (%.*s)", + sizeof(error), error); + return false; + } + + glAttachShader(tr->program, vs_shader); + glAttachShader(tr->program, fs_shader); + glLinkProgram(tr->program); + + return true; +} +#endif + +static void renderer_tiger_resize(struct camu_renderer *renderer, s32 *width, s32 *height) +{ + struct camu_renderer_tiger *tr = (struct camu_renderer_tiger *)renderer; + (void)tr; +#ifdef CAMU_RENDERER_OPENGL + glViewport(0, 0, *width, *height); +#endif +} + +static bool renderer_tiger_create_renderer(struct camu_renderer *renderer, s32 *width, s32 *height, + bool (*poll)(struct skh_window *, bool), +#if defined CAMU_RENDERER_VULKAN + VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL (*get_vk_proc_address)(VkInstance, const char *), + void (*vk_create_surface)(void *, VkInstance, VkSurfaceKHR *), + const char *const *(*vk_get_extensions)(u32 *), +#elif defined CAMU_RENDERER_OPENGL + void (*get_gl_proc_address(char const *procname))(void), + bool (*gl_load_loader)(void *), + bool (*gl_make_current)(void *), + void (*gl_release_current)(void *), + void (*gl_swap_buffers)(void *), +#endif + void *priv) +{ + struct camu_renderer_tiger *tr = (struct camu_renderer_tiger *)renderer; +#ifdef CAMU_RENDERER_OPENGL + (void)get_gl_proc_address; + + tr->load_loader = gl_load_loader; + tr->make_current = gl_make_current; + tr->release_current = gl_release_current; + tr->swap_buffers = gl_swap_buffers; + tr->priv = priv; + + tr->make_current(tr->priv); + + if (!tr->load_loader(tr->priv)) return false; + + renderer_tiger_resize(renderer, width, height); + + clear_color[0] = ((global_color_palette.colors[0] >> 16) & 0xff) / 255.f; + clear_color[1] = ((global_color_palette.colors[0] >> 8) & 0xff) / 255.f; + clear_color[2] = ((global_color_palette.colors[0]) & 0xff) / 255.f; + + glClearColor(clear_color[0], clear_color[1], clear_color[2], 1.f); + +#define PRE_SWAPS 2 + // Hack? to make the window appear quicker. Only tested on linux/wayland. + for (u32 i = 0; i < PRE_SWAPS; i++) { + poll(priv, true); + glClear(GL_COLOR_BUFFER_BIT); + tr->swap_buffers(tr->priv); + } + + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + + glGenBuffers(1, &tr->vbo); + glBindBuffer(GL_ARRAY_BUFFER, tr->vbo); + glBufferData(GL_ARRAY_BUFFER, sizeof(default_vertices), default_vertices, GL_STATIC_DRAW); + + if (!compile_shaders(tr)) return false; + + glUseProgram(tr->program); + + GLint pos = glGetAttribLocation(tr->program, "a_Position"); + glVertexAttribPointer(pos, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(GLfloat), (void *)0); + glEnableVertexAttribArray(pos); + GLint texcoord = glGetAttribLocation(tr->program, "a_TexCoord"); + glVertexAttribPointer(texcoord, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(GLfloat), (void *)12); + glEnableVertexAttribArray(texcoord); + + //glGenBuffers(1, &tr->texture_buffer); +#endif + +#ifdef HAVE_FFMPEG + tr->r.get_buffer2 = NULL; + tr->r.opaque = NULL; +#endif + + return true; +} + +static struct camu_frame_queue *renderer_tiger_create_queue(struct camu_renderer *renderer) +{ +#ifdef CAMU_RENDERER_OPENGL + struct camu_renderer_tiger *tr = (struct camu_renderer_tiger *)renderer; + struct camu_frame_queue *q = camu_frame_queue_tiger_create(); + struct camu_frame_queue_tiger *tq = (struct camu_frame_queue_tiger *)q; + tq->tr = tr; + return q; +#endif +} + +static void set_uniform(struct camu_renderer_tiger *tr, const GLchar *name, + u8 type, void *value) +{ +#ifdef CAMU_RENDERER_OPENGL + GLint loc = glGetUniformLocation(tr->program, name); + if (loc == -1) return; + + switch (type) + { + case TYPE_FLOAT: + glUniform1f(loc, *((GLfloat *)value)); + break; + case TYPE_SAMPLER2D: + glUniform1i(loc, (GLuint)(*((GLfloat *)value))); + break; + case TYPE_VEC2: + glUniform2fv(loc, 1, (GLfloat *)value); + break; + case TYPE_VEC3: + glUniform3fv(loc, 1, (GLfloat *)value); + break; + case TYPE_VEC4: + glUniform4fv(loc, 1, (GLfloat *)value); + break; + case TYPE_MAT4: + glUniformMatrix4fv(loc, 1, GL_FALSE, (GLfloat *)value); + break; + case TYPE_MAT3: + glUniformMatrix3fv(loc, 1, GL_FALSE, (GLfloat *)value); + break; + case TYPE_INVALID: + break; + } +#endif +} + +#ifdef CAMU_RENDERER_OPENGL +static mat4x4 model; +static GLuint texture0 = 0; +#endif + +static void renderer_tiger_render(struct camu_renderer *renderer, struct camu_screen *scr) +{ +#ifdef CAMU_RENDERER_OPENGL + struct camu_renderer_tiger *tr = (struct camu_renderer_tiger *)renderer; + + glClear(GL_COLOR_BUFFER_BIT); + + glUseProgram(tr->program); + glBindBuffer(GL_ARRAY_BUFFER, tr->vbo); + glActiveTexture(GL_TEXTURE0); + +#ifdef CAMU_SCREEN_THREADED + if (al_atomic_bool_load(&scr->queued, AL_ATOMIC_RELAXED)) { + camu_screen_run_queue(scr); + } +#endif + + if (scr->videos.size > 0) { + struct camu_screen_video *video = &al_array_last(scr->videos); + + GLuint texture_id; + camu_video_buffer_read(video->buf, &texture_id); + glBindTexture(GL_TEXTURE_2D, texture_id); + + mat4x4_ortho(model, 0.f, (f32)scr->width, (f32)scr->height, 0.f, -1.f, 1.f); + mat4x4_translate_in_place(model, (f32)video->view.x_offset, (f32)video->view.y_offset, 0.f); + mat4x4_scale_aniso(model, model, (f32)video->view.zoom, (f32)video->view.zoom, 1.f); + mat4x4_scale_aniso(model, model, (f32)video->view.width, (f32)video->view.height, 1.f); + set_uniform(tr, "g_ModelViewProjectionMatrix", TYPE_MAT4, model); + set_uniform(tr, "g_Texture0", TYPE_SAMPLER2D, &texture0); + + glDrawArrays(GL_TRIANGLES, 0, 6); + } + + tr->swap_buffers(tr->priv); +#endif +} + +static void *renderer_tiger_get_device_ptr(struct camu_renderer *renderer, size_t length) +{ + (void)renderer; + (void)length; + return NULL; +#ifdef CAMU_RENDERER_OPENGL + //struct camu_renderer_tiger *tr = (struct camu_renderer_tiger *)renderer; + //glBindBuffer(GL_PIXEL_UNPACK_BUFFER, tr->texture_buffer); + //glBufferData(GL_PIXEL_UNPACK_BUFFER, length, NULL, GL_STREAM_DRAW); + //return glMapBufferRange(GL_PIXEL_UNPACK_BUFFER, 0, length, GL_MAP_WRITE_BIT); +#endif +} + +static void renderer_tiger_commit_device_ptr(struct camu_renderer *renderer) +{ + (void)renderer; +#ifdef CAMU_RENDERER_OPENGL + //struct camu_renderer_tiger *tr = (struct camu_renderer_tiger *)renderer; + //glBindBuffer(GL_PIXEL_UNPACK_BUFFER, tr->texture_buffer); + //glUnmapBuffer(GL_PIXEL_UNPACK_BUFFER); +#endif +} + +static void renderer_tiger_free(struct camu_renderer **renderer) +{ + struct camu_renderer_tiger *tr = (struct camu_renderer_tiger *)*renderer; + glDeleteProgram(tr->program); + glDeleteBuffers(1, &tr->vbo); + al_free(tr); + *renderer = NULL; +} + +struct camu_renderer *camu_renderer_tiger_create(void) +{ + struct camu_renderer_tiger *tr = al_alloc_object(struct camu_renderer_tiger); + tr->r.create_renderer = renderer_tiger_create_renderer; + tr->r.create_queue = renderer_tiger_create_queue; + tr->r.resize = renderer_tiger_resize; + tr->r.render = renderer_tiger_render; + tr->r.get_device_ptr = renderer_tiger_get_device_ptr; + tr->r.commit_device_ptr = renderer_tiger_commit_device_ptr; + tr->r.free = renderer_tiger_free; + return (struct camu_renderer *)tr; +} diff --git a/src/render/renderer_tiger.h b/src/render/renderer_tiger.h new file mode 100644 index 0000000..e9a7eb0 --- /dev/null +++ b/src/render/renderer_tiger.h @@ -0,0 +1,31 @@ +#pragma once + +#include + +#include "renderer.h" + +enum { + TYPE_INVALID = 0, + TYPE_FLOAT, + TYPE_VEC4, + TYPE_VEC3, + TYPE_VEC2, + TYPE_MAT4, + TYPE_MAT3, + TYPE_SAMPLER2D +}; + +struct camu_renderer_tiger { + struct camu_renderer r; + GLuint vao; + GLuint vbo; + GLuint program; + GLuint texture_buffer; + bool (*load_loader)(void *); + bool (*make_current)(void *); + void (*release_current)(void *); + void (*swap_buffers)(void *); + void *priv; +}; + +struct camu_renderer *camu_renderer_tiger_create(void); -- cgit v1.2.3-101-g0448