Commit 34decaab authored by Niklas Haas's avatar Niklas Haas
Browse files

demos: modularize windowing backend

Instead of compiling all variants of all demos, load the best backend at
runtime. Also split off the nuklear implementation into a separate
library to avoid excessively recompiling it, something that should have
been done ages ago.

This is technically a functionality downgrade, since it doesn't allow
users to choose which backend to use (Vulkan or OpenGL), instead always
picking the "best" backend. But that's mostly interesting for
developers, not users, I think.

I'll probably implement some mechanism for making that selection at
runtime, when I actually need it.

As an aside, I also renamed 'image' to 'sdlimage' since I think the name
fits better - the only reason I didn't in the past was to avoid
confusion with the suffix.
parent 3ab959cd
......@@ -10,3 +10,5 @@
#include <libplacebo/context.h>
#include <libplacebo/renderer.h>
#include "config_demos.h"
......@@ -16,74 +16,91 @@ endforeach
nuklear_inc = include_directories('./3rdparty/nuklear')
nuklear_found = cc.has_header('nuklear.h', include_directories: nuklear_inc)
nuklear = declare_dependency(
sources: 'ui.c',
include_directories: nuklear_inc,
compile_args: ['-Wno-missing-prototypes', '-DHAVE_UI'],
dependencies: libm,
if nuklear_found
nuklear_lib = static_library('nuklear',
include_directories: nuklear_inc,
c_args: ['-O2', '-Wno-missing-prototypes'],
dependencies: [ libplacebo, libm ],
sources: 'ui.c',
)
nuklear = declare_dependency(
include_directories: nuklear_inc,
link_with: nuklear_lib,
)
else
warning('Nuklear was not found in `demos/3rdparty`. Please run ' +
'`git submodule update --init` followed by `meson --wipe`.')
endif
conf_demos = configuration_data()
conf_demos.set('HAVE_NUKLEAR', nuklear_found)
conf_demos.set('HAVE_GLFW', glfw.found())
conf_demos.set('HAVE_SDL', sdl.found())
configure_file(
output: 'config_demos.h',
configuration: conf_demos,
)
apis = {}
apis = []
# Enable all supported combinations of API and windowing system
if glfw.found()
if vulkan.found()
apis += {'glfw-vk': declare_dependency(
sources: 'window_glfw.c',
compile_args: '-DUSE_VK',
apis += static_library('glfw-vk',
dependencies: [libplacebo, vulkan, glfw],
)}
sources: 'window_glfw.c',
c_args: '-DUSE_VK',
)
endif
if opengl.found()
apis += {'glfw-gl': declare_dependency(
sources: 'window_glfw.c',
compile_args: '-DUSE_GL',
apis += static_library('glfw-gl',
dependencies: [libplacebo, glfw],
)}
sources: 'window_glfw.c',
c_args: '-DUSE_GL',
)
endif
endif
if sdl.found()
if vulkan.found()
apis += {'sdl-vk': declare_dependency(
sources: 'window_sdl.c',
compile_args: '-DUSE_VK',
apis += static_library('sdl-vk',
dependencies: [libplacebo, vulkan, sdl],
)}
sources: 'window_sdl.c',
c_args: '-DUSE_VK',
)
endif
if opengl.found()
apis += {'sdl-gl': declare_dependency(
sources: 'window_sdl.c',
compile_args: '-DUSE_GL',
apis += static_library('sdl-gl',
dependencies: [libplacebo, sdl],
)}
sources: 'window_sdl.c',
c_args: '-DUSE_GL',
)
endif
endif
if apis.keys().length() == 0
if apis.length() == 0
warning('Demos enabled but no supported combination of windowing system ' +
'and graphical APIs was found. Demo programs require either GLFW or ' +
'SDL and either Vulkan or OpenGL.')
subdir_done()
endif
if not nuklear_found
warning('Nuklear was not found in `demos/3rdparty`. Please run ' +
'`git submodule update --init` followed by `meson --wipe`. ' +
'Disabling nuklear based demos.')
endif
'SDL and either Vulkan or OpenGL to function.')
else
# Compile demos for each combination
foreach api, dep : apis
dep = declare_dependency(
dependencies: libplacebo,
sources: 'window.c',
link_with: apis,
)
executable('colors-' + api, 'colors.c',
# Graphical demo programs
executable('colors', 'colors.c',
dependencies: [ dep, libm ],
)
if sdl_image.found()
executable('image-' + api, 'image.c',
executable('sdlimage', 'sdlimage.c',
dependencies: [ dep, sdl_image ],
)
endif
......@@ -93,15 +110,16 @@ foreach api, dep : apis
if nuklear_found
plplay_deps += nuklear
endif
executable('plplay-' + api, 'plplay.c', dependencies: plplay_deps)
executable('plplay', 'plplay.c', dependencies: plplay_deps)
endif
if nuklear_found
executable('nuklear-' + api, 'nuklear.c',
executable('nuklear', 'nuklear.c',
dependencies: [ dep, nuklear ],
)
endif
endforeach
endif
# Headless video filtering demo
if vulkan.found()
......
/* Trivial UI demo, very unfinished. Currently just lets you change the
* background color of the window and nothing else.
/* Trivial UI demo, very basic. Currently just lets you change the background
* color of the window and nothing else. See `plplay.c` for a more complete UI.
*
* License: CC0 / Public Domain
*/
......
......@@ -20,7 +20,7 @@
#include "common.h"
#include "window.h"
#ifdef HAVE_UI
#ifdef HAVE_NUKLEAR
#include "ui.h"
#else
struct ui;
......@@ -482,7 +482,7 @@ int main(int argc, char **argv)
if (!p->win)
goto error;
#ifdef HAVE_UI
#ifdef HAVE_NUKLEAR
p->ui = ui_create(p->win->gpu);
if (!p->ui)
goto error;
......@@ -528,7 +528,7 @@ error:
return 1;
}
#ifdef HAVE_UI
#ifdef HAVE_NUKLEAR
static void add_hook(struct plplay *p, const struct pl_hook *hook, const char *path)
{
......
// License: CC0 / Public Domain
#include "common.h"
#include "window.h"
extern const struct window_impl win_impl_glfw_vk;
extern const struct window_impl win_impl_glfw_gl;
extern const struct window_impl win_impl_sdl_vk;
extern const struct window_impl win_impl_sdl_gl;
static const struct window_impl *win_impls[] = {
#ifdef HAVE_GLFW
# ifdef PL_HAVE_VULKAN
&win_impl_glfw_vk,
# endif
# ifdef PL_HAVE_OPENGL
&win_impl_glfw_gl,
# endif
#endif // HAVE_GLFW
#ifdef HAVE_SDL
# ifdef PL_HAVE_VULKAN
&win_impl_sdl_vk,
# endif
# ifdef PL_HAVE_OPENGL
&win_impl_sdl_gl,
# endif
#endif // HAVE_SDL
NULL
};
struct window *window_create(struct pl_context *ctx, const char *title,
int width, int height, enum winflags flags)
{
for (const struct window_impl **impl = win_impls; *impl; impl++) {
printf("Attempting to initialize API: %s\n", (*impl)->name);
struct window *win = (*impl)->create(ctx, title, width, height, flags);
if (win)
return win;
}
fprintf(stderr, "No windowing system / graphical API compiled or supported!");
exit(1);
}
void window_destroy(struct window **win)
{
if (*win)
(*win)->impl->destroy(win);
}
void window_poll(struct window *win, bool block)
{
return win->impl->poll(win, block);
}
void window_get_cursor(const struct window *win, int *x, int *y)
{
return win->impl->get_cursor(win, x, y);
}
void window_get_scroll(const struct window *win, float *dx, float *dy)
{
return win->impl->get_scroll(win, dx, dy);
}
bool window_get_button(const struct window *win, enum button btn)
{
return win->impl->get_button(win, btn);
}
char *window_get_file(const struct window *win)
{
return win->impl->get_file(win);
}
......@@ -4,6 +4,7 @@
#include <libplacebo/swapchain.h>
struct window {
const struct window_impl *impl;
const struct pl_swapchain *swapchain;
const struct pl_gpu *gpu;
bool window_lost;
......@@ -17,10 +18,10 @@ enum winflags {
struct window *window_create(struct pl_context *ctx, const char *title,
int width, int height, enum winflags flags);
void window_destroy(struct window **window);
void window_destroy(struct window **win);
// Poll/wait for window events
void window_poll(struct window *window, bool block);
void window_poll(struct window *win, bool block);
// Input handling
enum button {
......@@ -29,7 +30,19 @@ enum button {
BTN_MIDDLE,
};
void window_get_cursor(const struct window *window, int *x, int *y);
void window_get_scroll(const struct window *window, float *dx, float *dy);
bool window_get_button(const struct window *window, enum button);
char *window_get_file(const struct window *window);
void window_get_cursor(const struct window *win, int *x, int *y);
void window_get_scroll(const struct window *win, float *dx, float *dy);
bool window_get_button(const struct window *win, enum button);
char *window_get_file(const struct window *win);
// For implementations
struct window_impl {
const char *name;
__typeof__(window_create) *create;
__typeof__(window_destroy) *destroy;
__typeof__(window_poll) *poll;
__typeof__(window_get_cursor) *get_cursor;
__typeof__(window_get_scroll) *get_scroll;
__typeof__(window_get_button) *get_button;
__typeof__(window_get_file) *get_file;
};
......@@ -12,10 +12,14 @@
#ifdef USE_VK
#include <libplacebo/vulkan.h>
#define GLFW_INCLUDE_VULKAN
#define IMPL win_impl_glfw_vk
#define IMPL_NAME "GLFW (vulkan)"
#endif
#ifdef USE_GL
#include <libplacebo/opengl.h>
#define IMPL win_impl_glfw_gl
#define IMPL_NAME "GLFW (opengl)"
#endif
#include <GLFW/glfw3.h>
......@@ -26,6 +30,8 @@
#define DEBUG true
#endif
const struct window_impl IMPL;
struct priv {
struct window w;
GLFWwindow *win;
......@@ -96,13 +102,14 @@ static void drop_cb(GLFWwindow *win, int num, const char *files[])
}
}
struct window *window_create(struct pl_context *ctx, const char *title,
int width, int height, enum winflags flags)
static struct window *glfw_create(struct pl_context *ctx, const char *title,
int width, int height, enum winflags flags)
{
struct priv *p = calloc(1, sizeof(struct priv));
if (!p)
return NULL;
p->w.impl = &IMPL;
if (!glfwInit()) {
fprintf(stderr, "GLFW: Failed initializing?\n");
goto error;
......@@ -234,7 +241,7 @@ error:
return NULL;
}
void window_destroy(struct window **window)
static void glfw_destroy(struct window **window)
{
struct priv *p = (struct priv *) *window;
if (!p)
......@@ -262,7 +269,7 @@ void window_destroy(struct window **window)
*window = NULL;
}
void window_poll(struct window *window, bool block)
static void glfw_poll(struct window *window, bool block)
{
if (block) {
glfwWaitEvents();
......@@ -271,7 +278,7 @@ void window_poll(struct window *window, bool block)
}
}
void window_get_cursor(const struct window *window, int *x, int *y)
static void glfw_get_cursor(const struct window *window, int *x, int *y)
{
struct priv *p = (struct priv *) window;
double dx, dy;
......@@ -280,7 +287,7 @@ void window_get_cursor(const struct window *window, int *x, int *y)
*y = dy;
}
bool window_get_button(const struct window *window, enum button btn)
static bool glfw_get_button(const struct window *window, enum button btn)
{
static const int button_map[] = {
[BTN_LEFT] = GLFW_MOUSE_BUTTON_LEFT,
......@@ -292,7 +299,7 @@ bool window_get_button(const struct window *window, enum button btn)
return glfwGetMouseButton(p->win, button_map[btn]) == GLFW_PRESS;
}
void window_get_scroll(const struct window *window, float *dx, float *dy)
static void glfw_get_scroll(const struct window *window, float *dx, float *dy)
{
struct priv *p = (struct priv *) window;
*dx = p->scroll_dx;
......@@ -300,7 +307,7 @@ void window_get_scroll(const struct window *window, float *dx, float *dy)
p->scroll_dx = p->scroll_dy = 0.0;
}
char *window_get_file(const struct window *window)
static char *glfw_get_file(const struct window *window)
{
struct priv *p = (struct priv *) window;
if (p->file_seen) {
......@@ -316,3 +323,14 @@ char *window_get_file(const struct window *window)
p->file_seen = true;
return p->files[0];
}
const struct window_impl IMPL = {
.name = IMPL_NAME,
.create = glfw_create,
.destroy = glfw_destroy,
.poll = glfw_poll,
.get_cursor = glfw_get_cursor,
.get_button = glfw_get_button,
.get_scroll = glfw_get_scroll,
.get_file = glfw_get_file,
};
......@@ -13,11 +13,15 @@
#include <libplacebo/vulkan.h>
#include <SDL2/SDL_vulkan.h>
#define WINFLAG_API SDL_WINDOW_VULKAN
#define IMPL win_impl_sdl_vk
#define IMPL_NAME "SDL2 (vulkan)"
#endif
#ifdef USE_GL
#include <libplacebo/opengl.h>
#define WINFLAG_API SDL_WINDOW_OPENGL
#define IMPL win_impl_sdl_gl
#define IMPL_NAME "SDL2 (opengl)"
#endif
#ifdef NDEBUG
......@@ -26,6 +30,8 @@
#define DEBUG true
#endif
const struct window_impl IMPL;
struct priv {
struct window w;
SDL_Window *win;
......@@ -48,13 +54,14 @@ struct priv {
bool file_seen;
};
struct window *window_create(struct pl_context *ctx, const char *title,
int width, int height, enum winflags flags)
static struct window *sdl_create(struct pl_context *ctx, const char *title,
int width, int height, enum winflags flags)
{
struct priv *p = calloc(1, sizeof(struct priv));
if (!p)
return NULL;
p->w.impl = &IMPL;
if (SDL_Init(SDL_INIT_VIDEO) < 0) {
fprintf(stderr, "SDL2: Failed initializing: %s\n", SDL_GetError());
goto error;
......@@ -162,7 +169,7 @@ error:
return NULL;
}
void window_destroy(struct window **window)
static void sdl_destroy(struct window **window)
{
struct priv *p = (struct priv *) *window;
if (!p)
......@@ -232,7 +239,7 @@ static inline void handle_event(struct priv *p, SDL_Event *event)
}
}
void window_poll(struct window *window, bool block)
static void sdl_poll(struct window *window, bool block)
{
struct priv *p = (struct priv *) window;
SDL_Event event;
......@@ -248,12 +255,12 @@ void window_poll(struct window *window, bool block)
} while (ret);
}
void window_get_cursor(const struct window *window, int *x, int *y)
static void sdl_get_cursor(const struct window *window, int *x, int *y)
{
SDL_GetMouseState(x, y);
}
bool window_get_button(const struct window *window, enum button btn)
static bool sdl_get_button(const struct window *window, enum button btn)
{
static const uint32_t button_mask[] = {
[BTN_LEFT] = SDL_BUTTON_LMASK,
......@@ -264,7 +271,7 @@ bool window_get_button(const struct window *window, enum button btn)
return SDL_GetMouseState(NULL, NULL) & button_mask[btn];
}
void window_get_scroll(const struct window *window, float *dx, float *dy)
static void sdl_get_scroll(const struct window *window, float *dx, float *dy)
{
struct priv *p = (struct priv *) window;
*dx = p->scroll_dx;
......@@ -272,7 +279,7 @@ void window_get_scroll(const struct window *window, float *dx, float *dy)
p->scroll_dx = p->scroll_dy = 0;
}
char *window_get_file(const struct window *window)
static char *sdl_get_file(const struct window *window)
{
struct priv *p = (struct priv *) window;
if (p->file_seen) {
......@@ -288,3 +295,14 @@ char *window_get_file(const struct window *window)
p->file_seen = true;
return p->files[0];
}
const struct window_impl IMPL = {
.name = IMPL_NAME,
.create = sdl_create,
.destroy = sdl_destroy,
.poll = sdl_poll,
.get_cursor = sdl_get_cursor,
.get_button = sdl_get_button,
.get_scroll = sdl_get_scroll,
.get_file = sdl_get_file,
};
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment