diff options
Diffstat (limited to '')
-rw-r--r-- | demos/sdlimage.c | 281 |
1 files changed, 281 insertions, 0 deletions
diff --git a/demos/sdlimage.c b/demos/sdlimage.c new file mode 100644 index 0000000..87e6d03 --- /dev/null +++ b/demos/sdlimage.c @@ -0,0 +1,281 @@ +/* Simple image viewer that opens an image using SDL2_image and presents it + * to the screen. + * + * License: CC0 / Public Domain + */ + +#include <SDL_image.h> + +#include "common.h" +#include "window.h" + +#include <libplacebo/renderer.h> +#include <libplacebo/shaders/lut.h> +#include <libplacebo/utils/upload.h> + +// Static configuration, done in the file to keep things simple +static const char *icc_profile = ""; // path to ICC profile +static const char *lut_file = ""; // path to .cube lut + +// Program state +static pl_log logger; +static struct window *win; + +// For rendering +static pl_tex img_tex; +static pl_tex osd_tex; +static struct pl_plane img_plane; +static struct pl_plane osd_plane; +static pl_renderer renderer; +static struct pl_custom_lut *lut; + +struct file +{ + void *data; + size_t size; +}; + +static struct file icc_file; + +static bool open_file(const char *path, struct file *out) +{ + if (!path || !path[0]) { + *out = (struct file) {0}; + return true; + } + + FILE *fp = NULL; + bool success = false; + + fp = fopen(path, "rb"); + if (!fp) + goto done; + + if (fseeko(fp, 0, SEEK_END)) + goto done; + off_t size = ftello(fp); + if (size < 0) + goto done; + if (fseeko(fp, 0, SEEK_SET)) + goto done; + + void *data = malloc(size); + if (!fread(data, size, 1, fp)) + goto done; + + *out = (struct file) { + .data = data, + .size = size, + }; + + success = true; +done: + if (fp) + fclose(fp); + return success; +} + +static void close_file(struct file *file) +{ + if (!file->data) + return; + + free(file->data); + *file = (struct file) {0}; +} + +SDL_NORETURN static void uninit(int ret) +{ + pl_renderer_destroy(&renderer); + pl_tex_destroy(win->gpu, &img_tex); + pl_tex_destroy(win->gpu, &osd_tex); + close_file(&icc_file); + pl_lut_free(&lut); + + window_destroy(&win); + pl_log_destroy(&logger); + exit(ret); +} + +static bool upload_plane(const SDL_Surface *img, pl_tex *tex, + struct pl_plane *plane) +{ + if (!img) + return false; + + SDL_Surface *fixed = NULL; + const SDL_PixelFormat *fmt = img->format; + if (SDL_ISPIXELFORMAT_INDEXED(fmt->format)) { + // libplacebo doesn't handle indexed formats yet + fixed = SDL_CreateRGBSurfaceWithFormat(0, img->w, img->h, 32, + SDL_PIXELFORMAT_ABGR8888); + SDL_BlitSurface((SDL_Surface *) img, NULL, fixed, NULL); + img = fixed; + fmt = img->format; + } + + struct pl_plane_data data = { + .type = PL_FMT_UNORM, + .width = img->w, + .height = img->h, + .pixel_stride = fmt->BytesPerPixel, + .row_stride = img->pitch, + .pixels = img->pixels, + }; + + uint64_t masks[4] = { fmt->Rmask, fmt->Gmask, fmt->Bmask, fmt->Amask }; + pl_plane_data_from_mask(&data, masks); + + bool ok = pl_upload_plane(win->gpu, plane, tex, &data); + SDL_FreeSurface(fixed); + return ok; +} + +static bool render_frame(const struct pl_swapchain_frame *frame) +{ + pl_tex img = img_plane.texture; + struct pl_frame image = { + .num_planes = 1, + .planes = { img_plane }, + .repr = pl_color_repr_unknown, + .color = pl_color_space_unknown, + .crop = {0, 0, img->params.w, img->params.h}, + }; + + // This seems to be the case for SDL2_image + image.repr.alpha = PL_ALPHA_INDEPENDENT; + + struct pl_frame target; + pl_frame_from_swapchain(&target, frame); + target.profile = (struct pl_icc_profile) { + .data = icc_file.data, + .len = icc_file.size, + }; + + image.rotation = PL_ROTATION_0; // for testing + pl_rect2df_aspect_copy_rot(&target.crop, &image.crop, 0.0, image.rotation); + + struct pl_overlay osd; + struct pl_overlay_part osd_part; + if (osd_tex) { + osd_part = (struct pl_overlay_part) { + .src = { 0, 0, osd_tex->params.w, osd_tex->params.h }, + .dst = { 0, 0, osd_tex->params.w, osd_tex->params.h }, + }; + osd = (struct pl_overlay) { + .tex = osd_tex, + .mode = PL_OVERLAY_NORMAL, + .repr = image.repr, + .color = image.color, + .coords = PL_OVERLAY_COORDS_DST_FRAME, + .parts = &osd_part, + .num_parts = 1, + }; + target.overlays = &osd; + target.num_overlays = 1; + } + + // Use the heaviest preset purely for demonstration/testing purposes + struct pl_render_params params = pl_render_high_quality_params; + params.lut = lut; + + return pl_render_image(renderer, &image, &target, ¶ms); +} + +int main(int argc, char **argv) +{ + if (argc < 2 || argc > 3) { + fprintf(stderr, "Usage: %s <image> [<overlay>]\n", argv[0]); + return 255; + } + + const char *file = argv[1]; + const char *overlay = argc > 2 ? argv[2] : NULL; + logger = pl_log_create(PL_API_VER, pl_log_params( + .log_cb = pl_log_color, + .log_level = PL_LOG_INFO, + )); + + + // Load image, do this first so we can use it for the window size + SDL_Surface *img = IMG_Load(file); + if (!img) { + fprintf(stderr, "Failed loading '%s': %s\n", file, SDL_GetError()); + uninit(1); + } + + // Create window + unsigned int start = SDL_GetTicks(); + win = window_create(logger, &(struct window_params) { + .title = "SDL2_image demo", + .width = img->w, + .height = img->h, + }); + if (!win) + uninit(1); + + // Initialize rendering state + if (!upload_plane(img, &img_tex, &img_plane)) { + fprintf(stderr, "Failed uploading image plane!\n"); + uninit(2); + } + SDL_FreeSurface(img); + + if (overlay) { + SDL_Surface *osd = IMG_Load(overlay); + if (!upload_plane(osd, &osd_tex, &osd_plane)) + fprintf(stderr, "Failed uploading OSD plane.. continuing anyway\n"); + SDL_FreeSurface(osd); + } + + if (!open_file(icc_profile, &icc_file)) + fprintf(stderr, "Failed opening ICC profile.. continuing anyway\n"); + + struct file lutf; + if (open_file(lut_file, &lutf) && lutf.size) { + if (!(lut = pl_lut_parse_cube(logger, lutf.data, lutf.size))) + fprintf(stderr, "Failed parsing LUT.. continuing anyway\n"); + close_file(&lutf); + } + + renderer = pl_renderer_create(logger, win->gpu); + + unsigned int last = SDL_GetTicks(), frames = 0; + printf("Took %u ms for initialization\n", last - start); + + // Render loop + while (!win->window_lost) { + struct pl_swapchain_frame frame; + bool ok = pl_swapchain_start_frame(win->swapchain, &frame); + if (!ok) { + window_poll(win, true); + continue; + } + + if (!render_frame(&frame)) { + fprintf(stderr, "libplacebo: Failed rendering frame!\n"); + uninit(3); + } + + ok = pl_swapchain_submit_frame(win->swapchain); + if (!ok) { + fprintf(stderr, "libplacebo: Failed submitting frame!\n"); + uninit(3); + } + + pl_swapchain_swap_buffers(win->swapchain); + frames++; + + unsigned int now = SDL_GetTicks(); + if (now - last > 5000) { + printf("%u frames in %u ms = %f FPS\n", frames, now - last, + 1000.0f * frames / (now - last)); + last = now; + frames = 0; + } + + window_poll(win, false); + } + + uninit(0); +} |