Use transient buffers as staging area for uploads.
Allow passing transient buffers to more functions.
use std::path::Path;
-use narcissus_core::{default, obj, Widen};
-use narcissus_gpu::{
- Access, Buffer, BufferDesc, BufferImageCopy, BufferUsageFlags, Device, Extent3d, Image,
- ImageAspectFlags, ImageBarrier, ImageDesc, ImageDimension, ImageFormat, ImageLayout,
- ImageUsageFlags, MemoryLocation, Offset3d, ThreadToken,
-};
+use narcissus_core::{obj, Widen};
+use narcissus_gpu::{Buffer, BufferDesc, BufferUsageFlags, Device, MemoryLocation};
use narcissus_image as image;
use narcissus_maths::{vec2, vec3, vec4, Vec2, Vec3};
texture
}
-pub fn create_buffer_with_data<T>(
+pub fn create_host_buffer_with_data<T>(
device: &dyn Device,
usage: BufferUsageFlags,
data: &[T],
)
}
}
-
-pub fn create_image_with_data(
- device: &dyn Device,
- thread_token: &ThreadToken,
- width: u32,
- height: u32,
- data: &[u8],
-) -> Image {
- let frame = device.begin_frame();
-
- let buffer = create_buffer_with_data(device, BufferUsageFlags::TRANSFER, data);
-
- let image = device.create_image(&ImageDesc {
- location: MemoryLocation::Device,
- usage: ImageUsageFlags::SAMPLED | ImageUsageFlags::TRANSFER,
- dimension: ImageDimension::Type2d,
- format: ImageFormat::RGBA8_SRGB,
- initial_layout: ImageLayout::Optimal,
- width,
- height,
- depth: 1,
- layer_count: 1,
- mip_levels: 1,
- });
-
- let mut cmd_buffer = device.create_cmd_buffer(&frame, thread_token);
-
- device.cmd_barrier(
- &mut cmd_buffer,
- None,
- &[ImageBarrier::layout_optimal(
- &[Access::None],
- &[Access::TransferWrite],
- image,
- ImageAspectFlags::COLOR,
- )],
- );
-
- device.cmd_copy_buffer_to_image(
- &mut cmd_buffer,
- buffer,
- image,
- ImageLayout::Optimal,
- &[BufferImageCopy {
- buffer_offset: 0,
- buffer_row_length: 0,
- buffer_image_height: 0,
- image_subresource: default(),
- image_offset: Offset3d { x: 0, y: 0, z: 0 },
- image_extent: Extent3d {
- width,
- height,
- depth: 1,
- },
- }],
- );
-
- device.cmd_barrier(
- &mut cmd_buffer,
- None,
- &[ImageBarrier::layout_optimal(
- &[Access::TransferWrite],
- &[Access::FragmentShaderSampledImageRead],
- image,
- ImageAspectFlags::COLOR,
- )],
- );
-
- device.submit(&frame, cmd_buffer);
-
- device.destroy_buffer(&frame, buffer);
-
- device.end_frame(frame);
-
- image
-}
fonts::{FontFamily, Fonts},
pipelines::{BasicPipeline, TextPipeline},
};
-use helpers::{create_buffer_with_data, create_image_with_data, load_image, load_obj};
+use helpers::{create_host_buffer_with_data, load_image, load_obj};
use mapped_buffer::MappedBuffer;
use narcissus_app::{create_app, Event, Key, PressedState, WindowDesc};
use narcissus_core::{default, rand::Pcg64, slice::array_windows};
let fonts = Fonts::new();
let mut glyph_cache = GlyphCache::new(&fonts, GLYPH_CACHE_SIZE, GLYPH_CACHE_SIZE, 1);
- let blåhaj_image = load_image("bins/narcissus/data/blåhaj.png");
+ let blåhaj_image_data = load_image("bins/narcissus/data/blåhaj.png");
let (blåhaj_vertices, blåhaj_indices) = load_obj("bins/narcissus/data/blåhaj.obj");
- let blåhaj_vertex_buffer = create_buffer_with_data(
+ let blåhaj_vertex_buffer = create_host_buffer_with_data(
device.as_ref(),
BufferUsageFlags::STORAGE,
blåhaj_vertices.as_slice(),
);
- let blåhaj_index_buffer = create_buffer_with_data(
+ let blåhaj_index_buffer = create_host_buffer_with_data(
device.as_ref(),
BufferUsageFlags::INDEX,
blåhaj_indices.as_slice(),
);
- let blåhaj_image = create_image_with_data(
- device.as_ref(),
- &thread_token,
- blåhaj_image.width() as u32,
- blåhaj_image.height() as u32,
- blåhaj_image.as_slice(),
- );
+ let blåhaj_image = device.create_image(&ImageDesc {
+ location: MemoryLocation::Device,
+ usage: ImageUsageFlags::SAMPLED | ImageUsageFlags::TRANSFER,
+ dimension: ImageDimension::Type2d,
+ format: ImageFormat::RGBA8_SRGB,
+ initial_layout: ImageLayout::Optimal,
+ width: blåhaj_image_data.width() as u32,
+ height: blåhaj_image_data.height() as u32,
+ depth: 1,
+ layer_count: 1,
+ mip_levels: 1,
+ });
let mut basic_transform_buffer = MappedBuffer::new(
device.as_ref(),
{
let frame = device.begin_frame();
+
+ let mut blåhaj_buffer = device.request_transient_buffer(
+ &frame,
+ &thread_token,
+ BufferUsageFlags::TRANSFER,
+ blåhaj_image_data.as_slice().len(),
+ );
+
+ blåhaj_buffer.copy_from_slice(blåhaj_image_data.as_slice());
+
let mut cmd_buffer = device.create_cmd_buffer(&frame, &thread_token);
+ device.cmd_barrier(
+ &mut cmd_buffer,
+ None,
+ &[
+ ImageBarrier::layout_optimal(
+ &[Access::None],
+ &[Access::ShaderSampledImageRead],
+ glyph_atlas,
+ ImageAspectFlags::COLOR,
+ ),
+ ImageBarrier::layout_optimal(
+ &[Access::None],
+ &[Access::TransferWrite],
+ blåhaj_image,
+ ImageAspectFlags::COLOR,
+ ),
+ ],
+ );
+
+ device.cmd_copy_buffer_to_image(
+ &mut cmd_buffer,
+ blåhaj_buffer.into(),
+ blåhaj_image,
+ ImageLayout::Optimal,
+ &[BufferImageCopy {
+ buffer_offset: 0,
+ buffer_row_length: 0,
+ buffer_image_height: 0,
+ image_subresource: default(),
+ image_offset: Offset3d { x: 0, y: 0, z: 0 },
+ image_extent: Extent3d {
+ width: blåhaj_image_data.width() as u32,
+ height: blåhaj_image_data.width() as u32,
+ depth: 1,
+ },
+ }],
+ );
+
device.cmd_barrier(
&mut cmd_buffer,
None,
&[ImageBarrier::layout_optimal(
- &[Access::None],
- &[Access::ShaderSampledImageRead],
- glyph_atlas,
+ &[Access::TransferWrite],
+ &[Access::FragmentShaderSampledImageRead],
+ blåhaj_image,
ImageAspectFlags::COLOR,
)],
);
+
device.submit(&frame, cmd_buffer);
device.end_frame(frame);
}
let width = atlas_width;
let height = atlas_height;
let image = glyph_atlas;
- let data = texture;
- let buffer = create_buffer_with_data(device.as_ref(), BufferUsageFlags::TRANSFER, data);
+ let mut buffer = device.request_transient_buffer(
+ &frame,
+ &thread_token,
+ BufferUsageFlags::TRANSFER,
+ texture.len(),
+ );
+
+ buffer.copy_from_slice(texture);
device.cmd_barrier(
&mut cmd_buffer,
device.cmd_copy_buffer_to_image(
&mut cmd_buffer,
- buffer,
+ buffer.into(),
image,
ImageLayout::Optimal,
&[BufferImageCopy {
ImageAspectFlags::COLOR,
)],
);
-
- device.destroy_buffer(&frame, buffer);
}
device.cmd_begin_rendering(
#[allow(unused)]
#[repr(C)]
-#[repr(align(16))]
pub struct BasicUniforms {
pub clip_from_model: Mat4,
}
thread_token,
BufferUsageFlags::UNIFORM,
std::mem::size_of::<BasicUniforms>(),
- std::mem::align_of::<BasicUniforms>(),
);
uniform_buffer.copy_from_slice(basic_uniforms.as_bytes());
],
);
- device.cmd_set_index_buffer(cmd_buffer, index_buffer, 0, IndexType::U16);
+ device.cmd_set_index_buffer(cmd_buffer, index_buffer.into(), 0, IndexType::U16);
}
}
#[allow(unused)]
#[repr(C)]
-#[repr(align(16))]
pub struct TextUniforms {
pub screen_width: u32,
pub screen_height: u32,
thread_token,
BufferUsageFlags::UNIFORM,
std::mem::size_of::<TextUniforms>(),
- std::mem::align_of::<TextUniforms>(),
);
uniforms.copy_from_slice(text_uniforms.as_bytes());
delay_queue::DelayQueue,
frame_counter::FrameCounter,
tlsf::{self, Tlsf},
- Access, Bind, BindGroupLayout, BindGroupLayoutDesc, BindingType, BlendMode, Buffer, BufferBind,
+ Access, Bind, BindGroupLayout, BindGroupLayoutDesc, BindingType, BlendMode, Buffer, BufferArg,
BufferDesc, BufferImageCopy, BufferUsageFlags, ClearValue, CmdBuffer, CompareOp,
ComputePipelineDesc, CullingMode, Device, Extent2d, Extent3d, Frame, FrontFace, GlobalBarrier,
GpuConcurrent, GraphicsPipelineDesc, Image, ImageAspectFlags, ImageBarrier, ImageBlit,
thread_token: &'a ThreadToken,
usage: BufferUsageFlags,
size: usize,
- align: usize,
) -> TransientBuffer<'a> {
- self.request_transient_buffer(frame, thread_token, usage, size as u64, align as u64)
+ self.request_transient_buffer(frame, thread_token, usage, size as u64)
}
fn create_cmd_buffer<'a, 'thread>(
fn cmd_copy_buffer_to_image(
&self,
cmd_buffer: &mut CmdBuffer,
- src_buffer: Buffer,
+ src_buffer: BufferArg,
dst_image: Image,
dst_image_layout: ImageLayout,
copies: &[BufferImageCopy],
) {
let arena = HybridArena::<4096>::new();
+ let (src_buffer, base_offset) = match src_buffer {
+ BufferArg::Unmanaged(buffer) => {
+ (self.buffer_pool.lock().get(buffer.0).unwrap().buffer, 0)
+ }
+ BufferArg::Transient(buffer) => (vk::Buffer::from_raw(buffer.buffer), buffer.offset),
+ };
+
let regions = arena.alloc_slice_fill_iter(copies.iter().map(|copy| vk::BufferImageCopy {
- buffer_offset: copy.buffer_offset,
+ buffer_offset: copy.buffer_offset + base_offset,
buffer_row_length: copy.buffer_row_length,
buffer_image_height: copy.buffer_image_height,
image_subresource: vulkan_subresource_layers(©.image_subresource),
image_extent: copy.image_extent.into(),
}));
- let src_buffer = self
- .buffer_pool
- .lock()
- .get(src_buffer.0)
- .expect("invalid buffer handle")
- .buffer;
-
let dst_image = self
.image_pool
.lock()
TypedBind::UniformBuffer(buffers) => {
let buffer_pool = self.buffer_pool.lock();
let buffer_infos_iter = buffers.iter().map(|buffer| match buffer {
- BufferBind::Unmanaged(buffer) => {
+ BufferArg::Unmanaged(buffer) => {
let buffer = buffer_pool.get(buffer.0).unwrap().buffer;
vk::DescriptorBufferInfo {
buffer,
range: vk::WHOLE_SIZE,
}
}
- BufferBind::Transient(transient) => vk::DescriptorBufferInfo {
+ BufferArg::Transient(transient) => vk::DescriptorBufferInfo {
buffer: vk::Buffer::from_raw(transient.buffer),
offset: transient.offset,
range: transient.len as u64,
TypedBind::StorageBuffer(buffers) => {
let buffer_pool = self.buffer_pool.lock();
let buffer_infos_iter = buffers.iter().map(|buffer| match buffer {
- BufferBind::Unmanaged(buffer) => {
+ BufferArg::Unmanaged(buffer) => {
let buffer = buffer_pool.get(buffer.0).unwrap().buffer;
vk::DescriptorBufferInfo {
buffer,
range: vk::WHOLE_SIZE,
}
}
- BufferBind::Transient(transient) => vk::DescriptorBufferInfo {
+ BufferArg::Transient(transient) => vk::DescriptorBufferInfo {
buffer: vk::Buffer::from_raw(transient.buffer),
offset: transient.offset,
range: transient.len as u64,
fn cmd_set_index_buffer(
&self,
cmd_buffer: &mut CmdBuffer,
- buffer: Buffer,
+ buffer: BufferArg,
offset: u64,
index_type: IndexType,
) {
- let buffer = self.buffer_pool.lock().get(buffer.0).unwrap().buffer;
+ let (buffer, base_offset) = match buffer {
+ BufferArg::Unmanaged(buffer) => {
+ (self.buffer_pool.lock().get(buffer.0).unwrap().buffer, 0)
+ }
+ BufferArg::Transient(buffer) => (vk::Buffer::from_raw(buffer.buffer), buffer.offset),
+ };
+
let command_buffer = self.cmd_buffer_mut(cmd_buffer).command_buffer;
let index_type = vulkan_index_type(index_type);
unsafe {
- self.device_fn
- .cmd_bind_index_buffer(command_buffer, buffer, offset, index_type)
+ self.device_fn.cmd_bind_index_buffer(
+ command_buffer,
+ buffer,
+ offset + base_offset,
+ index_type,
+ )
}
}
thread_token: &'a ThreadToken,
usage: BufferUsageFlags,
size: u64,
- align: u64,
) -> TransientBuffer<'a> {
let frame = self.frame(frame);
let per_thread = frame.per_thread.get(thread_token);
let mut allocator = per_thread.transient_buffer_allocator.borrow_mut();
assert!(size <= VULKAN_CONSTANTS.transient_buffer_size);
- assert!(align != 0 && align.is_power_of_two());
+
+ let align = 1;
let align = if usage.contains(BufferUsageFlags::UNIFORM) {
align.max(
len: size as usize,
buffer: current.buffer.as_raw(),
offset: allocator.offset,
- _phantom: &PhantomData,
+ phantom: PhantomData,
}
}
len: usize,
buffer: u64,
offset: u64,
- _phantom: &'a PhantomData<()>,
+ phantom: PhantomData<&'a u8>,
}
impl<'a> TransientBuffer<'a> {
pub typed: TypedBind<'a>,
}
-pub enum BufferBind<'a> {
+pub enum BufferArg<'a> {
Unmanaged(Buffer),
Transient(TransientBuffer<'a>),
}
-impl<'a> From<Buffer> for BufferBind<'a> {
+impl<'a> From<Buffer> for BufferArg<'a> {
fn from(value: Buffer) -> Self {
- BufferBind::Unmanaged(value)
+ BufferArg::Unmanaged(value)
}
}
-impl<'a> From<TransientBuffer<'a>> for BufferBind<'a> {
+impl<'a> From<TransientBuffer<'a>> for BufferArg<'a> {
fn from(value: TransientBuffer<'a>) -> Self {
- BufferBind::Transient(value)
+ BufferArg::Transient(value)
}
}
pub enum TypedBind<'a> {
Sampler(&'a [Sampler]),
Image(&'a [(ImageLayout, Image)]),
- UniformBuffer(&'a [BufferBind<'a>]),
- StorageBuffer(&'a [BufferBind<'a>]),
+ UniformBuffer(&'a [BufferArg<'a>]),
+ StorageBuffer(&'a [BufferArg<'a>]),
}
#[derive(Clone, Copy, PartialEq, Eq)]
thread_token: &'a ThreadToken,
usage: BufferUsageFlags,
size: usize,
- align: usize,
) -> TransientBuffer<'a>;
#[must_use]
fn cmd_set_index_buffer(
&self,
cmd_buffer: &mut CmdBuffer,
- buffer: Buffer,
+ buffer: BufferArg,
offset: u64,
index_type: IndexType,
);
fn cmd_copy_buffer_to_image(
&self,
cmd_buffer: &mut CmdBuffer,
- src_buffer: Buffer,
+ src_buffer: BufferArg,
dst_image: Image,
dst_image_layout: ImageLayout,
copies: &[BufferImageCopy],