Skip to content
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

add linecaps (GLMakie, CairoMakie) #2536

Closed
wants to merge 54 commits into from
Closed
Show file tree
Hide file tree
Changes from 2 commits
Commits
Show all changes
54 commits
Select commit Hold shift + click to select a range
fe0043f
prototype linecaps in shader
ffreyer Dec 30, 2022
5c14b08
fix triangle
ffreyer Dec 30, 2022
1035f9a
fix antialiasing & add uniforms
ffreyer Dec 30, 2022
2868301
add line shortening and mirrored triangle
ffreyer Dec 30, 2022
ac54023
only shorter discontinous lines
ffreyer Dec 30, 2022
58238c4
fix printing
ffreyer Dec 30, 2022
21c260d
make linewidth and linecap_length per vertex
ffreyer Dec 30, 2022
41a200f
add linecaps to linesegments
ffreyer Dec 30, 2022
2103da7
fix cut off triangles
ffreyer Dec 30, 2022
8af7d28
minor cleanup
ffreyer Dec 30, 2022
fe26ed7
improve triangle fix
ffreyer Dec 30, 2022
df4cc82
get linestyles working
ffreyer Dec 31, 2022
0ed7fd3
add linecap attribute
ffreyer Dec 31, 2022
0bcc438
add refimg test
ffreyer Dec 31, 2022
4b3f232
update NEWS
ffreyer Dec 31, 2022
344d5ba
add linecap to CairoMakie
ffreyer Dec 31, 2022
a0e8004
update NEWS
ffreyer Dec 31, 2022
d571ae9
exclude linecap test from WGLMakie
ffreyer Dec 31, 2022
afc879a
minor cleanup
ffreyer Dec 31, 2022
1503d8f
Merge branch 'master' into ff/linecaps
ffreyer Dec 31, 2022
6ac6bf7
fix test failure
ffreyer Dec 31, 2022
5e206a9
simplify fragment shader (drop triangle caps)
ffreyer Jan 1, 2023
ff118ea
Merge branch 'master' into ff/linecaps
ffreyer Jan 1, 2023
61802c4
Merge branch 'master' into ff/linecaps
SimonDanisch Jan 2, 2023
a4ee760
remove unnecessary lastlen and maxlen
ffreyer Jan 2, 2023
7fd4efb
update recipes (linecap passthrough & tweaks)
ffreyer Jan 2, 2023
3916802
use lines without point dublication
ffreyer Jan 3, 2023
3fe7351
fix test failures
ffreyer Jan 3, 2023
fa7cbd9
update MakieLayout
ffreyer Jan 3, 2023
812ff3f
fix rebase
ffreyer Jan 3, 2023
8ff1bed
fix typo
ffreyer Jan 3, 2023
d05b002
update legendelements
ffreyer Jan 3, 2023
401e1d8
add linecap examples
ffreyer Jan 3, 2023
035ba35
mention linecap in poly docstring
ffreyer Jan 3, 2023
3da3d96
Merge branch 'master' into ff/linecaps
ffreyer Jan 3, 2023
3e92c0e
no linecap for latexstrings
ffreyer Jan 3, 2023
ef2bd88
fix typo
ffreyer Jan 3, 2023
918d268
remove linecap attribute
ffreyer Jan 3, 2023
c368811
fix convert error
ffreyer Jan 3, 2023
33f36b4
fix another typo
ffreyer Jan 3, 2023
5054952
and another one
ffreyer Jan 3, 2023
e8e0943
Merge branch 'master' into ff/linecaps
ffreyer Jan 12, 2023
11a12ba
make test name more unique
ffreyer Jan 17, 2023
a0b2a1b
Merge branch 'master' into ff/linecaps
ffreyer Jan 17, 2023
ef78de7
rework linecap_length into more general length_offset
ffreyer Jan 18, 2023
bbf3445
add reference test for offsets
ffreyer Jan 18, 2023
06afc32
add length_offset to CairoMakie
ffreyer Jan 18, 2023
29e9c1d
add offsets to WGLMakie and exclude test
ffreyer Jan 18, 2023
22e42a4
add entry for length_offset
ffreyer Jan 18, 2023
6ada0f6
remove experimental stuff
ffreyer Jan 18, 2023
e9a853b
fix screen to clip transformation
ffreyer Jan 18, 2023
835b582
Merge branch 'master' into ff/linecaps
ffreyer Jan 24, 2023
f99ccaf
Merge branch 'master' into ff/linecaps
ffreyer Jan 29, 2023
add06f8
adjust linestyle spacing with linecaps
ffreyer Jan 30, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions GLMakie/assets/shader/line_segment.geom
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ out float f_thickness;
out vec4 f_color;
out vec2 f_uv;
flat out uvec2 f_id;
flat out int f_type;

#define AA_THICKNESS 2.0

Expand All @@ -33,6 +34,7 @@ void emit_vertex(vec2 position, vec2 uv, int index)
gl_Position = vec4((position / resolution) * inpos.w, inpos.z, inpos.w);
f_id = g_id[index];
f_thickness = g_thickness[index] + AA_THICKNESS;
f_type = 0;
EmitVertex();
}

Expand Down
48 changes: 44 additions & 4 deletions GLMakie/assets/shader/lines.frag
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ in vec4 f_color;
in vec2 f_uv;
in float f_thickness;
flat in uvec2 f_id;
flat in int f_type; // TODO bad for performance
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Given the comment in the scatter shader

uniform int shape; // shape is a uniform for now. Making them a in && using them for control flow is expected to kill performance

I assume we should find a way around this?

Copy link
Collaborator Author

@ffreyer ffreyer Dec 31, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Did some benchmarking with

let 
    GLMakie.closeall()
    ps = [2 * rand(Point2f) .- 1 for _ in 1:2000]

    function myrenderloop(screen)
        yield()
        GLMakie.GLFW.SwapInterval(0)
        GLMakie.pollevents(screen)
        GLMakie.render_frame(screen)
        GLMakie.GLFW.SwapBuffers(GLMakie.to_native(screen))
        yield()

        @time for _ in 1:10_000
            GLMakie.pollevents(screen)
            GLMakie.render_frame(screen)
            GLMakie.GLFW.SwapBuffers(GLMakie.to_native(screen))
        end

        while GLMakie.isopen(screen) && !screen.stop_renderloop
            GLMakie.pollevents(screen)
            sleep(0.1)
            yield()
        end

        return
    end

    scene = Scene()
    linesegments!(scene, ps, linewidth = 10)
    screen = GLMakie.Screen(renderloop = myrenderloop)
    display(screen, scene)
end

I get the same ~5% CI got for this branch vs master.

I tried hacking together a two pass version which does the old lines in the first pass and caps in the second pass. This way we can swap out the flat in int f_type for uniform int linecap and uniform int render_pass. This ends up being about 10% slower than master though, doing both passes. Doing just the line pass is 3-4% slower.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think that's ok for linecaps! Can we optionally disable it and get the 5% back for high perf use cases? We could also think about having a different recipe for that though 🤷 I think the default should make good lines, and performance should be the special case!

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reducing the number of options in the fragment shader (5e206a9) helped a bit ... I think. I'm never sure with gpu benchmarking. When I tested it I got a bunch of benchmarks that were ~2% slower than master and then a bunch up to 5% slower 🤷

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I ran them again without background processes and I'm getting ~2% now (812ff3f)

{{pattern_type}} pattern;

uniform float pattern_length;
Expand All @@ -26,6 +27,7 @@ float aastep(float threshold1, float threshold2, float value) {
}
void write2framebuffer(vec4 color, uvec2 id);

// Signed distance fields for lines
// x/y pattern
float get_sd(sampler2D pattern, vec2 uv){
return texture(pattern, uv).x;
Expand All @@ -40,10 +42,48 @@ vec2 get_sd(Nothing _, vec2 uv){
return vec2(0.5, uv.y);
}

// Signed distance fields for caps
#define LINE 0
#define CIRCLE 4
#define RECTANGLE 5
#define TRIANGLE 6

float triangle(vec2 P){
// adjusted from distance shape to fill TODO (0..0.5, 0..1)
// reused for
P -= vec2(0.5);
float x = P.y - P.x;
float y = P.y + P.x;
return 0.5 - max(abs(x), abs(y));
}
float circle(vec2 uv){
// Radius 0.5 circle centered at (0.5, 0.5)
return 0.5-length(uv - vec2(0.5));
}
float rectangle(vec2 uv){
// fills 0..1 x 0..1
vec2 d = max(-uv, uv-vec2(1));
return -( length(max(vec2(0.0), d)) + min(0.0, max(d.x, d.y)) );
}


void main(){
vec2 xy = get_sd(pattern, f_uv);
float alpha = aastep(0, xy.x);
float alpha2 = aastep(-1, 1, xy.y);
vec4 color = vec4(f_color.rgb, f_color.a*alpha*alpha2);
vec4 color = vec4(f_color.rgb, 0.0);
if (f_type == CIRCLE){
float sd = f_thickness * circle(f_uv);
color = mix(color, f_color, smoothstep(-ALIASING_CONST, ALIASING_CONST, sd));
} else if (f_type == RECTANGLE) {
float sd = f_thickness * rectangle(f_uv);
// color = mix(color, f_color, smoothstep(-ALIASING_CONST, ALIASING_CONST, sd));
color = mix(color, f_color, aastep(0, sd));
} else if (f_type == TRIANGLE) {
float sd = f_thickness * triangle(f_uv);
color = mix(color, f_color, smoothstep(-ALIASING_CONST, ALIASING_CONST, sd));
} else {
vec2 xy = get_sd(pattern, f_uv);
float alpha = aastep(0, xy.x);
float alpha2 = aastep(-1, 1, xy.y);
color = vec4(f_color.rgb, f_color.a*alpha*alpha2);
}
write2framebuffer(color, f_id);
}
54 changes: 49 additions & 5 deletions GLMakie/assets/shader/lines.geom
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
{{GLSL_EXTENSIONS}}

layout(lines_adjacency) in;
layout(triangle_strip, max_vertices = 7) out;
layout(triangle_strip, max_vertices = 15) out;

in vec4 g_color[];
in float g_lastlen[];
Expand All @@ -17,6 +17,7 @@ out vec2 f_uv;
out float f_thickness;

flat out uvec2 f_id;
flat out int f_type;

uniform vec2 resolution;
uniform float maxlength;
Expand All @@ -25,19 +26,41 @@ uniform float pattern_length;


#define MITER_LIMIT -0.4
// types
#define LINE 0
#define CIRCLE 4
#define RECTANGLE 5
#define TRIANGLE 6


vec2 screen_space(vec4 vertex)
{
return vec2(vertex.xy / vertex.w) * resolution;
}

// for line sections
void emit_vertex(vec2 position, vec2 uv, int index, float ratio)
{
vec4 inpos = gl_in[index].gl_Position;
f_uv = vec2((g_lastlen[index] * ratio) / pattern_length / (thickness+4) / 2.0, uv.y);
f_color = g_color[index];
f_color = vec4(0, 1, 0, 1); //g_color[index];
gl_Position = vec4((position/resolution)*inpos.w, inpos.z, inpos.w);
f_id = g_id[index];
f_thickness = thickness;
f_type = LINE;
EmitVertex();
}

// for linecaps
void emit_vertex(vec2 position, vec2 uv, int index, int type)
{
vec4 inpos = gl_in[index].gl_Position;
f_uv = uv;
f_color = vec4(1,0,1,1);
gl_Position = vec4((position/resolution)*inpos.w, inpos.z, inpos.w);
f_id = g_id[index];
f_thickness = thickness;
f_type = type;
EmitVertex();
}

Expand Down Expand Up @@ -160,8 +183,29 @@ void main(void)
// generate the triangle strip

emit_vertex(p1 + length_a * miter_a, vec2( 0, -uvy), 1, ratio);
emit_vertex(p1 - length_a * miter_a, vec2( 0, uvy), 1, ratio);
emit_vertex(p1 - length_a * miter_a, vec2( 0, uvy), 1, ratio);

emit_vertex(p2 + length_b * miter_b, vec2( 0, -uvy ), 2, ratio);
emit_vertex(p2 - length_b * miter_b, vec2( 0, uvy), 2, ratio);
emit_vertex(p2 + length_b * miter_b, vec2( 0, -uvy), 2, ratio);
emit_vertex(p2 - length_b * miter_b, vec2( 0, uvy), 2, ratio);

// generate quad for line cap
int cap = RECTANGLE;
if (cap != LINE) {
if (!isvalid[0] && isvalid[1]) {
// there is no line before this
EndPrimitive();
emit_vertex(p1 + thickness * (-v1 + n1), vec2(0.0, 0.0), 1, cap);
emit_vertex(p1 + thickness * (-v1 - n1), vec2(0.0, 1.0), 1, cap);
emit_vertex(p1 + thickness * (+ n1), vec2(0.5, 0.0), 1, cap);
emit_vertex(p1 + thickness * (- n1), vec2(0.5, 1.0), 1, cap);
}
if (isvalid[2] && !isvalid[3]) {
// there is no line after this
EndPrimitive();
emit_vertex(p2 + thickness * (+ n1), vec2(0.5, 0.0), 2, cap);
emit_vertex(p2 + thickness * (- n1), vec2(0.5, 1.0), 2, cap);
emit_vertex(p2 + thickness * (v1 + n1), vec2(1.0, 0.0), 2, cap);
emit_vertex(p2 + thickness * (v1 - n1), vec2(1.0, 1.0), 2, cap);
}
}
}