Skip to content

Instantly share code, notes, and snippets.

@DGriffin91
Created August 29, 2024 20:07
Show Gist options
  • Save DGriffin91/d792f15c1d0ae0c323f3b64e50968abf to your computer and use it in GitHub Desktop.
Save DGriffin91/d792f15c1d0ae0c323f3b64e50968abf to your computer and use it in GitHub Desktop.
SYNC-HAZARD-WRITE-AFTER-WRITE when writing to multiple mips
mod profile_with_puffin;
use {
bytemuck::cast_slice, inline_spirv::inline_spirv, screen_13::prelude::*,
screen_13_window::Window, std::sync::Arc, winit::dpi::PhysicalSize,
};
// A Vulkan triangle using a graphic pipeline, vertex/fragment shaders, and index/vertex buffers.
fn main() -> anyhow::Result<()> {
pretty_env_logger::init();
profile_with_puffin::init();
let width = 512;
let height = 512;
let window = Window::builder()
.window(|builder| builder.with_inner_size(PhysicalSize::new(width as f64, height as f64)))
.build()?;
let triangle_pipeline = Arc::new(GraphicPipeline::create(
&window.device,
GraphicPipelineInfo::default(),
[
Shader::new_vertex(
inline_spirv!(
r#"
#version 460 core
layout(location = 0) in vec3 position;
layout(location = 1) in vec3 color;
layout(location = 0) out vec3 vk_Color;
void main() {
gl_Position = vec4(position, 1);
vk_Color = color;
}
"#,
vert
)
.as_slice(),
),
Shader::new_fragment(
inline_spirv!(
r#"
#version 460 core
layout(location = 0) in vec3 color;
layout(location = 0) out vec4 vk_Color;
void main() {
vk_Color = vec4(color, 1);
}
"#,
frag
)
.as_slice(),
),
],
)?);
let index_buf = Arc::new(Buffer::create_from_slice(
&window.device,
vk::BufferUsageFlags::INDEX_BUFFER,
cast_slice(&[0u16, 1, 2]),
)?);
let vertex_buf = Arc::new(Buffer::create_from_slice(
&window.device,
vk::BufferUsageFlags::VERTEX_BUFFER,
cast_slice(&[
1.0f32, 1.0, 0.0, // v1
1.0, 0.0, 0.0, // red
0.0, -1.0, 0.0, // v2
0.0, 1.0, 0.0, // green
-1.0, 1.0, 0.0, // v3
0.0, 0.0, 1.0, // blue
]),
)?);
// ------------------------
// MIP
// ------------------------
let mip_compute_pipeline = Arc::new(ComputePipeline::create(
&window.device,
ComputePipelineInfo::default(),
Shader::new_compute(
inline_spirv!(
r#"
#version 460 core
layout(binding = 0) uniform sampler2D inputTexture;
layout(binding = 1, rgba8) uniform writeonly image2D output_mip0;
layout(binding = 2, rgba8) uniform writeonly image2D output_mip1;
layout(binding = 3, rgba8) uniform writeonly image2D output_mip2;
layout (local_size_x = 8, local_size_y = 8) in;
void main() {
ivec2 texSize = textureSize(inputTexture, 0);
ivec2 gid = ivec2(gl_GlobalInvocationID.xy);
if (gid.x >= texSize.x || gid.y >= texSize.y) return;
vec4 color = texelFetch(inputTexture, gid, 0);
if (gid.x < texSize.x / 2 && gid.y < texSize.y / 2) {
imageStore(output_mip0, gid, color);
}
if (gid.x % 2 == 0 && gid.y % 2 == 0) {
imageStore(output_mip1, gid / 2, color);
}
if (gid.x % 4 == 0 && gid.y % 4 == 0) {
imageStore(output_mip2, gid / 4, color);
}
}
"#,
comp
)
.as_slice(),
),
)?);
let mut info = ImageInfo::image_2d(
width,
height,
vk::Format::R8G8B8A8_UNORM,
vk::ImageUsageFlags::TRANSFER_SRC
| vk::ImageUsageFlags::TRANSFER_DST
| vk::ImageUsageFlags::STORAGE
| vk::ImageUsageFlags::SAMPLED,
);
info.mip_level_count = 3;
let mip_image = Arc::new(Image::create(&window.device, info).unwrap());
// ------------------------
// BLIT
// ------------------------
let blit_pipeline = Arc::new(GraphicPipeline::create(
&window.device,
GraphicPipelineInfo::default(),
[
Shader::new_vertex(
inline_spirv!(
r#"
#version 460 core
layout(location = 0) out vec2 uv;
void main()
{
uint vertexID = uint(gl_VertexIndex);
uv = vec2(float(vertexID >> 1), float(vertexID & 1)) * 2.0;
gl_Position = vec4(uv * vec2(2.0, 2.0) + vec2(-1.0, -1.0), 0.0, 1.0);
}
"#,
vert
)
.as_slice(),
),
Shader::new_fragment(
inline_spirv!(
r#"
#version 460 core
layout(binding = 0) uniform sampler2D tex;
layout(location = 0) in vec2 inUV;
layout(location = 0) out vec4 outColor;
void main() { outColor = textureLod(tex, inUV, 2.0); }
"#,
frag
)
.as_slice(),
),
],
)?);
Ok(window.run(|frame| {
let index_node = frame.render_graph.bind_node(&index_buf);
let vertex_node = frame.render_graph.bind_node(&vertex_buf);
frame
.render_graph
.begin_pass("Triangle Example")
.bind_pipeline(&triangle_pipeline)
.access_node(index_node, AccessType::IndexBuffer)
.access_node(vertex_node, AccessType::VertexBuffer)
.clear_color(0, frame.swapchain_image)
.store_color(0, frame.swapchain_image)
.record_subpass(move |subpass, _| {
subpass.bind_index_buffer(index_node, vk::IndexType::UINT16);
subpass.bind_vertex_buffer(vertex_node);
subpass.draw_indexed(3, 1, 0, 0, 0);
});
// ------------------------
// MIP
// ------------------------
let mip_image_node = frame.render_graph.bind_node(mip_image.clone());
let mut mip0_view = mip_image.info.default_view_info();
mip0_view.mip_level_count = Some(1);
mip0_view.base_mip_level = 0;
let mut mip1_view = mip_image.info.default_view_info();
mip1_view.mip_level_count = Some(1);
mip1_view.base_mip_level = 1;
let mut mip2_view = mip_image.info.default_view_info();
mip2_view.mip_level_count = Some(1);
mip2_view.base_mip_level = 2;
frame
.render_graph
.begin_pass("write_to_mips")
.bind_pipeline(&mip_compute_pipeline)
.read_descriptor(0, frame.swapchain_image)
.access_descriptor_as(1, mip_image_node, AccessType::General, mip0_view)
.access_descriptor_as(2, mip_image_node, AccessType::General, mip1_view)
.access_descriptor_as(3, mip_image_node, AccessType::General, mip2_view)
.record_compute(move |compute, _bindings| {
compute.dispatch(width / 8 + 1, height / 8 + 1, 1);
});
// ------------------------
// BLIT
// ------------------------
// Uncomment to display mip
// Intrestingly the WRITE-AFTER-WRITE goes away if this is run.
//frame
// .render_graph
// .begin_pass("blit_to_swapchain")
// .bind_pipeline(&blit_pipeline)
// .read_descriptor(0, mip_image_node)
// .load_color(0, frame.swapchain_image)
// .store_color(0, frame.swapchain_image)
// .record_subpass(move |subpass, _| {
// subpass.draw_indexed(3, 1, 0, 0, 0);
// });
})?)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment