Commit 7e1c5dc9 authored by Manuel Stoeckl's avatar Manuel Stoeckl

Use a code generator to call functions from wire format

This change removes the dependency on libffi and the header-dependency on
libwayland. (`wayland-xml` is still needed, of course.)

A python script is used to generate a series of 'call_*' functions which
parse the wire format and invoke matching `do_*` functions to be defined
by the user. With lto the `call_*` and `do_*` parts can often be combined,
reducing their effective cost to almost zero.

The script also generates more optimized data to check sizes and generate
new objects.
parent 2db592bb
......@@ -3,4 +3,5 @@ clang-format -style=file --assume-filename=C -i \
util.h \
waypipe.c server.c handlers.c client.c util.c parsing.c dmabuf.c shadow.c mainloop.c interval.c video.c \
test/diff_roundtrip.c test/damage_merge.c test/fd_mirror.c test/wire_parse.c
black -q test/headless.py test/startup_failure.py
black -q test/headless.py test/startup_failure.py \
protocols/symgen.py
This diff is collapsed.
......@@ -38,16 +38,11 @@ else
)
endif
wayland_client = dependency('wayland-client', version: '>=1.15') # scanner headers
wayland_server = dependency('wayland-server', version: '>=1.15') # scanner headers
wayland_scanner = dependency('wayland-scanner', native: true, version: '>=1.15') # public-code
wayland_protos = dependency('wayland-protocols', version: '>=1.12') # xdg-shell
libgbm = dependency('gbm', required: get_option('with_dmabuf'))
libdrm = dependency('libdrm', required: get_option('with_dmabuf'))
if libgbm.found() and libdrm.found()
add_project_arguments('-DHAS_DMABUF=1', language: 'c')
endif
libffi = dependency('libffi')
pthreads = dependency('threads')
rt = cc.find_library('rt')
# XXX dtrace -G (Solaris, FreeBSD, NetBSD) isn't supported yet
......@@ -76,14 +71,12 @@ subdir('protocols')
waypipe_source_files = ['client.c', 'dmabuf.c', 'handlers.c', 'mainloop.c', 'parsing.c', 'server.c', 'shadow.c', 'interval.c', 'util.c', 'video.c']
waypipe_dependencies = [
libgbm, # General GPU buffer creation, aligned with dmabuf proto
libffi, # To call wayland protocol functions
liblz4, # Fast compression option
libzstd, # Slow compression option
libavcodec,libavutil,libswscale, # Video encoding
pthreads, # To run expensive computations in parallel
protos, # Wayland protocol data
rt, # For shared memory
wayland_client.partial_dependency(compile_args: true), # protocol headers need these
]
waypipe_includes = []
......@@ -148,7 +141,7 @@ test_parse = executable(
'wire_parse',
['test/wire_parse.c'],
link_with: lib_waypipe_src,
dependencies: [libffi, wayland_client.partial_dependency(compile_args: true)]
dependencies: []
)
test('That protocol parsing fails cleanly', test_parse)
weston_prog = find_program('weston', required: false)
......
This diff is collapsed.
gtk_primary_selection_offer_req_receive
gtk_primary_selection_source_evt_send
wl_buffer_evt_release
wl_data_offer_req_receive
wl_data_source_evt_send
wl_display_evt_delete_id
wl_display_evt_error
wl_display_req_get_registry
wl_display_req_sync
wl_drm_evt_device
wl_drm_req_create_prime_buffer
wl_keyboard_evt_keymap
wl_registry_evt_global
wl_registry_evt_global_remove
wl_registry_req_bind
wl_shm_req_create_pool
wl_shm_pool_req_create_buffer
wl_shm_pool_req_resize
wl_surface_req_amage_buffer
wl_surface_req_attach
wl_surface_req_commit
wl_surface_req_damage
wl_surface_req_damage_buffer
wl_surface_req_set_buffer_transform
wl_surface_req_set_buffer_scale
wp_presentation_evt_clock_id
wp_presentation_feedback_evt_presented
wp_presentation_req_feedback
zwlr_data_control_offer_v1_req_receive
zwlr_data_control_source_v1_evt_send
zwlr_export_dmabuf_frame_v1_evt_frame
zwlr_export_dmabuf_frame_v1_evt_object
zwlr_export_dmabuf_frame_v1_evt_ready
zwlr_screencopy_frame_v1_evt_ready
zwlr_screencopy_frame_v1_req_copy
zwp_linux_buffer_params_v1_evt_created
zwp_linux_buffer_params_v1_req_add
zwp_linux_buffer_params_v1_req_create
zwp_linux_buffer_params_v1_req_create_immed
zwp_linux_dmabuf_v1_evt_modifier
wl_protocol_dir = wayland_protos.get_pkgconfig_variable('pkgdatadir')
wayland_dir = wayland_client.get_pkgconfig_variable('pkgdatadir')
wayland_scanner_prog = find_program(wayland_scanner.get_pkgconfig_variable('wayland_scanner'))
# todo: make function list dependency explicit
gen_path = join_paths(meson.current_source_dir(), 'symgen.py')
fn_list = join_paths(meson.current_source_dir(), 'function_list.txt')
wayland_protos = dependency('wayland-protocols', version: '>=1.12') # xdg-shell
wayland_dep = dependency('wayland-client', required: false)
if not wayland_dep.found()
wayland_dep = dependency('wayland-server', required: true)
endif
wayland_dir = wayland_dep.get_pkgconfig_variable('pkgdatadir')
wl_protocol_dir = wayland_protos.get_pkgconfig_variable('pkgdatadir')
protocols = [
wayland_dir + '/wayland.xml',
......@@ -19,24 +28,19 @@ protocols = [
protocols_src = []
protocols_headers = []
protocols_headers += configure_file(input: 'symgen_types.h', copy: true, output: 'symgen_types.h')
foreach xml : protocols
protocols_src += custom_target(
'@0@ code'.format(xml.underscorify()),
output: '@BASENAME@-data.c',
input: xml,
command: [wayland_scanner_prog, 'private-code', '@INPUT@', '@OUTPUT@'],
command: [python3, gen_path, 'data', fn_list, '@INPUT@', '@OUTPUT@'],
)
protocols_headers += custom_target(
'@0@ client-header'.format(xml.underscorify()),
output: '@BASENAME@-client-defs.h',
input: xml,
command: [wayland_scanner_prog, 'client-header', '@INPUT@', '@OUTPUT@'],
)
protocols_headers += custom_target(
'@0@ server-header'.format(xml.underscorify()),
output: '@BASENAME@-server-defs.h',
output: '@BASENAME@-defs.h',
input: xml,
command: [wayland_scanner_prog, 'server-header', '@INPUT@', '@OUTPUT@'],
command: [python3, gen_path, 'header', fn_list, '@INPUT@', '@OUTPUT@'],
)
endforeach
......@@ -44,7 +48,6 @@ endforeach
lib_protocols = static_library(
'protocols',
protocols_src,
dependencies: wayland_client.partial_dependency(compile_args: true),
)
protos = declare_dependency(
link_with: lib_protocols,
......
This diff is collapsed.
#ifndef SYMGEN_TYPES_H
#define SYMGEN_TYPES_H
#include <stdbool.h>
#include <stdint.h>
struct context;
struct message_tracker;
struct wp_object;
typedef void (*wp_callfn_t)(struct context *ctx, const uint32_t *payload, const int *fds, struct message_tracker *mt);
struct msg_data {
const char *name;
const int n_stretch;
const int base_gap;
const int *trail_gap;
const bool *stretch_is_string;
const int n_fds;
const int new_vec_len;
const int *new_obj_idxs;/* there are special 'spacer' fields at each string/arr, =-1*/
const struct wp_interface **new_obj_types;
};
struct wp_interface {
const char *name;
/* 0=request, 1=event */
const struct msg_data *funcs[2];
const int nfuncs[2];
};
/* User should define this function. */
struct wp_object *get_object(struct message_tracker *mt, uint32_t id, const struct wp_interface *intf);
#endif /* SYMGEN_TYPES_H */
......@@ -31,6 +31,7 @@
#include <string.h>
#include <time.h>
#if 0
#include <sys/mman.h>
#include <ffi.h>
......@@ -183,3 +184,13 @@ int main(int argc, char **argv)
printf("Net result: %s\n", all_success ? "pass" : "FAIL");
return all_success ? EXIT_SUCCESS : EXIT_FAILURE;
}
#else
log_handler_func_t log_funcs[2] = {test_log_handler, test_log_handler};
int main(int argc, char **argv)
{
(void)argc;
(void)argv;
return EXIT_SUCCESS;
}
#endif
......@@ -353,8 +353,9 @@ struct transfer {
struct bytebuf *subtransfers;
};
struct wp_interface;
struct msg_handler {
const struct wl_interface *interface;
const struct wp_interface *interface;
// these are structs packed densely with function pointers
const void *event_handlers;
const void *request_handlers;
......@@ -362,7 +363,7 @@ struct msg_handler {
struct wp_object {
/* An object used by the wayland protocol. Specific types may extend
* this struct, using the following data as a header */
const struct wl_interface *type; // Use to lookup the message handler
const struct wp_interface *type; // Use to lookup the message handler
uint32_t obj_id;
bool is_zombie; // object deleted but not yet acknowledged remotely
};
......@@ -377,14 +378,6 @@ struct message_tracker {
// creating a new type <-> binding it in the 'interface' list, via
// registry. each type produces 'callbacks'
struct obj_list objects;
// Precomputed signatures for active functions. The arg table contains
// a concatenated list of all argument type signature vectors. The
// request/event cache elements are vectors of ffi_cif types
void *cif_arg_table;
void *cif_table;
void **event_cif_cache;
void **request_cif_cache;
};
struct context {
struct globals *const g;
......@@ -542,13 +535,12 @@ enum parse_state handle_message(struct globals *g, bool on_display_side,
struct int_window *fds);
// handlers.c
struct wl_interface;
struct wp_object *create_wp_object(
uint32_t it, const struct wl_interface *type);
uint32_t it, const struct wp_interface *type);
void destroy_wp_object(
struct fd_translation_map *map, struct wp_object *object);
extern const struct msg_handler handlers[];
extern const struct wl_interface *the_display_interface;
extern const struct wp_interface *the_display_interface;
// dmabuf.c
......
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