-
Notifications
You must be signed in to change notification settings - Fork 13
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
bdc4a81
commit fa16928
Showing
1 changed file
with
250 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,250 @@ | ||
mod profile_with_puffin; | ||
|
||
use { | ||
bytemuck::{bytes_of, Pod, Zeroable}, | ||
core::f32, | ||
glam::{vec3, Vec4}, | ||
inline_spirv::inline_spirv, | ||
screen_13::prelude::*, | ||
screen_13_window::{Window, WindowError}, | ||
std::sync::Arc, | ||
}; | ||
|
||
// TODO: Add texelFetch option | ||
|
||
fn main() -> Result<(), WindowError> { | ||
pretty_env_logger::init(); | ||
profile_with_puffin::init(); | ||
|
||
let window = Window::new()?; | ||
|
||
let size = 237u32; | ||
let mip_level_count = size.ilog2(); | ||
|
||
assert_ne!(mip_level_count, 0, "size must be greater than one"); | ||
|
||
let image_info = ImageInfo::image_2d( | ||
size, | ||
size, | ||
vk::Format::R8G8B8A8_UNORM, | ||
vk::ImageUsageFlags::COLOR_ATTACHMENT | vk::ImageUsageFlags::SAMPLED, | ||
) | ||
.to_builder() | ||
.mip_level_count(mip_level_count) | ||
.build(); | ||
let image = Arc::new(Image::create(&window.device, image_info)?); | ||
|
||
fill_mip_levels(&window.device, &image)?; | ||
|
||
let splat = splat(&window.device)?; | ||
|
||
window.run(|frame| { | ||
// It is 100% certain that the swapchain supports color attachment usage, so this is shown | ||
// for completeness only | ||
// https://vulkan.gpuinfo.org/listsurfaceusageflags.php | ||
assert!(frame | ||
.render_graph | ||
.node_info(frame.swapchain_image) | ||
.usage | ||
.contains(vk::ImageUsageFlags::COLOR_ATTACHMENT)); | ||
|
||
let image = frame.render_graph.bind_node(&image); | ||
let swapchain_info = frame.render_graph.node_info(frame.swapchain_image); | ||
let stripe_width = swapchain_info.width / mip_level_count; | ||
|
||
let mut pass = frame | ||
.render_graph | ||
.begin_pass("splat mips") | ||
.bind_pipeline(&splat); | ||
|
||
for mip_level in 0..mip_level_count { | ||
let stripe_x = mip_level * stripe_width; | ||
pass = pass | ||
.read_descriptor_as( | ||
0, | ||
image, | ||
image_info | ||
.default_view_info() | ||
.to_builder() | ||
.base_mip_level(mip_level) | ||
.mip_level_count(Some(1)), | ||
) | ||
.store_color(0, frame.swapchain_image) | ||
.set_render_area(stripe_x as _, 0, stripe_width, swapchain_info.height) | ||
.record_subpass(|subpass, _| { | ||
subpass.draw(6, 1, 0, 0); | ||
}); | ||
} | ||
}) | ||
} | ||
|
||
fn fill_mip_levels(device: &Arc<Device>, image: &Arc<Image>) -> Result<(), DriverError> { | ||
#[derive(Clone, Copy, Pod, Zeroable)] | ||
#[repr(C)] | ||
struct PushConstants { | ||
a: Vec4, | ||
b: Vec4, | ||
} | ||
|
||
let vertical_gradient = Arc::new(GraphicPipeline::create( | ||
device, | ||
GraphicPipelineInfo::default(), | ||
[ | ||
Shader::new_vertex( | ||
inline_spirv!( | ||
r#" | ||
#version 460 core | ||
const vec2 POSITION[] = { | ||
vec2(-1, -1), | ||
vec2(-1, 1), | ||
vec2( 1, 1), | ||
vec2(-1, -1), | ||
vec2( 1, 1), | ||
vec2( 1, -1), | ||
}; | ||
layout(location = 0) out float ab; | ||
void main() { | ||
vec2 position = POSITION[gl_VertexIndex]; | ||
ab = max(position.y, 0); | ||
gl_Position = vec4(position, 0, 1); | ||
} | ||
"#, | ||
vert | ||
) | ||
.as_slice(), | ||
), | ||
Shader::new_fragment( | ||
inline_spirv!( | ||
r#" | ||
#version 460 core | ||
layout(push_constant) uniform PushConstants { | ||
layout(offset = 0) vec3 a; | ||
layout(offset = 16) vec3 b; | ||
}; | ||
layout(location = 0) in float ab; | ||
layout(location = 0) out vec4 color; | ||
void main() { | ||
color = vec4(mix(a, b, ab), 1); | ||
} | ||
"#, | ||
frag | ||
) | ||
.as_slice(), | ||
), | ||
], | ||
)?); | ||
|
||
let mut render_graph = RenderGraph::new(); | ||
let mut pass = render_graph | ||
.begin_pass("fill mip levels") | ||
.bind_pipeline(&vertical_gradient); | ||
let image_info = image.info; | ||
let image = pass.bind_node(image); | ||
|
||
for mip_level in 0..image_info.mip_level_count { | ||
pass = pass | ||
.store_color_as( | ||
0, | ||
image, | ||
image_info | ||
.default_view_info() | ||
.to_builder() | ||
.base_mip_level(mip_level) | ||
.mip_level_count(Some(1)), | ||
) | ||
.record_subpass(|subpass, _| { | ||
subpass | ||
.push_constants(bytes_of(&PushConstants { | ||
a: vec3(0.0, 1.0, 0.0).extend(f32::NAN), | ||
b: vec3(1.0, 0.0, 1.0).extend(f32::NAN), | ||
})) | ||
.draw(6, 1, 0, 0); | ||
}); | ||
} | ||
|
||
// This is the overly-complicated way of picking queue family 0 | ||
let queue_family_index = device | ||
.physical_device | ||
.queue_families | ||
.iter() | ||
.enumerate() | ||
.find_map(|(idx, family)| { | ||
family | ||
.queue_flags | ||
.contains(vk::QueueFlags::GRAPHICS) | ||
.then_some(idx) | ||
}) | ||
.ok_or(DriverError::Unsupported)?; | ||
|
||
// Submits to the GPU but does not wait for anything to be finished | ||
render_graph | ||
.resolve() | ||
.submit(&mut LazyPool::new(device), queue_family_index, 0) | ||
.map(|_| ()) | ||
} | ||
|
||
fn splat(device: &Arc<Device>) -> Result<Arc<GraphicPipeline>, DriverError> { | ||
Ok(Arc::new(GraphicPipeline::create( | ||
device, | ||
GraphicPipelineInfo::default(), | ||
[ | ||
Shader::new_vertex( | ||
inline_spirv!( | ||
r#" | ||
#version 460 core | ||
const vec2 POSITION[] = { | ||
vec2(-1, -1), | ||
vec2(-1, 1), | ||
vec2( 1, 1), | ||
vec2(-1, -1), | ||
vec2( 1, 1), | ||
vec2( 1, -1), | ||
}; | ||
const vec2 TEXCOORD[] = { | ||
vec2(0, 0), | ||
vec2(0, 1), | ||
vec2(1, 1), | ||
vec2(0, 0), | ||
vec2(1, 1), | ||
vec2(1, 0), | ||
}; | ||
layout(location = 0) out vec2 texcoord; | ||
void main() { | ||
texcoord = TEXCOORD[gl_VertexIndex]; | ||
gl_Position = vec4(POSITION[gl_VertexIndex], 0, 1); | ||
} | ||
"#, | ||
vert | ||
) | ||
.as_slice(), | ||
), | ||
Shader::new_fragment( | ||
inline_spirv!( | ||
r#" | ||
#version 460 core | ||
layout(binding = 0) uniform sampler2D image; | ||
layout(location = 0) in vec2 texcoord; | ||
layout(location = 0) out vec4 color; | ||
void main() { | ||
color = texture(image, texcoord); | ||
} | ||
"#, | ||
frag | ||
) | ||
.as_slice(), | ||
), | ||
], | ||
)?)) | ||
} |