Skip to content

Commit

Permalink
split up multi-step stages
Browse files Browse the repository at this point in the history
  • Loading branch information
ffreyer committed Dec 26, 2024
1 parent 5071d72 commit 0f206e5
Show file tree
Hide file tree
Showing 3 changed files with 112 additions and 78 deletions.
162 changes: 96 additions & 66 deletions GLMakie/src/postprocessing.jl
Original file line number Diff line number Diff line change
Expand Up @@ -177,7 +177,7 @@ end
# Vaguely leaning on Vulkan Terminology
struct RenderPass{Name} <: AbstractRenderStep
framebuffer::GLFramebuffer
passes::Vector{RenderObject}
robj::RenderObject
end


Expand All @@ -199,7 +199,7 @@ function RenderPass{:OIT}(screen)
:sum_color => get_buffer(factory.fb, :HDR_color),
:prod_alpha => get_buffer(factory.fb, :OIT_weight),
)
pass = RenderObject(
robj = RenderObject(
data, shader,
() -> begin
glDepthMask(GL_TRUE)
Expand All @@ -216,39 +216,48 @@ function RenderPass{:OIT}(screen)
end,
nothing
)
pass.postrenderfunction = () -> draw_fullscreen(pass.vertexarray.id)
robj.postrenderfunction = () -> draw_fullscreen(robj.vertexarray.id)

return RenderPass{:OIT}(framebuffer, RenderObject[pass])
return RenderPass{:OIT}(framebuffer, robj)
end

function run_step(screen, glscene, step::RenderPass{:OIT})
# Blend transparent onto opaque
wh = size(step.framebuffer)
set_draw_buffers(step.framebuffer)
glViewport(0, 0, wh[1], wh[2])
GLAbstraction.render(step.passes[1])
GLAbstraction.render(step.robj)
return
end


function RenderPass{:SSAO}(screen)
function add_ssao_buffers(screen)
@debug "Creating SSAO postprocessor"

factory = screen.framebuffer_factory

# Add missing buffers
pos_tex = Texture(Vec3f, size(screen), minfilter = :nearest, x_repeat = :clamp_to_edge)
push!(factory, :position => pos_tex)
# HDR_color always exists...
if length(factory.render_buffer_ids) < 4
# Add missing buffers
pos_tex = Texture(Vec3f, size(screen), minfilter = :nearest, x_repeat = :clamp_to_edge)
push!(factory, :position => pos_tex)
# HDR_color always exists...

# TODO: temp - update renderbuffers and main renderbuffer
# eventually RenderPlots should have dedicated GLFramebuffers too, which
# derive their draw buffers from the abstracted render pipeline
pos_id = attach_colorbuffer(factory.fb, :position, pos_tex)
normal_id = attach_colorbuffer(factory.fb, :normal, get_buffer(factory, :HDR_color))
push!(factory.render_buffer_ids, pos_id, normal_id)
end

return
end

# TODO: temp - update renderbuffers and main renderbuffer
# eventually RenderPlots should have dedicated GLFramebuffers too, which
# derive their draw buffers from the abstracted render pipeline
pos_id = attach_colorbuffer(factory.fb, :position, pos_tex)
normal_id = attach_colorbuffer(factory.fb, :normal, get_buffer(factory, :HDR_color))
push!(factory.render_buffer_ids, pos_id, normal_id)
function RenderPass{:SSAO1}(screen)
factory = screen.framebuffer_factory
framebuffer = generate_framebuffer(factory, :HDR_color => :normal_occlusion)

framebuffer = generate_framebuffer(factory, :color, :HDR_color => :normal_occlusion)
add_ssao_buffers(screen)

# SSAO setup
N_samples = 64
Expand All @@ -261,17 +270,17 @@ function RenderPass{:SSAO}(screen)
end

# compute occlusion
shader1 = LazyShader(
shader = LazyShader(
screen.shader_cache,
loadshader("postprocessing/fullscreen.vert"),
loadshader("postprocessing/SSAO.frag"),
view = Dict(
"N_samples" => "$N_samples"
)
)
data1 = Dict{Symbol, Any}(
:position_buffer => get_buffer(factory.fb, :position),
:normal_occlusion_buffer => get_buffer(factory.fb, :normal),
data = Dict{Symbol, Any}(
:position_buffer => get_buffer(factory, :position),
:normal_occlusion_buffer => get_buffer(factory, :HDR_color),
:kernel => kernel,
:noise => Texture(
[normalize(Vec2f(2.0rand(2) .- 1.0)) for _ in 1:4, __ in 1:4],
Expand All @@ -282,38 +291,46 @@ function RenderPass{:SSAO}(screen)
:bias => 0.025f0,
:radius => 0.5f0
)
pass1 = RenderObject(data1, shader1, PostprocessPrerender(), nothing)
pass1.postrenderfunction = () -> draw_fullscreen(pass1.vertexarray.id)
robj = RenderObject(data, shader, PostprocessPrerender(), nothing)
robj.postrenderfunction = () -> draw_fullscreen(robj.vertexarray.id)

return RenderPass{:SSAO1}(framebuffer, robj)
end

function RenderPass{:SSAO2}(screen)
factory = screen.framebuffer_factory
framebuffer = generate_framebuffer(factory, :color)

add_ssao_buffers(screen)

# blur occlusion and combine with color
shader2 = LazyShader(
shader = LazyShader(
screen.shader_cache,
loadshader("postprocessing/fullscreen.vert"),
loadshader("postprocessing/SSAO_blur.frag")
)
data2 = Dict{Symbol, Any}(
:normal_occlusion => get_buffer(framebuffer, :normal_occlusion),
:color_texture => get_buffer(factory.fb, :color),
:ids => get_buffer(factory.fb, :objectid),
data = Dict{Symbol, Any}(
:normal_occlusion => get_buffer(factory, :HDR_color),
:color_texture => get_buffer(factory, :color),
:ids => get_buffer(factory, :objectid),
:inv_texel_size => rcpframe(size(screen)),
:blur_range => Int32(2)
)
pass2 = RenderObject(data2, shader2, PostprocessPrerender(), nothing)
pass2.postrenderfunction = () -> draw_fullscreen(pass2.vertexarray.id)
robj = RenderObject(data, shader, PostprocessPrerender(), nothing)
robj.postrenderfunction = () -> draw_fullscreen(robj.vertexarray.id)

return RenderPass{:SSAO}(framebuffer, [pass1, pass2])
return RenderPass{:SSAO2}(framebuffer, robj)
end

function run_step(screen, glscene, step::RenderPass{:SSAO})
set_draw_buffers(step.framebuffer, :normal_occlusion) # occlusion buffer
function run_step(screen, glscene, step::RenderPass{:SSAO1})
set_draw_buffers(step.framebuffer) # occlusion buffer

wh = size(step.framebuffer)
glViewport(0, 0, wh[1], wh[2])
glEnable(GL_SCISSOR_TEST)
ppu = (x) -> round.(Int, screen.px_per_unit[] .* x)

data1 = step.passes[1].uniforms
data = step.robj.uniforms
for (screenid, scene) in screen.screens
# Select the area of one leaf scene
# This should be per scene because projection may vary between
Expand All @@ -323,82 +340,95 @@ function run_step(screen, glscene, step::RenderPass{:SSAO})
a = viewport(scene)[]
glScissor(ppu(minimum(a))..., ppu(widths(a))...)
# update uniforms
data1[:projection] = Mat4f(scene.camera.projection[])
data1[:bias] = scene.ssao.bias[]
data1[:radius] = scene.ssao.radius[]
data1[:noise_scale] = Vec2f(0.25f0 .* size(step.framebuffer))
GLAbstraction.render(step.passes[1])
data[:projection] = Mat4f(scene.camera.projection[])
data[:bias] = scene.ssao.bias[]
data[:radius] = scene.ssao.radius[]
data[:noise_scale] = Vec2f(0.25f0 .* size(step.framebuffer))
GLAbstraction.render(step.robj)
end

return
end

function run_step(screen, glscene, step::RenderPass{:SSAO2})
# SSAO - blur occlusion and apply to color
set_draw_buffers(step.framebuffer, :color) # color buffer
data2 = step.passes[2].uniforms
set_draw_buffers(step.framebuffer) # color buffer
ppu = (x) -> round.(Int, screen.px_per_unit[] .* x)
data = step.robj.uniforms
for (screenid, scene) in screen.screens
# Select the area of one leaf scene
isempty(scene.children) || continue
a = viewport(scene)[]
glScissor(ppu(minimum(a))..., ppu(widths(a))...)
# update uniforms
data2[:blur_range] = scene.ssao.blur
data2[:inv_texel_size] = rcpframe(size(step.framebuffer))
GLAbstraction.render(step.passes[2])
data[:blur_range] = scene.ssao.blur
data[:inv_texel_size] = rcpframe(size(step.framebuffer))
GLAbstraction.render(step.robj)
end
glDisable(GL_SCISSOR_TEST)

return
end


function RenderPass{:FXAA}(screen)
@debug "Creating FXAA postprocessor"
function RenderPass{:FXAA1}(screen)
factory = screen.framebuffer_factory
framebuffer = generate_framebuffer(factory, :color, :HDR_color => :color_luma)
framebuffer = generate_framebuffer(factory, :HDR_color => :color_luma)

# calculate luma for FXAA
shader1 = LazyShader(
shader = LazyShader(
screen.shader_cache,
loadshader("postprocessing/fullscreen.vert"),
loadshader("postprocessing/postprocess.frag")
)
data1 = Dict{Symbol, Any}(
:color_texture => get_buffer(factory.fb, :color),
:object_ids => get_buffer(factory.fb, :objectid)
data = Dict{Symbol, Any}(
:color_texture => get_buffer(factory, :color),
:object_ids => get_buffer(factory, :objectid)
)
pass1 = RenderObject(data1, shader1, PostprocessPrerender(), nothing)
pass1.postrenderfunction = () -> draw_fullscreen(pass1.vertexarray.id)
robj = RenderObject(data, shader, PostprocessPrerender(), nothing)
robj.postrenderfunction = () -> draw_fullscreen(robj.vertexarray.id)

return RenderPass{:FXAA1}(framebuffer, robj)
end

function RenderPass{:FXAA2}(screen)
factory = screen.framebuffer_factory
framebuffer = generate_framebuffer(factory, :color)

# perform FXAA
shader2 = LazyShader(
shader = LazyShader(
screen.shader_cache,
loadshader("postprocessing/fullscreen.vert"),
loadshader("postprocessing/fxaa.frag")
)
data2 = Dict{Symbol, Any}(
:color_texture => get_buffer(framebuffer, :color_luma),
data = Dict{Symbol, Any}(
:color_texture => get_buffer(factory, :HDR_color),
:RCPFrame => rcpframe(size(framebuffer)),
)
pass2 = RenderObject(data2, shader2, PostprocessPrerender(), nothing)
pass2.postrenderfunction = () -> draw_fullscreen(pass2.vertexarray.id)
robj = RenderObject(data, shader, PostprocessPrerender(), nothing)
robj.postrenderfunction = () -> draw_fullscreen(robj.vertexarray.id)

return RenderPass{:FXAA}(framebuffer, RenderObject[pass1, pass2])
return RenderPass{:FXAA2}(framebuffer, robj)
end

function run_step(screen, glscene, step::RenderPass{:FXAA})
function run_step(screen, glscene, step::RenderPass{:FXAA1})
# FXAA - calculate LUMA
set_draw_buffers(step.framebuffer, :color_luma)
set_draw_buffers(step.framebuffer)
# TODO: make scissor explicit?
wh = size(step.framebuffer)
glViewport(0, 0, wh[1], wh[2])
# necessary with negative SSAO bias...
glClearColor(1, 1, 1, 1)
glClear(GL_COLOR_BUFFER_BIT)
GLAbstraction.render(step.passes[1])
GLAbstraction.render(step.robj)
return
end

function run_step(screen, glscene, step::RenderPass{:FXAA2})
# FXAA - perform anti-aliasing
set_draw_buffers(step.framebuffer, :color) # color buffer
step.passes[2][:RCPFrame] = rcpframe(size(step.framebuffer))
GLAbstraction.render(step.passes[2])

set_draw_buffers(step.framebuffer) # color buffer
step.robj[:RCPFrame] = rcpframe(size(step.framebuffer))
GLAbstraction.render(step.robj)
return
end

Expand Down
10 changes: 7 additions & 3 deletions GLMakie/src/screen.jl
Original file line number Diff line number Diff line change
Expand Up @@ -299,10 +299,12 @@ Makie.@noconstprop function empty_screen(debugging::Bool, reuse::Bool, window)
push!(screen.render_pipeline, SortPlots())
push!(screen.render_pipeline, RenderPlots(screen, :SSAO))
push!(screen.render_pipeline, EmptyRenderStep())
push!(screen.render_pipeline, EmptyRenderStep())
push!(screen.render_pipeline, RenderPlots(screen, :FXAA))
push!(screen.render_pipeline, RenderPlots(screen, :OIT))
push!(screen.render_pipeline, EmptyRenderStep())
push!(screen.render_pipeline, EmptyRenderStep())
push!(screen.render_pipeline, EmptyRenderStep())
push!(screen.render_pipeline, BlitToScreen(screen))

if owns_glscreen
Expand Down Expand Up @@ -393,9 +395,11 @@ function apply_config!(screen::Screen, config::ScreenConfig; start_renderloop::B
return
end

replace_renderpass!(config.ssao ? RenderPass{:SSAO} : EmptyRenderStep, 3)
replace_renderpass!(config.oit ? RenderPass{:OIT} : EmptyRenderStep, 6)
replace_renderpass!(config.fxaa ? RenderPass{:FXAA} : EmptyRenderStep, 7)
replace_renderpass!(config.ssao ? RenderPass{:SSAO1} : EmptyRenderStep, 3)
replace_renderpass!(config.ssao ? RenderPass{:SSAO2} : EmptyRenderStep, 4)
replace_renderpass!(config.oit ? RenderPass{:OIT} : EmptyRenderStep, 7)
replace_renderpass!(config.fxaa ? RenderPass{:FXAA1} : EmptyRenderStep, 8)
replace_renderpass!(config.fxaa ? RenderPass{:FXAA2} : EmptyRenderStep, 9)

# TODO: replace shader programs with lighting to update N_lights & N_light_parameters

Expand Down
18 changes: 9 additions & 9 deletions src/utilities/RenderPipeline.jl
Original file line number Diff line number Diff line change
Expand Up @@ -446,7 +446,7 @@ end
################################################################################


SortStage() = Stage("z-sort")
SortStage() = Stage(:ZSort)

# I guess we should have multiple versions of this? Because SSAO render and OIT render don't really fit?
# SSAO color objectid position normal
Expand All @@ -459,15 +459,15 @@ function RenderStage()
:position => Format(3, Float16),
:normal => Format(3, Float16),
)
Stage("render", outputs = outputs)
Stage(:Render, outputs = outputs)
end
function TransparentRenderStage()
outputs = (
:weighted_color_sum => Format(4, Float16),
:objectid => Format(2, UInt32),
:alpha_product => Format(1, Float8),
)
Stage("transparent render", outputs = outputs)
Stage(:TransparentRender, outputs = outputs)
end

# Want a MultiSzage kinda thing
Expand All @@ -476,10 +476,10 @@ function SSAOStage()
:position => Format(3, Float32),
:normal => Format(3, Float16)
)
stage1 = Stage("SSAO occlusion"; inputs, outputs = (:occlusion => Format(1, Float8),))
stage1 = Stage(:SSAO1; inputs, outputs = (:occlusion => Format(1, Float8),))

inputs = (:occlusion => Format(1, Float8), :color => Format(4, Float8), :objectid => Format(2, UInt32))
stage2 = Stage("SSAO blur", inputs = inputs, outputs = (:color => Format(),))
stage2 = Stage(:SSAO2, inputs = inputs, outputs = (:color => Format(),))

pipeline = Pipeline(stage1, stage2)
connect!(pipeline, 1, :occlusion, 2, :occlusion)
Expand All @@ -490,17 +490,17 @@ end
function OITStage()
inputs = (:weighted_color_sum => Format(4, Float16), :alpha_product => Format(1, Float8))
outputs = (:color => Format(4, Float8),)
return Stage("OIT"; inputs, outputs)
return Stage(:OIT; inputs, outputs)
end

function FXAAStage()
inputs = (:color => Format(4, Float8), :objectid => Format(2, UInt32))
outputs = (:color_luma => Format(4, Float8),)
stage1 = Stage("FXAA luma"; inputs, outputs)
stage1 = Stage(:FXAA1; inputs, outputs)

inputs = (:color_luma => Format(4, Float8),)
outputs = (:color => Format(4, Float8),)
stage2 = Stage("FXAA apply"; inputs, outputs)
stage2 = Stage(:FXAA2; inputs, outputs)

pipeline = Pipeline(stage1, stage2)
connect!(pipeline, 1, :color_luma, 2, :color_luma)
Expand All @@ -510,7 +510,7 @@ end

function DisplayStage()
inputs = (:color => Format(4, Float8), :objectid => Format(2, UInt32))
return Stage("display"; inputs)
return Stage(:Display; inputs)
end


Expand Down

0 comments on commit 0f206e5

Please sign in to comment.