diff --git a/CMakeLists.txt b/CMakeLists.txt index ae2397b2..b15882ce 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -63,4 +63,4 @@ add_subdirectory(session) add_subdirectory(render) add_subdirectory(util) -add_subdirectory(example) +add_subdirectory(examples) diff --git a/example/CMakeLists.txt b/examples/CMakeLists.txt similarity index 79% rename from example/CMakeLists.txt rename to examples/CMakeLists.txt index fff2e49b..f3f555c3 100644 --- a/example/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -65,3 +65,17 @@ target_link_libraries(tablet wlr-render ${XKBCOMMON_LIBRARIES} ) + +add_executable(compositor + compositor/main.c + compositor/wl_compositor.c + compositor/wl_shell.c + shared.c +) + +target_link_libraries(compositor + wlr-backend + wlr-session + wlr-render + ${XKBCOMMON_LIBRARIES} +) diff --git a/example/cat.c b/examples/cat.c similarity index 100% rename from example/cat.c rename to examples/cat.c diff --git a/example/cat.h b/examples/cat.h similarity index 100% rename from example/cat.h rename to examples/cat.h diff --git a/examples/compositor.h b/examples/compositor.h new file mode 100644 index 00000000..4773b83d --- /dev/null +++ b/examples/compositor.h @@ -0,0 +1,21 @@ +#ifndef _EXAMPLE_COMPOSITOR_H +#define _EXAMPLE_COMPOSITOR_H +#include + +struct wl_compositor_state { + struct wl_global *wl_global; + struct wl_list wl_resources; +}; + +void wl_compositor_init(struct wl_display *display, + struct wl_compositor_state *state); + +struct wl_shell_state { + struct wl_global *wl_global; + struct wl_list wl_resources; +}; + +void wl_shell_init(struct wl_display *display, + struct wl_shell_state *state); + +#endif diff --git a/examples/compositor/main.c b/examples/compositor/main.c new file mode 100644 index 00000000..6a689669 --- /dev/null +++ b/examples/compositor/main.c @@ -0,0 +1,49 @@ +#define _POSIX_C_SOURCE 199309L +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "shared.h" +#include "compositor.h" + +struct sample_state { + struct wlr_renderer *renderer; + struct wl_compositor_state compositor; + struct wl_shell_state shell; +}; + +void handle_output_frame(struct output_state *output, struct timespec *ts) { + struct compositor_state *state = output->compositor; + struct sample_state *sample = state->data; + struct wlr_output *wlr_output = output->output; + + wlr_output_make_current(wlr_output); + wlr_renderer_begin(sample->renderer, wlr_output); + // TODO: render surfaces + wlr_renderer_end(sample->renderer); + wlr_output_swap_buffers(wlr_output); +} + +int main() { + struct sample_state state = { 0 }; + struct compositor_state compositor = { 0, + .data = &state, + .output_frame_cb = handle_output_frame, + }; + compositor_init(&compositor); + + state.renderer = wlr_gles2_renderer_init(); + wl_display_init_shm(compositor.display); + wl_compositor_init(compositor.display, &state.compositor); + wl_shell_init(compositor.display, &state.shell); + + compositor_run(&compositor); +} diff --git a/examples/compositor/wl_compositor.c b/examples/compositor/wl_compositor.c new file mode 100644 index 00000000..0cd73afb --- /dev/null +++ b/examples/compositor/wl_compositor.c @@ -0,0 +1,55 @@ +#include +#include +#include +#include "compositor.h" + +static void wl_compositor_create_surface(struct wl_client *client, + struct wl_resource *resource, uint32_t id) { + wlr_log(L_DEBUG, "TODO: implement create_surface"); +} + +static void wl_compositor_create_region(struct wl_client *client, + struct wl_resource *resource, uint32_t id) { + wlr_log(L_DEBUG, "TODO: implement create_region"); +} + +struct wl_compositor_interface wl_compositor_impl = { + .create_surface = wl_compositor_create_surface, + .create_region = wl_compositor_create_region +}; + +static void wl_compositor_destroy(struct wl_resource *resource) { + struct wl_compositor_state *state = wl_resource_get_user_data(resource); + struct wl_resource *_resource = NULL; + wl_resource_for_each(_resource, &state->wl_resources) { + if (_resource == resource) { + struct wl_list *link = wl_resource_get_link(_resource); + wl_list_remove(link); + break; + } + } +} + +static void wl_compositor_bind(struct wl_client *wl_client, void *_state, + uint32_t version, uint32_t id) { + struct wl_compositor_state *state = _state; + assert(wl_client && state); + if (version > 4) { + wlr_log(L_ERROR, "Client requested unsupported wl_compositor version, disconnecting"); + wl_client_destroy(wl_client); + return; + } + struct wl_resource *wl_resource = wl_resource_create( + wl_client, &wl_compositor_interface, version, id); + wl_resource_set_implementation(wl_resource, &wl_compositor_impl, + state, wl_compositor_destroy); + wl_list_insert(&state->wl_resources, wl_resource_get_link(wl_resource)); +} + +void wl_compositor_init(struct wl_display *display, + struct wl_compositor_state *state) { + struct wl_global *wl_global = wl_global_create(display, + &wl_compositor_interface, 4, state, wl_compositor_bind); + state->wl_global = wl_global; + wl_list_init(&state->wl_resources); +} diff --git a/examples/compositor/wl_shell.c b/examples/compositor/wl_shell.c new file mode 100644 index 00000000..f2ec3c56 --- /dev/null +++ b/examples/compositor/wl_shell.c @@ -0,0 +1,50 @@ +#include +#include +#include +#include "compositor.h" + +void wl_shell_get_shell_surface(struct wl_client *client, + struct wl_resource *resource, uint32_t id, + struct wl_resource *surface) { + wlr_log(L_DEBUG, "TODO: implement get_shell_surface"); +} + +static struct wl_shell_interface wl_shell_impl = { + .get_shell_surface = wl_shell_get_shell_surface +}; + +static void wl_shell_destroy(struct wl_resource *resource) { + struct wl_shell_state *state = wl_resource_get_user_data(resource); + struct wl_resource *_resource = NULL; + wl_resource_for_each(_resource, &state->wl_resources) { + if (_resource == resource) { + struct wl_list *link = wl_resource_get_link(_resource); + wl_list_remove(link); + break; + } + } +} + +static void wl_shell_bind(struct wl_client *wl_client, void *_state, + uint32_t version, uint32_t id) { + struct wl_shell_state *state = _state; + assert(wl_client && state); + if (version > 1) { + wlr_log(L_ERROR, "Client requested unsupported wl_shell version, disconnecting"); + wl_client_destroy(wl_client); + return; + } + struct wl_resource *wl_resource = wl_resource_create( + wl_client, &wl_shell_interface, version, id); + wl_resource_set_implementation(wl_resource, &wl_shell_impl, + state, wl_shell_destroy); + wl_list_insert(&state->wl_resources, wl_resource_get_link(wl_resource)); +} + +void wl_shell_init(struct wl_display *display, + struct wl_shell_state *state) { + struct wl_global *wl_global = wl_global_create(display, + &wl_shell_interface, 1, state, wl_shell_bind); + state->wl_global = wl_global; + wl_list_init(&state->wl_resources); +} diff --git a/example/pointer.c b/examples/pointer.c similarity index 100% rename from example/pointer.c rename to examples/pointer.c diff --git a/example/rotation.c b/examples/rotation.c similarity index 98% rename from example/rotation.c rename to examples/rotation.c index 2dd148d0..1b75ccaf 100644 --- a/example/rotation.c +++ b/examples/rotation.c @@ -206,7 +206,7 @@ int main(int argc, char *argv[]) { state.renderer = wlr_gles2_renderer_init(); state.cat_texture = wlr_render_surface_init(state.renderer); - wlr_surface_attach_pixels(state.cat_texture, GL_RGBA, + wlr_surface_attach_pixels(state.cat_texture, WL_SHM_FORMAT_ABGR8888, cat_tex.width, cat_tex.width, cat_tex.height, cat_tex.pixel_data); compositor_run(&compositor); diff --git a/example/shared.c b/examples/shared.c similarity index 100% rename from example/shared.c rename to examples/shared.c diff --git a/example/shared.h b/examples/shared.h similarity index 99% rename from example/shared.h rename to examples/shared.h index 37f52dcc..1633f2c8 100644 --- a/example/shared.h +++ b/examples/shared.h @@ -126,7 +126,6 @@ struct compositor_state { struct wl_listener output_remove; struct wl_list outputs; - bool exit; void *data; }; diff --git a/example/simple.c b/examples/simple.c similarity index 100% rename from example/simple.c rename to examples/simple.c diff --git a/example/tablet.c b/examples/tablet.c similarity index 100% rename from example/tablet.c rename to examples/tablet.c diff --git a/example/touch.c b/examples/touch.c similarity index 100% rename from example/touch.c rename to examples/touch.c diff --git a/include/render/gles2.h b/include/render/gles2.h index bd0106b3..7b835209 100644 --- a/include/render/gles2.h +++ b/include/render/gles2.h @@ -6,19 +6,38 @@ #include #include +struct pixel_format { + uint32_t wl_format; + GLint gl_format, gl_type; + int depth, bpp; + GLuint *shader; +}; + struct wlr_surface_state { struct wlr_surface *wlr_surface; GLuint tex_id; + const struct pixel_format *pixel_format; +}; + +struct shaders { + bool initialized; + GLuint rgba, rgbx; + GLuint quad; + GLuint ellipse; }; +extern struct shaders shaders; + +const struct pixel_format *gl_format_for_wl_format(enum wl_shm_format fmt); + struct wlr_surface *gles2_surface_init(); extern const GLchar quad_vertex_src[]; extern const GLchar quad_fragment_src[]; extern const GLchar ellipse_fragment_src[]; extern const GLchar vertex_src[]; -extern const GLchar fragment_src_RGB[]; -extern const GLchar fragment_src_RGBA[]; +extern const GLchar fragment_src_rgba[]; +extern const GLchar fragment_src_rgbx[]; bool _gles2_flush_errors(const char *file, int line); #define gles2_flush_errors(...) \ diff --git a/include/wlr/render.h b/include/wlr/render.h index 53df01d2..30648a20 100644 --- a/include/wlr/render.h +++ b/include/wlr/render.h @@ -38,6 +38,11 @@ void wlr_render_colored_quad(struct wlr_renderer *r, */ void wlr_render_colored_ellipse(struct wlr_renderer *r, const float (*color)[4], const float (*matrix)[16]); +/** + * Returns a list of pixel formats supported by this renderer. + */ +const enum wl_shm_format *wlr_renderer_get_formats( + struct wlr_renderer *r, size_t *len); /** * Destroys this wlr_renderer. Surfaces must be destroyed separately. */ @@ -58,8 +63,9 @@ struct wlr_surface { * Attaches a pixel buffer to this surface. The buffer may be discarded after * calling this function. */ -bool wlr_surface_attach_pixels(struct wlr_surface *surf, uint32_t format, - int stride, int width, int height, const unsigned char *pixels); +bool wlr_surface_attach_pixels(struct wlr_surface *surf, + enum wl_shm_format format, int stride, int width, int height, + const unsigned char *pixels); /** * Attaches pixels from a wl_shm_buffer to this surface. The shm buffer may be * invalidated after calling this function. diff --git a/include/wlr/render/interface.h b/include/wlr/render/interface.h index a9c86f2c..ed804bb4 100644 --- a/include/wlr/render/interface.h +++ b/include/wlr/render/interface.h @@ -20,9 +20,11 @@ struct wlr_renderer_impl { bool (*render_with_matrix)(struct wlr_renderer_state *state, struct wlr_surface *surface, const float (*matrix)[16]); void (*render_quad)(struct wlr_renderer_state *state, - const float (*color)[4], const float (*matrix)[16]); + const float (*color)[4], const float (*matrix)[16]); void (*render_ellipse)(struct wlr_renderer_state *state, - const float (*color)[4], const float (*matrix)[16]); + const float (*color)[4], const float (*matrix)[16]); + const enum wl_shm_format *(*formats)( + struct wlr_renderer_state *state, size_t *len); void (*destroy)(struct wlr_renderer_state *state); }; @@ -30,13 +32,14 @@ struct wlr_renderer *wlr_renderer_init(struct wlr_renderer_state *state, struct wlr_renderer_impl *impl); struct wlr_surface_impl { - bool (*attach_pixels)(struct wlr_surface_state *state, uint32_t format, - int stride, int width, int height, const unsigned char *pixels); + bool (*attach_pixels)(struct wlr_surface_state *state, + enum wl_shm_format format, int stride, int width, int height, + const unsigned char *pixels); bool (*attach_shm)(struct wlr_surface_state *state, uint32_t format, struct wl_shm_buffer *shm); // TODO: egl void (*get_matrix)(struct wlr_surface_state *state, - float (*matrix)[16], const float (*projection)[16], int x, int y); + float (*matrix)[16], const float (*projection)[16], int x, int y); void (*bind)(struct wlr_surface_state *state); void (*destroy)(struct wlr_surface_state *state); }; diff --git a/include/wlr/types/wlr_output.h b/include/wlr/types/wlr_output.h index da5a7b07..cfc4cc0e 100644 --- a/include/wlr/types/wlr_output.h +++ b/include/wlr/types/wlr_output.h @@ -19,8 +19,9 @@ struct wlr_output_state; struct wlr_output { const struct wlr_output_impl *impl; struct wlr_output_state *state; + void *user_data; struct wl_global *wl_global; - struct wl_list resource_list; + struct wl_list wl_resources; uint32_t flags; char name[16]; diff --git a/render/CMakeLists.txt b/render/CMakeLists.txt index 4058b50e..d412ddbc 100644 --- a/render/CMakeLists.txt +++ b/render/CMakeLists.txt @@ -5,5 +5,6 @@ add_library(wlr-render gles2/shaders.c gles2/renderer.c gles2/surface.c + gles2/pixel_format.c gles2/util.c ) diff --git a/render/gles2/pixel_format.c b/render/gles2/pixel_format.c new file mode 100644 index 00000000..a0b9d09f --- /dev/null +++ b/render/gles2/pixel_format.c @@ -0,0 +1,45 @@ +#include +#include +#include "render/gles2.h" + +// Adapted from weston +struct pixel_format formats[] = { + { + .wl_format = WL_SHM_FORMAT_ARGB8888, + .depth = 32, + .bpp = 32, + .gl_format = GL_BGRA_EXT, + .gl_type = GL_UNSIGNED_BYTE, + .shader = &shaders.rgba + }, + { + .wl_format = WL_SHM_FORMAT_XRGB8888, + .depth = 24, + .bpp = 32, + .gl_format = GL_BGRA_EXT, + .gl_type = GL_UNSIGNED_BYTE, + .shader = &shaders.rgbx + }, + { + .wl_format = WL_SHM_FORMAT_XBGR8888, + .gl_format = GL_RGBA, + .gl_type = GL_UNSIGNED_BYTE, + .shader = &shaders.rgbx + }, + { + .wl_format = WL_SHM_FORMAT_ABGR8888, + .gl_format = GL_RGBA, + .gl_type = GL_UNSIGNED_BYTE, + .shader = &shaders.rgba + }, +}; +// TODO: more pixel formats + +const struct pixel_format *gl_format_for_wl_format(enum wl_shm_format fmt) { + for (size_t i = 0; i < sizeof(formats) / sizeof(*formats); ++i) { + if (formats[i].wl_format == fmt) { + return &formats[i]; + } + } + return NULL; +} diff --git a/render/gles2/renderer.c b/render/gles2/renderer.c index 623f378e..897dc3b8 100644 --- a/render/gles2/renderer.c +++ b/render/gles2/renderer.c @@ -10,12 +10,7 @@ #include #include "render/gles2.h" -static struct { - bool initialized; - GLuint rgb, rgba; - GLuint quad; - GLuint ellipse; -} shaders; +struct shaders shaders; static bool compile_shader(GLuint type, const GLchar *src, GLuint *shader) { *shader = GL_CALL(glCreateShader(type)); @@ -58,10 +53,10 @@ static void init_default_shaders() { if (shaders.initialized) { return; } - if (!compile_program(vertex_src, fragment_src_RGB, &shaders.rgb)) { + if (!compile_program(vertex_src, fragment_src_rgba, &shaders.rgba)) { goto error; } - if (!compile_program(vertex_src, fragment_src_RGBA, &shaders.rgba)) { + if (!compile_program(vertex_src, fragment_src_rgbx, &shaders.rgbx)) { goto error; } if (!compile_program(quad_vertex_src, quad_fragment_src, &shaders.quad)) { @@ -129,20 +124,10 @@ static void draw_quad() { static bool wlr_gles2_render_surface(struct wlr_renderer_state *state, struct wlr_surface *surface, const float (*matrix)[16]) { assert(surface && surface->valid); - switch (surface->format) { - case GL_RGB: - GL_CALL(glUseProgram(shaders.rgb)); - break; - case GL_RGBA: - GL_CALL(glUseProgram(shaders.rgba)); - break; - default: - wlr_log(L_ERROR, "No shader for this surface format"); - return false; - } - gles2_flush_errors(); wlr_surface_bind(surface); GL_CALL(glUniformMatrix4fv(0, 1, GL_FALSE, *matrix)); + // TODO: source alpha from somewhere else I guess + GL_CALL(glUniform1f(2, 1.0f)); draw_quad(); return true; } @@ -163,6 +148,18 @@ static void wlr_gles2_render_ellipse(struct wlr_renderer_state *state, draw_quad(); } +static const enum wl_shm_format *wlr_gles2_formats( + struct wlr_renderer_state *state, size_t *len) { + static enum wl_shm_format formats[] = { + WL_SHM_FORMAT_ARGB8888, + WL_SHM_FORMAT_XRGB8888, + WL_SHM_FORMAT_ABGR8888, + WL_SHM_FORMAT_XBGR8888, + }; + *len = sizeof(formats) / sizeof(formats[0]); + return formats; +} + static void wlr_gles2_destroy(struct wlr_renderer_state *state) { // no-op } @@ -174,6 +171,7 @@ static struct wlr_renderer_impl wlr_renderer_impl = { .render_with_matrix = wlr_gles2_render_surface, .render_quad = wlr_gles2_render_quad, .render_ellipse = wlr_gles2_render_ellipse, + .formats = wlr_gles2_formats, .destroy = wlr_gles2_destroy }; diff --git a/render/gles2/shaders.c b/render/gles2/shaders.c index 62712230..f5e61dd6 100644 --- a/render/gles2/shaders.c +++ b/render/gles2/shaders.c @@ -20,7 +20,6 @@ const GLchar quad_vertex_src[] = " vec4(i0.z, i1.z, i2.z, i3.z)," " vec4(i0.w, i1.w, i2.w, i3.w)" " );" -"" " return outMatrix;" "}" "void main() {" @@ -37,8 +36,7 @@ const GLchar quad_fragment_src[] = " gl_FragColor = v_color;" "}"; -// Colored ellipses (TODO) - +// Colored ellipses const GLchar ellipse_fragment_src[] = "precision mediump float;" "varying vec4 v_color;" @@ -74,18 +72,21 @@ const GLchar vertex_src[] = " v_texcoord = texcoord;" "}"; -const GLchar fragment_src_RGB[] = +const GLchar fragment_src_rgba[] = "precision mediump float;" "varying vec2 v_texcoord;" "uniform sampler2D tex;" +"uniform float alpha;" "void main() {" -" gl_FragColor = vec4(texture2D(tex, v_texcoord).rgb, 1.0);" +" gl_FragColor = alpha * texture2D(tex, v_texcoord);" "}"; -const GLchar fragment_src_RGBA[] = +const GLchar fragment_src_rgbx[] = "precision mediump float;" "varying vec2 v_texcoord;" "uniform sampler2D tex;" +"uniform float alpha;" "void main() {" -" gl_FragColor = texture2D(tex, v_texcoord);" +" gl_FragColor.rgb = alpha * texture2D(tex, v_texcoord).rgb;" +" gl_FragColor.a = alpha;" "}"; diff --git a/render/gles2/surface.c b/render/gles2/surface.c index c9be6ac2..f730a499 100644 --- a/render/gles2/surface.c +++ b/render/gles2/surface.c @@ -8,19 +8,27 @@ #include #include #include +#include #include "render/gles2.h" static bool gles2_surface_attach_pixels(struct wlr_surface_state *surface, - uint32_t format, int stride, int width, int height, const unsigned char *pixels) { + enum wl_shm_format format, int stride, int width, int height, + const unsigned char *pixels) { assert(surface); + const struct pixel_format *fmt = gl_format_for_wl_format(format); + if (!fmt || !fmt->gl_format) { + wlr_log(L_ERROR, "No supported pixel format for this surface"); + return false; + } surface->wlr_surface->width = width; surface->wlr_surface->height = height; surface->wlr_surface->format = format; + surface->pixel_format = fmt; GL_CALL(glGenTextures(1, &surface->tex_id)); GL_CALL(glBindTexture(GL_TEXTURE_2D, surface->tex_id)); GL_CALL(glPixelStorei(GL_UNPACK_ROW_LENGTH_EXT, stride)); - GL_CALL(glTexImage2D(GL_TEXTURE_2D, 0, format, width, height, 0, - format, GL_UNSIGNED_BYTE, pixels)); + GL_CALL(glTexImage2D(GL_TEXTURE_2D, 0, fmt->gl_format, width, height, 0, + fmt->gl_format, fmt->gl_type, pixels)); GL_CALL(glPixelStorei(GL_UNPACK_ROW_LENGTH_EXT, 0)); surface->wlr_surface->valid = true; return true; @@ -43,6 +51,7 @@ static void gles2_surface_bind(struct wlr_surface_state *surface) { GL_CALL(glBindTexture(GL_TEXTURE_2D, surface->tex_id)); GL_CALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR)); GL_CALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR)); + GL_CALL(glUseProgram(*surface->pixel_format->shader)); } static void gles2_surface_destroy(struct wlr_surface_state *surface) { diff --git a/render/wlr_renderer.c b/render/wlr_renderer.c index f48bb3eb..720c5254 100644 --- a/render/wlr_renderer.c +++ b/render/wlr_renderer.c @@ -41,3 +41,8 @@ void wlr_render_colored_ellipse(struct wlr_renderer *r, const float (*color)[4], const float (*matrix)[16]) { r->impl->render_ellipse(r->state, color, matrix); } + +const enum wl_shm_format *wlr_renderer_get_formats( + struct wlr_renderer *r, size_t *len) { + return r->impl->formats(r->state, len); +} diff --git a/types/wlr_output.c b/types/wlr_output.c index b64fd827..bec7cd5f 100644 --- a/types/wlr_output.c +++ b/types/wlr_output.c @@ -45,7 +45,7 @@ static void wl_output_send_to_resource(struct wl_resource *resource) { static void wl_output_destroy(struct wl_resource *resource) { struct wlr_output *output = wl_resource_get_user_data(resource); struct wl_resource *_resource = NULL; - wl_resource_for_each(_resource, &output->resource_list) { + wl_resource_for_each(_resource, &output->wl_resources) { if (_resource == resource) { struct wl_list *link = wl_resource_get_link(_resource); wl_list_remove(link); @@ -75,7 +75,7 @@ static void wl_output_bind(struct wl_client *wl_client, void *_wlr_output, wl_client, &wl_output_interface, version, id); wl_resource_set_implementation(wl_resource, &wl_output_impl, wlr_output, wl_output_destroy); - wl_list_insert(&wlr_output->resource_list, wl_resource_get_link(wl_resource)); + wl_list_insert(&wlr_output->wl_resources, wl_resource_get_link(wl_resource)); wl_output_send_to_resource(wl_resource); } @@ -84,7 +84,7 @@ struct wl_global *wlr_output_create_global( struct wl_global *wl_global = wl_global_create(display, &wl_output_interface, 3, wlr_output, wl_output_bind); wlr_output->wl_global = wl_global; - wl_list_init(&wlr_output->resource_list); + wl_list_init(&wlr_output->wl_resources); return wl_global; }