From 42785cec51a0208adcf49657c77d507739575ce3 Mon Sep 17 00:00:00 2001 From: SimonDanisch Date: Tue, 15 Oct 2024 22:39:51 +0200 Subject: [PATCH 1/3] fix low hanging fruits for render performance --- CairoMakie/src/infrastructure.jl | 6 ++---- GLMakie/src/GLAbstraction/GLRenderObject.jl | 6 +++--- GLMakie/src/postprocessing.jl | 2 +- GLMakie/src/rendering.jl | 10 ++++------ GLMakie/src/screen.jl | 4 +++- 5 files changed, 13 insertions(+), 15 deletions(-) diff --git a/CairoMakie/src/infrastructure.jl b/CairoMakie/src/infrastructure.jl index 0f70934682b..15a665a4d36 100644 --- a/CairoMakie/src/infrastructure.jl +++ b/CairoMakie/src/infrastructure.jl @@ -12,9 +12,7 @@ function cairo_draw(screen::Screen, scene::Scene) draw_background(screen, scene) allplots = Makie.collect_atomic_plots(scene; is_atomic_plot = is_cairomakie_atomic_plot) - zvals = Makie.zvalue2d.(allplots) - permute!(allplots, sortperm(zvals)) - + sort!(allplots; by=Makie.zvalue2d) # If the backend is not a vector surface (i.e., PNG/ARGB), # then there is no point in rasterizing twice. should_rasterize = is_vector_backend(screen.surface) @@ -120,7 +118,7 @@ function draw_background(screen::Screen, scene::Scene, root_h) bg = scene.backgroundcolor[] Cairo.set_source_rgba(cr, red(bg), green(bg), blue(bg), alpha(bg)); r = viewport(scene)[] - # Makie has (0,0) at bottom left, Cairo at top left. Makie extends up, + # Makie has (0,0) at bottom left, Cairo at top left. Makie extends up, # Cairo down. Negative height breaks other backgrounds x, y = origin(r); w, h = widths(r) Cairo.rectangle(cr, x, root_h - y - h, w, h) # background diff --git a/GLMakie/src/GLAbstraction/GLRenderObject.jl b/GLMakie/src/GLAbstraction/GLRenderObject.jl index fe644f5c586..3c697e877ab 100644 --- a/GLMakie/src/GLAbstraction/GLRenderObject.jl +++ b/GLMakie/src/GLAbstraction/GLRenderObject.jl @@ -68,14 +68,14 @@ function (sp::StandardPostrender)() render(sp.vao, sp.primitive) end -struct StandardPostrenderInstanced{T} - main::T +struct StandardPostrenderInstanced + n_instances::Observable{Int} vao::GLVertexArray primitive::GLenum end function (sp::StandardPostrenderInstanced)() - renderinstanced(sp.vao, to_value(sp.main), sp.primitive) + return renderinstanced(sp.vao, sp.n_instances[], sp.primitive) end struct EmptyPrerender end diff --git a/GLMakie/src/postprocessing.jl b/GLMakie/src/postprocessing.jl index 60c978e07cf..0195b040ae3 100644 --- a/GLMakie/src/postprocessing.jl +++ b/GLMakie/src/postprocessing.jl @@ -290,7 +290,7 @@ function to_screen_postprocessor(framebuffer, shader_cache, screen_fb_id = nothi default_id = isnothing(screen_fb_id) ? 0 : screen_fb_id[] # GLFW uses 0, Gtk uses a value that we have to probe at the beginning of rendering glBindFramebuffer(GL_FRAMEBUFFER, default_id) - glViewport(0, 0, framebuffer_size(screen.glscreen)...) + glViewport(0, 0, framebuffer_size(screen)...) glClear(GL_COLOR_BUFFER_BIT) GLAbstraction.render(pass) # copy postprocess end diff --git a/GLMakie/src/rendering.jl b/GLMakie/src/rendering.jl index dda559f5ec3..4453abc9985 100644 --- a/GLMakie/src/rendering.jl +++ b/GLMakie/src/rendering.jl @@ -29,14 +29,12 @@ Renders a single frame of a `window` function render_frame(screen::Screen; resize_buffers=true) nw = to_native(screen) ShaderAbstractions.switch_context!(nw) + function sortby(x) - robj = x[3] - plot = screen.cache2plot[robj.id] - # TODO, use actual boundingbox - return Makie.zvalue2d(plot) + return x[3][:model][][3, 4] end - zvals = sortby.(screen.renderlist) - permute!(screen.renderlist, sortperm(zvals)) + + sort!(screen.renderlist; by=sortby) # NOTE # The transparent color buffer is reused by SSAO and FXAA. Changing the diff --git a/GLMakie/src/screen.jl b/GLMakie/src/screen.jl index 6188b400bd3..efaa71eda94 100644 --- a/GLMakie/src/screen.jl +++ b/GLMakie/src/screen.jl @@ -174,7 +174,7 @@ mutable struct Screen{GLWindow} <: MakieScreen renderlist::Vector{Tuple{ZIndex, ScreenID, RenderObject}} postprocessors::Vector{PostProcessor} cache::Dict{UInt64, RenderObject} - cache2plot::Dict{UInt32, AbstractPlot} + cache2plot::Dict{UInt32, Plot} framecache::Matrix{RGB{N0f8}} render_tick::Observable{Makie.TickState} # listeners must not Consume(true) window_open::Observable{Bool} @@ -218,6 +218,8 @@ mutable struct Screen{GLWindow} <: MakieScreen end end +framebuffer_size(screen::Screen) = screen.framebuffer.resolution[] + Makie.isvisible(screen::Screen) = screen.config.visible # for e.g. closeall, track all created screens From e118e414e81d85523ef7ecc69984c2d3b6cc93cd Mon Sep 17 00:00:00 2001 From: ffreyer Date: Mon, 4 Nov 2024 21:06:11 +0100 Subject: [PATCH 2/3] try fix test failures --- GLMakie/src/rendering.jl | 7 ++++++- src/layouting/transformation.jl | 5 +++-- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/GLMakie/src/rendering.jl b/GLMakie/src/rendering.jl index 8f7ae54a81d..4e6f9f65caf 100644 --- a/GLMakie/src/rendering.jl +++ b/GLMakie/src/rendering.jl @@ -31,7 +31,12 @@ function render_frame(screen::Screen; resize_buffers=true) ShaderAbstractions.switch_context!(nw) function sortby(x) - return x[3][:model][][3, 4] + robj = x[3] + plot = screen.cache2plot[robj.id] + # TODO, use actual boundingbox + # ~7% faster than calling zvalue2d doing the same thing? + return Makie.transformationmatrix(plot)[][3, 4] + # return Makie.zvalue2d(plot) end sort!(screen.renderlist; by=sortby) diff --git a/src/layouting/transformation.jl b/src/layouting/transformation.jl index 1bb59e62a8e..5a377fb7c89 100644 --- a/src/layouting/transformation.jl +++ b/src/layouting/transformation.jl @@ -536,5 +536,6 @@ end # and this way we can use the z-value as a means to shift the drawing order # by translating e.g. the axis spines forward so they are not obscured halfway # by heatmaps or images -zvalue2d(x)::Float32 = Float32(Makie.translation(x)[][3] + zvalue2d(x.parent)) -zvalue2d(::Nothing)::Float32 = 0f0 +# zvalue2d(x)::Float32 = Float32(Makie.translation(x)[][3] + zvalue2d(x.parent)) +@inline zvalue2d(x)::Float32 = Float32(transformationmatrix(x)[][3, 4]) +@inline zvalue2d(::Nothing)::Float32 = 0f0 From 96d592f9586ac63ff051fb7abc3db079f8db68a2 Mon Sep 17 00:00:00 2001 From: ffreyer Date: Mon, 4 Nov 2024 21:36:47 +0100 Subject: [PATCH 3/3] fix runtime dispatch with clip planes --- GLMakie/src/GLAbstraction/GLRender.jl | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/GLMakie/src/GLAbstraction/GLRender.jl b/GLMakie/src/GLAbstraction/GLRender.jl index 357ce23781b..44bb5b5a59b 100644 --- a/GLMakie/src/GLAbstraction/GLRender.jl +++ b/GLMakie/src/GLAbstraction/GLRender.jl @@ -5,8 +5,7 @@ function render(list::Tuple) return end -function setup_clip_planes(robj) - N = to_value(get(robj.uniforms, :num_clip_planes, 0)) +function setup_clip_planes(N::Integer) for i in 0:min(7, N-1) glEnable(GL_CLIP_DISTANCE0 + UInt32(i)) end @@ -22,13 +21,13 @@ When rendering a specialised list of Renderables, we can do some optimizations function render(list::Vector{RenderObject{Pre}}) where Pre isempty(list) && return nothing first(list).prerenderfunction() - setup_clip_planes(first(list)) vertexarray = first(list).vertexarray program = vertexarray.program glUseProgram(program.id) bind(vertexarray) for renderobject in list renderobject.visible || continue # skip invisible + setup_clip_planes(to_value(get(renderobject.uniforms, :num_clip_planes, 0))) # make sure we only bind new programs and vertexarray when it is actually # different from the previous one if renderobject.vertexarray != vertexarray @@ -70,7 +69,7 @@ a lot of objects. function render(renderobject::RenderObject, vertexarray=renderobject.vertexarray) if renderobject.visible renderobject.prerenderfunction() - setup_clip_planes(renderobject) + setup_clip_planes(to_value(get(renderobject.uniforms, :num_clip_planes, 0))) program = vertexarray.program glUseProgram(program.id) for (key, value) in program.uniformloc