Skip to content

Commit

Permalink
Bindings for rendering from Python.
Browse files Browse the repository at this point in the history
  • Loading branch information
Joe Rabinoff committed Nov 17, 2023
1 parent 1b39a33 commit 7e75921
Show file tree
Hide file tree
Showing 8 changed files with 389 additions and 7 deletions.
118 changes: 118 additions & 0 deletions wlroots/ffi_build.py
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,9 @@ def has_xwayland() -> bool:
const float projection[static 9], int x, int y, float alpha);
bool wlr_render_texture_with_matrix(struct wlr_renderer *r,
struct wlr_texture *texture, const float matrix[static 9], float alpha);
bool wlr_render_subtexture_with_matrix(struct wlr_renderer *r,
struct wlr_texture *texture, const struct wlr_fbox *box,
const float matrix[static 9], float alpha);
void wlr_render_rect(struct wlr_renderer *r, const struct wlr_box *box,
const float color[static 4], const float projection[static 9]);
Expand All @@ -180,6 +183,11 @@ def has_xwayland() -> bool:

# wlr/render/wlr_texture.h
CDEF += """
struct wlr_texture {
uint32_t width, height;
...;
};
struct wlr_texture *wlr_texture_from_pixels(struct wlr_renderer *renderer,
uint32_t fmt, uint32_t stride, uint32_t width, uint32_t height,
const void *data);
Expand All @@ -192,6 +200,45 @@ def has_xwayland() -> bool:
struct wlr_buffer *buffer);
"""

# wlr/render/gles2.h
CDEF += """
struct wlr_renderer *wlr_gles2_renderer_create_with_drm_fd(int drm_fd);
struct wlr_renderer *wlr_gles2_renderer_create(struct wlr_egl *egl);
struct wlr_egl *wlr_gles2_renderer_get_egl(struct wlr_renderer *renderer);
bool wlr_gles2_renderer_check_ext(struct wlr_renderer *renderer,
const char *ext);
typedef int... GLuint;
typedef int... GLenum;
GLuint wlr_gles2_renderer_get_current_fbo(struct wlr_renderer *wlr_renderer);
bool wlr_renderer_is_gles2(struct wlr_renderer *wlr_renderer);
bool wlr_texture_is_gles2(struct wlr_texture *texture);
struct wlr_gles2_texture_attribs {
GLenum target;
GLuint tex;
bool has_alpha;
};
void wlr_gles2_texture_get_attribs(struct wlr_texture *texture,
struct wlr_gles2_texture_attribs *attribs);
"""

# wlr/render/egl.h
CDEF += """
typedef void *EGLDisplay;
typedef void *EGLContext;
struct wlr_egl *wlr_egl_create_with_context(EGLDisplay display,
EGLContext context);
EGLDisplay wlr_egl_get_display(struct wlr_egl *egl);
EGLContext wlr_egl_get_context(struct wlr_egl *egl);
"""

# types/wlr_box.h
CDEF += """
struct wlr_box {
Expand Down Expand Up @@ -223,9 +270,19 @@ def has_xwayland() -> bool:
# types/wlr_buffer.h
CDEF += """
struct wlr_buffer {
int width, height;
...;
};
struct wlr_client_buffer {
struct wlr_buffer base;
struct wlr_texture *texture;
struct wlr_buffer *source;
...;
};
struct wlr_client_buffer *wlr_client_buffer_get(struct wlr_buffer *buffer);
void wlr_buffer_drop(struct wlr_buffer *buffer);
enum wlr_buffer_data_ptr_access_flag {
Expand Down Expand Up @@ -493,6 +550,14 @@ def has_xwayland() -> bool:
struct pixman_region32 current;
...;
};
void wlr_damage_ring_get_buffer_damage(struct wlr_damage_ring *ring,
int buffer_age, struct pixman_region32 *damage);
void wlr_damage_ring_rotate(struct wlr_damage_ring *ring);
void wlr_damage_ring_add_whole(struct wlr_damage_ring *ring);
bool wlr_damage_ring_add_box(struct wlr_damage_ring *ring,
const struct wlr_box *box);
"""

# types/wlr_data_control_v1.h
Expand Down Expand Up @@ -1062,7 +1127,34 @@ def has_xwayland() -> bool:
struct pixman_box32* pixman_region32_rectangles(struct pixman_region32 *region,
int *n_rects);
struct pixman_box32* pixman_region32_extents(struct pixman_region32 *region);
bool pixman_region32_not_empty(struct pixman_region32 *region);
bool pixman_region32_copy(struct pixman_region32 *dest,
const struct pixman_region32 *source);
void pixman_region32_translate(struct pixman_region32 *region, int x, int y);
bool pixman_region32_intersect_rect(struct pixman_region32 *dest,
struct pixman_region32 *source,
int x, int y, unsigned int width, unsigned int height);
bool pixman_region32_intersect(struct pixman_region32 *new_reg,
const struct pixman_region32 *reg1, const struct pixman_region32 *reg2);
bool pixman_region32_union(struct pixman_region32 *new_reg,
const struct pixman_region32 *reg1, const struct pixman_region32 *reg2);
bool pixman_region32_union_rect(struct pixman_region32 *dest,
const struct pixman_region32 *source, int x, int y, int width, int height);
bool pixman_region32_subtract(struct pixman_region32 *reg_d,
const struct pixman_region32 *reg_m,
const struct pixman_region32 *reg_s);
void pixman_region32_clear(struct pixman_region32 *region);
"""

# types/wlr_output.h
Expand Down Expand Up @@ -1132,6 +1224,11 @@ def has_xwayland() -> bool:
struct wlr_output_cursor *hardware_cursor;
int software_cursor_locks;
struct wlr_allocator *allocator;
struct wlr_renderer *renderer;
struct wlr_swapchain *swapchain;
struct wlr_buffer *back_buffer;
struct wl_listener display_destroy;
void *data;
Expand Down Expand Up @@ -1769,6 +1866,9 @@ def has_xwayland() -> bool:
struct wlr_scene_tree tree;
struct wl_list outputs;
struct wlr_presentation *presentation;
// private...
bool calculate_visibility;
...;
};
Expand Down Expand Up @@ -1798,6 +1898,13 @@ def has_xwayland() -> bool:
wlr_scene_buffer_point_accepts_input_func_t point_accepts_input;
struct wlr_scene_output *primary_output;
// private state...
struct wlr_texture *texture;
struct wlr_fbox src_box;
int dst_width, dst_height;
enum wl_output_transform transform;
...;
};
Expand Down Expand Up @@ -2752,8 +2859,17 @@ def has_xwayland() -> bool:

# util/region.h
CDEF += """
void wlr_region_scale(struct pixman_region32 *dst, const struct pixman_region32 *src,
float scale);
void wlr_region_scale_xy(struct pixman_region32 *dst, const struct pixman_region32 *src,
float scale_x, float scale_y);
void wlr_region_transform(struct pixman_region32 *dst, struct pixman_region32 *src,
enum wl_output_transform transform, int width, int height);
void wlr_region_expand(struct pixman_region32 *dst, const struct pixman_region32 *src,
int distance);
"""

# backend/headless.h
Expand Down Expand Up @@ -2783,6 +2899,8 @@ def has_xwayland() -> bool:
#include <wlr/render/allocator.h>
#include <wlr/render/drm_format_set.h>
#include <wlr/render/wlr_renderer.h>
#include <wlr/render/gles2.h>
#include <wlr/render/egl.h>
#include <wlr/types/wlr_buffer.h>
#include <wlr/types/wlr_compositor.h>
#include <wlr/types/wlr_cursor.h>
Expand Down
11 changes: 11 additions & 0 deletions wlroots/renderer.py
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,17 @@ def render_texture_with_matrix(
# TODO: get a better exception type
raise Exception("Bad render")

def render_subtexture_with_matrix(
self, texture: Texture, box: Ptr, matrix: Matrix, alpha: float
) -> None:
"""Renders the requested subtexture using the provided matrix"""
ret = lib.wlr_render_subtexture_with_matrix(
self._ptr, texture._ptr, box, matrix._ptr, alpha
)
if not ret:
# TODO: get a better exception type
raise Exception("Bad render")

def render_rect(self, box: Box, color: ColorType, projection: Matrix) -> None:
"""Renders a solid rectangle in the specified color."""
if not isinstance(color, ffi.CData):
Expand Down
17 changes: 17 additions & 0 deletions wlroots/util/box.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@

from __future__ import annotations

from pywayland.protocol.wayland import WlOutput

from wlroots import ffi, lib


Expand Down Expand Up @@ -52,10 +54,25 @@ def __init__(
def __repr__(self) -> str:
return f"Box({self.x}, {self.y}, {self.width}, {self.height})"

def copy(self) -> Box:
return Box(self.x, self.y, self.width, self.height)

def copy_from(self, other: Box) -> None:
self.x = other.x
self.y = other.y
self.width = other.width
self.height = other.height

def closest_point(self, x: float, y: float) -> tuple[float, float]:
xy_ptr = ffi.new("double[2]")
lib.wlr_box_closest_point(self._ptr, x, y, xy_ptr, xy_ptr + 1)
return xy_ptr[0], xy_ptr[1]

def contains_point(self, x: float, y: float) -> bool:
return lib.wlr_box_contains_point(self._ptr, x, y)

def transform(self, box: Box, transform: WlOutput.transform, width: int, height: int):
lib.wlr_box_transform(self._ptr, box._ptr, transform, width, height)

def intersection(self, box_a: Box, box_b: Box) -> bool:
return lib.wlr_box_intersection(self._ptr, box_a._ptr, box_b._ptr)
73 changes: 73 additions & 0 deletions wlroots/util/region.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,11 @@ def rectangles_as_boxes(self) -> list[Box]:
rects += 1
return boxes

@property
def extents(self) -> Box:
rect = lib.pixman_region32_extents(self._ptr)
return Box(rect.x1, rect.y1, rect.x2 - rect.x1, rect.y2 - rect.y1)

def transform(
self,
src: PixmanRegion32,
Expand All @@ -68,3 +73,71 @@ def not_empty(self) -> bool:
Wrapper around pixman_region32_not_empty
"""
return lib.pixman_region32_not_empty(self._ptr)

def intersect_rect(self, other: PixmanRegion32,
x: int, y: int, width: int, height: int) -> bool:
"""
Wrapper around pixman_region32_intersect_rect
"""
return lib.pixman_region32_intersect_rect(self._ptr, other._ptr, x, y, width, height)

def union_rect(self, other: PixmanRegion32,
x: int, y: int, width: int, height: int) -> bool:
"""
Wrapper around pixman_region32_union_rect
"""
return lib.pixman_region32_union_rect(self._ptr, other._ptr, x, y, width, height)

def intersect(self, reg1: PixmanRegion32, reg2: PixmanRegion32) -> bool:
"""
Wrapper around pixman_region32_intersect
"""
return lib.pixman_region32_intersect(self._ptr, reg1._ptr, reg2._ptr)

def union(self, reg1: PixmanRegion32, reg2: PixmanRegion32) -> bool:
"""
Wrapper around pixman_region32_union
"""
return lib.pixman_region32_union(self._ptr, reg1._ptr, reg2._ptr)

def subtract(self, reg1: PixmanRegion32, reg2: PixmanRegion32) -> bool:
"""
Wrapper around pixman_region32_subtract
"""
return lib.pixman_region32_subtract(self._ptr, reg1._ptr, reg2._ptr)

def copy_from(self, other: PixmanRegion32) -> bool:
"""
Wrapper around pixman_region32_copy
"""
return lib.pixman_region32_copy(self._ptr, other._ptr)

def translate(self, x: int, y: int) -> None:
"""
Wrapper around pixman_region32_translate
"""
lib.pixman_region32_translate(self._ptr, x, y)

def scale(self, other: PixmanRegion32, scale: float) -> None:
"""
Wrapper around wlr_region_scale
"""
lib.wlr_region_scale(self._ptr, other._ptr, scale)

def scale_xy(self, other: PixmanRegion32, scale_x: float, scale_y: float) -> None:
"""
Wrapper around wlr_region_scale_xy
"""
lib.wlr_region_scale_xy(self._ptr, other._ptr, scale_x, scale_y)

def expand(self, other: PixmanRegion32, distance: int) -> None:
"""
Wrapper around wlr_region_expand
"""
lib.wlr_region_expand(self._ptr, other._ptr, distance)

def clear(self) -> None:
"""
Wrapper around pixman_region32_clear
"""
lib.pixman_region32_clear(self._ptr)
8 changes: 8 additions & 0 deletions wlroots/wlr_types/buffer.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,14 @@ class Buffer(Ptr):
def __init__(self, ptr) -> None:
self._ptr = ptr

@property
def width(self) -> int:
return self._ptr.width;

@property
def height(self) -> int:
return self._ptr.height;

def drop(self) -> None:
"""Destroys this wlr_texture."""
lib.wlr_buffer_drop(self._ptr)
Expand Down
18 changes: 16 additions & 2 deletions wlroots/wlr_types/output.py
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,14 @@ def current_mode(self) -> OutputMode | None:
return None
return OutputMode(self._ptr.current_mode)

@property
def width(self) -> int:
return self._ptr.width

@property
def height(self) -> int:
return self._ptr.height

@property
def scale(self) -> float:
return self._ptr.scale
Expand All @@ -113,6 +121,10 @@ def transform_matrix(self) -> Matrix:
"""The transform matrix giving the projection of the output"""
return Matrix(self._ptr.transform_matrix)

@property
def needs_frame(self) -> bool:
return self._ptr.needs_frame

def enable(self, *, enable: bool = True) -> None:
"""Enables or disables the output
Expand Down Expand Up @@ -178,14 +190,16 @@ def init_render(self, allocator: Allocator, renderer: Renderer) -> None:
"Output capabilities must match the capabilities of the output's backend."
)

def attach_render(self) -> None:
def attach_render(self) -> int:
"""Attach the renderer's buffer to the output
Compositors must call this function before rendering. After they are
done rendering, they should call `.commit()` to submit the new frame.
"""
if not lib.wlr_output_attach_render(self._ptr, ffi.NULL):
buffer_age_ptr = ffi.new("int *")
if not lib.wlr_output_attach_render(self._ptr, buffer_age_ptr):
raise RuntimeError("Unable to attach render")
return buffer_age_ptr[0]

def commit(self) -> None:
"""Commit the pending output state
Expand Down
Loading

0 comments on commit 7e75921

Please sign in to comment.