-
-
Notifications
You must be signed in to change notification settings - Fork 8k
Faster path drawing for the cairo backend (cairocffi only) #8787
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 1 commit
3edc982
b549d12
8a07eef
52ed746
5312461
1a2848d
aca804f
7a727a1
abbcb3e
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
- Loading branch information
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -94,15 +94,6 @@ def buffer_info(self): | |
_CAIRO_PATH_TYPE_SIZES[cairo.PATH_CLOSE_PATH] = 1 | ||
|
||
|
||
def _convert_path(ctx, path, transform, clip=None): | ||
return _convert_paths(ctx, [path], [transform], clip) | ||
|
||
|
||
def _convert_paths(ctx, paths, transforms, clip=None): | ||
return (_convert_paths_fast if HAS_CAIRO_CFFI else _convert_paths_slow)( | ||
ctx, paths, transforms, clip) | ||
|
||
|
||
def _convert_paths_slow(ctx, paths, transforms, clip=None): | ||
for path, transform in zip(paths, transforms): | ||
for points, code in path.iter_segments(transform, clip=clip): | ||
|
@@ -123,7 +114,7 @@ def _convert_paths_slow(ctx, paths, transforms, clip=None): | |
|
||
def _convert_paths_fast(ctx, paths, transforms, clip=None): | ||
# We directly convert to the internal representation used by cairo, for | ||
# which ABI compatibility is guaranteed. The layout is for each item is | ||
# which ABI compatibility is guaranteed. The layout for each item is | ||
# --CODE(4)-- -LENGTH(4)- ---------PAD(8)--------- | ||
# ----------X(8)---------- ----------Y(8)---------- | ||
# with the size in bytes in parentheses, and (X, Y) repeated as many times | ||
|
@@ -154,10 +145,10 @@ def _convert_paths_fast(ctx, paths, transforms, clip=None): | |
# Fill the buffer. | ||
buf = np.empty(cairo_num_data * 16, np.uint8) | ||
as_int = np.frombuffer(buf.data, np.int32) | ||
as_float = np.frombuffer(buf.data, np.float64) | ||
mask = np.ones_like(as_float, bool) | ||
as_int[::4][cairo_type_positions] = codes | ||
as_int[1::4][cairo_type_positions] = cairo_type_sizes | ||
as_float = np.frombuffer(buf.data, np.float64) | ||
mask = np.ones_like(as_float, bool) | ||
mask[::2][cairo_type_positions] = mask[1::2][cairo_type_positions] = False | ||
as_float[mask] = vertices.ravel() | ||
|
||
|
@@ -169,6 +160,13 @@ def _convert_paths_fast(ctx, paths, transforms, clip=None): | |
cairo.cairo.cairo_append_path(ctx._pointer, ptr) | ||
|
||
|
||
_convert_paths = _convert_paths_fast if HAS_CAIRO_CFFI else _convert_paths_slow | ||
|
||
|
||
def _convert_path(ctx, path, transform, clip=None): | ||
return _convert_paths(ctx, [path], [transform], clip) | ||
|
||
|
||
class RendererCairo(RendererBase): | ||
fontweights = { | ||
100 : cairo.FONT_WEIGHT_NORMAL, | ||
|
@@ -247,8 +245,7 @@ def draw_markers(self, gc, marker_path, marker_trans, path, transform, | |
|
||
ctx.new_path() | ||
# Create the path for the marker; it needs to be flipped here already! | ||
_convert_path( | ||
ctx, marker_path, marker_trans + Affine2D().scale(1, -1)) | ||
_convert_path(ctx, marker_path, marker_trans + Affine2D().scale(1, -1)) | ||
marker_path = ctx.copy_path_flat() | ||
|
||
# Figure out whether the path has a fill | ||
|
@@ -312,7 +309,7 @@ def _draw_paths(): | |
for k, v in gc_vars.items(): | ||
try: | ||
getattr(gc, "set" + k)(v) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. No underscore is needed? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Actually no, I'm just copying the |
||
except (AttributeError, TypeError): | ||
except (AttributeError, TypeError) as e: | ||
pass | ||
gc.ctx.new_path() | ||
paths, transforms = zip(*grouped_draw) | ||
|
@@ -326,8 +323,8 @@ def _draw_paths(): | |
offsetTrans, facecolors, edgecolors, linewidths, linestyles, | ||
antialiaseds, urls, offset_position): | ||
path, transform = path_id | ||
transform = (Affine2D(transform.get_matrix()).translate(xo, yo) | ||
+ Affine2D().scale(1, -1).translate(0, self.height)) | ||
transform = (Affine2D(transform.get_matrix()) | ||
.translate(xo, yo - self.height).scale(1, -1)) | ||
# rgb_fc could be a ndarray, for which equality is elementwise. | ||
new_key = vars(gc0), tuple(rgb_fc) if rgb_fc is not None else None | ||
if new_key == reuse_key: | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could be re-arranged slightly to keep the
int
andfloat
bits together.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not sure what you meant?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Well, you start with a buffer, make an
int
version, then afloat
version, then a mask (which is forfloat
). But then go back to filling theint
version, modifying the mask (which isfloat
stuff again), then fill thefloat
version. So I mean more like: