Skip to content

Instantly share code, notes, and snippets.

@Dooskington
Created October 9, 2018 13:45
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Dooskington/8f09e560735ee3efa296f6bdef8338e0 to your computer and use it in GitHub Desktop.
Save Dooskington/8f09e560735ee3efa296f6bdef8338e0 to your computer and use it in GitHub Desktop.
// Create texture
let (texture_image, texture_memory, texture_view, texture_sampler) = {
let img = image::open("res/textures/costanza.png")
.expect("Failed to load image!")
.to_rgba();
let (width, height) = img.dimensions();
let (texture_image, texture_memory, texture_view) = create_image(
&device,
physical_device,
width,
height,
Format::Rgba8Srgb,
img::Usage::TRANSFER_DST | img::Usage::SAMPLED,
Aspects::COLOR);
let texture_sampler = device.create_sampler(img::SamplerInfo::new(Filter::Linear, WrapMode::Tile));
// Write data into texture
{
let row_alignment_mask =
physical_device.limits().min_buffer_copy_pitch_alignment as u32 - 1;
let image_stride: usize = 4;
let row_pitch =
(width * image_stride as u32 + row_alignment_mask) & !row_alignment_mask;
let upload_size: u64 = (height * row_pitch).into();
let (image_upload_buffer, mut image_upload_memory) = create_buffer(
&device,
physical_device,
buffer::Usage::TRANSFER_SRC,
Properties::CPU_VISIBLE,
upload_size,
);
{
let mut data = device
.acquire_mapping_writer::<u8>(&image_upload_memory, 0..upload_size)
.unwrap();
for y in 0..height as usize {
let row = &(*img)[y * (width as usize) * image_stride
..(y + 1) * (width as usize) * image_stride];
let dest_base = y * row_pitch as usize;
data[dest_base..dest_base + row.len()].copy_from_slice(row);
}
device.release_mapping_writer(data);
}
// Submit commands to transfer data
let submit = {
let mut cmd_buffer = command_pool.acquire_command_buffer(false);
let image_barrier = Barrier::Image {
states: (Access::empty(), Layout::Undefined)
..(Access::TRANSFER_WRITE, Layout::TransferDstOptimal),
target: &texture_image,
range: SubresourceRange {
aspects: Aspects::COLOR,
levels: 0..1,
layers: 0..1,
},
};
cmd_buffer.pipeline_barrier(
PipelineStage::TOP_OF_PIPE..PipelineStage::TRANSFER,
Dependencies::empty(),
&[image_barrier]
);
cmd_buffer.copy_buffer_to_image(
&image_upload_buffer,
&texture_image,
Layout::TransferDstOptimal,
&[BufferImageCopy {
buffer_offset: 0,
buffer_width: row_pitch / (image_stride as u32),
buffer_height: height as u32,
image_layers: SubresourceLayers {
aspects: Aspects::COLOR,
level: 0,
layers: 0..1,
},
image_offset: Offset { x: 0, y: 0, z: 0 },
image_extent: Extent { width, height, depth: 1 },
}],
);
let image_barrier = Barrier::Image {
states: (Access::TRANSFER_WRITE, Layout::TransferDstOptimal)
..(Access::SHADER_READ, Layout::ShaderReadOnlyOptimal),
target: &texture_image,
range: SubresourceRange {
aspects: Aspects::COLOR,
levels: 0..1,
layers: 0..1,
},
};
cmd_buffer.pipeline_barrier(
PipelineStage::TRANSFER..PipelineStage::FRAGMENT_SHADER,
Dependencies::empty(),
&[image_barrier],
);
cmd_buffer.finish()
};
let submission = Submission::new().submit(Some(submit));
queue_group.queues[0].submit(submission, Some(&frame_fence));
device.wait_for_fence(&frame_fence, !0);
// Destroy our staging resources
device.destroy_buffer(image_upload_buffer);
device.free_memory(image_upload_memory);
}
(texture_image, texture_memory, texture_view, texture_sampler)
};
fn create_image(
device: &impl Device<backend::Backend>,
physical_device: &PhysicalDevice<backend::Backend>,
width: u32,
height: u32,
format: Format,
usage: img::Usage,
aspects: Aspects,
) -> (GfxImage, GfxMemory, GfxImageView) {
// Get a list of available memory types
let memory_types = physical_device.memory_properties().memory_types;
let kind = img::Kind::D2(width, height, 1, 1);
let unbound_image = device
.create_image(
kind,
1,
format,
img::Tiling::Optimal,
usage,
ViewCapabilities::empty(),
).expect("Failed to create unbound image!");
let requirements = device.get_image_requirements(&unbound_image);
let device_type = memory_types
.iter()
.enumerate()
.position(|(id, memory_type)| {
requirements.type_mask & (1_u64 << id) != 0
&& memory_type.properties.contains(Properties::DEVICE_LOCAL)
}).unwrap()
.into();
let image_memory = device
.allocate_memory(device_type, requirements.size)
.expect("Failed to allocate image memory!");
let image = device
.bind_image_memory(&image_memory, 0, unbound_image)
.expect("Failed to bind image memory!");
let image_view = device
.create_image_view(
&image,
img::ViewKind::D2,
format,
Swizzle::NO,
img::SubresourceRange {
aspects,
levels: 0..1,
layers: 0..1,
},
).expect("Failed to create image view!");
(image, image_memory, image_view)
}
fn create_buffer(
device: &impl Device<backend::Backend>,
physical_device: &PhysicalDevice<backend::Backend>,
usage: buffer::Usage,
properties: Properties,
buffer_len: u64,
) -> (GfxBuffer, GfxMemory) {
// Get a list of available memory types
let memory_types = physical_device.memory_properties().memory_types;
// First create an unbound buffer
let unbound_buffer = device.create_buffer(buffer_len, usage).unwrap();
// Get the memory requirements for this buffer
let mem_requirements = device.get_buffer_requirements(&unbound_buffer);
// Filter through memory types to find one that is appropriate.
let upload_type = memory_types
.iter()
.enumerate()
.find(|(id, ty)| {
let type_supported = mem_requirements.type_mask & (1_u64 << id) != 0;
type_supported && ty.properties.contains(properties)
})
.map(|(id, _ty)| MemoryTypeId(id))
.expect("Could not find appropriate vertex buffer memory type!");
// Now allocate the memory and bind our buffer to it.
let buffer_memory = device
.allocate_memory(upload_type, mem_requirements.size)
.unwrap();
let buffer = device
.bind_buffer_memory(&buffer_memory, 0, unbound_buffer)
.unwrap();
(buffer, buffer_memory)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment