Rework mapped memory, add BufferContents trait with bytemuck (#1853)

* Rework mapped memory, add `BufferContents` trait with bytemuck

* Platform fix
This commit is contained in:
Rua 2022-03-06 20:30:49 +01:00 committed by GitHub
parent 6061fb738a
commit c70fcc575f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
84 changed files with 4329 additions and 4294 deletions

View File

@ -17,9 +17,9 @@ winit = "0.26"
# and winit doesn't know about vulkano, so import a crate that will provide a link between the two.
vulkano-win = { path = "../vulkano-win" }
bytemuck = { version = "1.7", features = ["derive", "extern_crate_std", "min_const_generics"] }
cgmath = "0.18"
png = "0.17"
time = "0.3"
serde = { version = "1.0", features = ["derive"] }
ron = "0.7"
rand = "0.8.4"

View File

@ -13,15 +13,18 @@
// been more or more used for general-purpose operations as well. This is called "General-Purpose
// GPU", or *GPGPU*. This is what this example demonstrates.
use vulkano::buffer::{BufferUsage, CpuAccessibleBuffer};
use vulkano::command_buffer::{AutoCommandBufferBuilder, CommandBufferUsage};
use vulkano::descriptor_set::{PersistentDescriptorSet, WriteDescriptorSet};
use vulkano::device::physical::{PhysicalDevice, PhysicalDeviceType};
use vulkano::device::{Device, DeviceCreateInfo, DeviceExtensions, QueueCreateInfo};
use vulkano::instance::Instance;
use vulkano::pipeline::{ComputePipeline, Pipeline, PipelineBindPoint};
use vulkano::sync;
use vulkano::sync::GpuFuture;
use vulkano::{
buffer::{BufferUsage, CpuAccessibleBuffer},
command_buffer::{AutoCommandBufferBuilder, CommandBufferUsage},
descriptor_set::{PersistentDescriptorSet, WriteDescriptorSet},
device::{
physical::{PhysicalDevice, PhysicalDeviceType},
Device, DeviceCreateInfo, DeviceExtensions, QueueCreateInfo,
},
instance::Instance,
pipeline::{ComputePipeline, Pipeline, PipelineBindPoint},
sync::{self, GpuFuture},
};
fn main() {
// As with other examples, the first step is to create an instance.

View File

@ -19,35 +19,48 @@
// See: https://github.com/vulkano-rs/vulkano/issues/1221
// Finally, I have not profiled CpuBufferPool against CpuAccessibleBuffer
use std::sync::Arc;
use std::time::{SystemTime, UNIX_EPOCH};
use vulkano::buffer::CpuBufferPool;
use vulkano::command_buffer::{AutoCommandBufferBuilder, CommandBufferUsage, SubpassContents};
use vulkano::device::physical::{PhysicalDevice, PhysicalDeviceType};
use vulkano::device::{Device, DeviceCreateInfo, DeviceExtensions, QueueCreateInfo};
use vulkano::image::view::ImageView;
use vulkano::image::{ImageAccess, ImageUsage, SwapchainImage};
use vulkano::instance::{Instance, InstanceCreateInfo};
use vulkano::pipeline::graphics::input_assembly::InputAssemblyState;
use vulkano::pipeline::graphics::vertex_input::BuffersDefinition;
use vulkano::pipeline::graphics::viewport::{Viewport, ViewportState};
use vulkano::pipeline::GraphicsPipeline;
use vulkano::render_pass::{Framebuffer, FramebufferCreateInfo, RenderPass, Subpass};
use vulkano::swapchain::{
self, AcquireError, Swapchain, SwapchainCreateInfo, SwapchainCreationError,
use bytemuck::{Pod, Zeroable};
use std::{
sync::Arc,
time::{SystemTime, UNIX_EPOCH},
};
use vulkano::{
buffer::CpuBufferPool,
command_buffer::{AutoCommandBufferBuilder, CommandBufferUsage, SubpassContents},
device::{
physical::{PhysicalDevice, PhysicalDeviceType},
Device, DeviceCreateInfo, DeviceExtensions, QueueCreateInfo,
},
image::{view::ImageView, ImageAccess, ImageUsage, SwapchainImage},
impl_vertex,
instance::{Instance, InstanceCreateInfo},
pipeline::{
graphics::{
input_assembly::InputAssemblyState,
vertex_input::BuffersDefinition,
viewport::{Viewport, ViewportState},
},
GraphicsPipeline,
},
render_pass::{Framebuffer, FramebufferCreateInfo, RenderPass, Subpass},
swapchain::{
acquire_next_image, AcquireError, Swapchain, SwapchainCreateInfo, SwapchainCreationError,
},
sync::{self, FlushError, GpuFuture},
};
use vulkano::sync::{self, FlushError, GpuFuture};
use vulkano_win::VkSurfaceBuild;
use winit::event::{Event, WindowEvent};
use winit::event_loop::{ControlFlow, EventLoop};
use winit::window::{Window, WindowBuilder};
use winit::{
event::{Event, WindowEvent},
event_loop::{ControlFlow, EventLoop},
window::{Window, WindowBuilder},
};
#[repr(C)]
#[derive(Default, Debug, Clone)]
#[derive(Clone, Copy, Debug, Default, Zeroable, Pod)]
struct Vertex {
position: [f32; 2],
}
vulkano::impl_vertex!(Vertex, position);
impl_vertex!(Vertex, position);
fn main() {
let required_extensions = vulkano_win::required_extensions();
@ -242,7 +255,7 @@ fn main() {
}
let (image_num, suboptimal, acquire_future) =
match swapchain::acquire_next_image(swapchain.clone(), None) {
match acquire_next_image(swapchain.clone(), None) {
Ok(r) => r,
Err(AcquireError::OutOfDate) => {
recreate_swapchain = true;

View File

@ -8,24 +8,32 @@
// according to those terms.
use std::sync::Arc;
use vulkano::command_buffer::{AutoCommandBufferBuilder, CommandBufferUsage, SubpassContents};
use vulkano::device::physical::{PhysicalDevice, PhysicalDeviceType};
use vulkano::device::{Device, DeviceCreateInfo, DeviceExtensions, QueueCreateInfo};
use vulkano::format::ClearValue;
use vulkano::image::attachment::{ClearAttachment, ClearRect};
use vulkano::image::{view::ImageView, ImageUsage, SwapchainImage};
use vulkano::instance::{Instance, InstanceCreateInfo};
use vulkano::pipeline::graphics::viewport::ViewportState;
use vulkano::pipeline::GraphicsPipeline;
use vulkano::render_pass::{Framebuffer, FramebufferCreateInfo, RenderPass, Subpass};
use vulkano::swapchain::{
self, AcquireError, Swapchain, SwapchainCreateInfo, SwapchainCreationError,
use vulkano::{
command_buffer::{AutoCommandBufferBuilder, CommandBufferUsage, SubpassContents},
device::{
physical::{PhysicalDevice, PhysicalDeviceType},
Device, DeviceCreateInfo, DeviceExtensions, QueueCreateInfo,
},
format::ClearValue,
image::{
attachment::{ClearAttachment, ClearRect},
view::ImageView,
ImageUsage, SwapchainImage,
},
instance::{Instance, InstanceCreateInfo},
pipeline::{graphics::viewport::ViewportState, GraphicsPipeline},
render_pass::{Framebuffer, FramebufferCreateInfo, RenderPass, Subpass},
swapchain::{
acquire_next_image, AcquireError, Swapchain, SwapchainCreateInfo, SwapchainCreationError,
},
sync::{self, FlushError, GpuFuture},
};
use vulkano::sync::{self, FlushError, GpuFuture};
use vulkano_win::VkSurfaceBuild;
use winit::event::{Event, WindowEvent};
use winit::event_loop::{ControlFlow, EventLoop};
use winit::window::{Window, WindowBuilder};
use winit::{
event::{Event, WindowEvent},
event_loop::{ControlFlow, EventLoop},
window::{Window, WindowBuilder},
};
fn main() {
// The start of this example is exactly the same as `triangle`. You should read the
@ -209,7 +217,7 @@ fn main() {
}
let (image_num, suboptimal, acquire_future) =
match swapchain::acquire_next_image(swapchain.clone(), None) {
match acquire_next_image(swapchain.clone(), None) {
Ok(r) => r,
Err(AcquireError::OutOfDate) => {
recreate_swapchain = true;

View File

@ -7,15 +7,18 @@
// notice may not be copied, modified, or distributed except
// according to those terms.
use vulkano::device::physical::{PhysicalDevice, PhysicalDeviceType};
use vulkano::device::{Device, DeviceCreateInfo, DeviceExtensions, QueueCreateInfo};
use vulkano::format::Format;
use vulkano::image::ImageDimensions;
use vulkano::image::ImmutableImage;
use vulkano::image::MipmapsCount;
use vulkano::instance::debug::{DebugCallback, MessageSeverity, MessageType};
use vulkano::instance::{self, InstanceCreateInfo};
use vulkano::instance::{Instance, InstanceExtensions};
use vulkano::{
device::{
physical::{PhysicalDevice, PhysicalDeviceType},
Device, DeviceCreateInfo, DeviceExtensions, QueueCreateInfo,
},
format::Format,
image::{ImageDimensions, ImmutableImage, MipmapsCount},
instance::{
debug::{DebugCallback, MessageSeverity, MessageType},
layers_list, Instance, InstanceCreateInfo, InstanceExtensions,
},
};
fn main() {
// Vulkano Debugging Example Code
@ -43,7 +46,7 @@ fn main() {
// and you should verify that list for safety - Vulkano will return an error if you specify
// any layers that are not installed on this system. That code to do could look like this:
println!("List of Vulkan debugging layers available to use:");
let mut layers = instance::layers_list().unwrap();
let mut layers = layers_list().unwrap();
while let Some(l) = layers.next() {
println!("\t{}", l.name());
}
@ -158,9 +161,9 @@ fn main() {
height: 4096,
array_layers: 1,
};
const DATA: [[u8; 4]; 4096 * 4096] = [[0; 4]; 4096 * 4096];
static DATA: [[u8; 4]; 4096 * 4096] = [[0; 4]; 4096 * 4096];
let _ = ImmutableImage::from_iter(
DATA.iter().cloned(),
DATA.iter().copied(),
dimensions,
MipmapsCount::One,
pixel_format,

View File

@ -7,22 +7,26 @@
// notice may not be copied, modified, or distributed except
// according to those terms.
use bytemuck::{Pod, Zeroable};
use std::sync::Arc;
use vulkano::buffer::{BufferUsage, CpuAccessibleBuffer, TypedBufferAccess};
use vulkano::command_buffer::{
AutoCommandBufferBuilder, CommandBufferUsage, SecondaryAutoCommandBuffer,
use vulkano::{
buffer::{BufferUsage, CpuAccessibleBuffer, TypedBufferAccess},
command_buffer::{AutoCommandBufferBuilder, CommandBufferUsage, SecondaryAutoCommandBuffer},
descriptor_set::{PersistentDescriptorSet, WriteDescriptorSet},
device::Queue,
image::ImageViewAbstract,
impl_vertex,
pipeline::{
graphics::{
color_blend::{AttachmentBlend, BlendFactor, BlendOp, ColorBlendState},
input_assembly::InputAssemblyState,
vertex_input::BuffersDefinition,
viewport::{Viewport, ViewportState},
},
GraphicsPipeline, Pipeline, PipelineBindPoint,
},
render_pass::Subpass,
};
use vulkano::descriptor_set::{PersistentDescriptorSet, WriteDescriptorSet};
use vulkano::device::Queue;
use vulkano::image::ImageViewAbstract;
use vulkano::pipeline::graphics::color_blend::{
AttachmentBlend, BlendFactor, BlendOp, ColorBlendState,
};
use vulkano::pipeline::graphics::input_assembly::InputAssemblyState;
use vulkano::pipeline::graphics::vertex_input::BuffersDefinition;
use vulkano::pipeline::graphics::viewport::{Viewport, ViewportState};
use vulkano::pipeline::{GraphicsPipeline, Pipeline, PipelineBindPoint};
use vulkano::render_pass::Subpass;
/// Allows applying an ambient lighting to a scene.
pub struct AmbientLightingSystem {
@ -36,12 +40,7 @@ impl AmbientLightingSystem {
pub fn new(gfx_queue: Arc<Queue>, subpass: Subpass) -> AmbientLightingSystem {
// TODO: vulkano doesn't allow us to draw without a vertex buffer, otherwise we could
// hard-code these values in the shader
let vertex_buffer = {
CpuAccessibleBuffer::from_iter(
gfx_queue.device().clone(),
BufferUsage::all(),
false,
[
let vertices = [
Vertex {
position: [-1.0, -1.0],
},
@ -51,9 +50,13 @@ impl AmbientLightingSystem {
Vertex {
position: [3.0, -1.0],
},
]
.iter()
.cloned(),
];
let vertex_buffer = {
CpuAccessibleBuffer::from_iter(
gfx_queue.device().clone(),
BufferUsage::all(),
false,
vertices,
)
.expect("failed to create buffer")
};
@ -84,9 +87,9 @@ impl AmbientLightingSystem {
};
AmbientLightingSystem {
gfx_queue: gfx_queue,
vertex_buffer: vertex_buffer,
pipeline: pipeline,
gfx_queue,
vertex_buffer,
pipeline,
}
}
@ -150,11 +153,11 @@ impl AmbientLightingSystem {
}
#[repr(C)]
#[derive(Default, Debug, Clone)]
#[derive(Clone, Copy, Debug, Default, Zeroable, Pod)]
struct Vertex {
position: [f32; 2],
}
vulkano::impl_vertex!(Vertex, position);
impl_vertex!(Vertex, position);
mod vs {
vulkano_shaders::shader! {

View File

@ -7,23 +7,27 @@
// notice may not be copied, modified, or distributed except
// according to those terms.
use bytemuck::{Pod, Zeroable};
use cgmath::Vector3;
use std::sync::Arc;
use vulkano::buffer::{BufferUsage, CpuAccessibleBuffer, TypedBufferAccess};
use vulkano::command_buffer::{
AutoCommandBufferBuilder, CommandBufferUsage, SecondaryAutoCommandBuffer,
use vulkano::{
buffer::{BufferUsage, CpuAccessibleBuffer, TypedBufferAccess},
command_buffer::{AutoCommandBufferBuilder, CommandBufferUsage, SecondaryAutoCommandBuffer},
descriptor_set::{PersistentDescriptorSet, WriteDescriptorSet},
device::Queue,
image::ImageViewAbstract,
impl_vertex,
pipeline::{
graphics::{
color_blend::{AttachmentBlend, BlendFactor, BlendOp, ColorBlendState},
input_assembly::InputAssemblyState,
vertex_input::BuffersDefinition,
viewport::{Viewport, ViewportState},
},
GraphicsPipeline, Pipeline, PipelineBindPoint,
},
render_pass::Subpass,
};
use vulkano::descriptor_set::{PersistentDescriptorSet, WriteDescriptorSet};
use vulkano::device::Queue;
use vulkano::image::ImageViewAbstract;
use vulkano::pipeline::graphics::color_blend::{
AttachmentBlend, BlendFactor, BlendOp, ColorBlendState,
};
use vulkano::pipeline::graphics::input_assembly::InputAssemblyState;
use vulkano::pipeline::graphics::vertex_input::BuffersDefinition;
use vulkano::pipeline::graphics::viewport::{Viewport, ViewportState};
use vulkano::pipeline::{GraphicsPipeline, Pipeline, PipelineBindPoint};
use vulkano::render_pass::Subpass;
/// Allows applying a directional light source to a scene.
pub struct DirectionalLightingSystem {
@ -37,12 +41,7 @@ impl DirectionalLightingSystem {
pub fn new(gfx_queue: Arc<Queue>, subpass: Subpass) -> DirectionalLightingSystem {
// TODO: vulkano doesn't allow us to draw without a vertex buffer, otherwise we could
// hard-code these values in the shader
let vertex_buffer = {
CpuAccessibleBuffer::from_iter(
gfx_queue.device().clone(),
BufferUsage::all(),
false,
[
let vertices = [
Vertex {
position: [-1.0, -1.0],
},
@ -52,9 +51,13 @@ impl DirectionalLightingSystem {
Vertex {
position: [3.0, -1.0],
},
]
.iter()
.cloned(),
];
let vertex_buffer = {
CpuAccessibleBuffer::from_iter(
gfx_queue.device().clone(),
BufferUsage::all(),
false,
vertices,
)
.expect("failed to create buffer")
};
@ -85,9 +88,9 @@ impl DirectionalLightingSystem {
};
DirectionalLightingSystem {
gfx_queue: gfx_queue,
vertex_buffer: vertex_buffer,
pipeline: pipeline,
gfx_queue,
vertex_buffer,
pipeline,
}
}
@ -164,11 +167,11 @@ impl DirectionalLightingSystem {
}
#[repr(C)]
#[derive(Default, Debug, Clone)]
#[derive(Clone, Copy, Debug, Default, Zeroable, Pod)]
struct Vertex {
position: [f32; 2],
}
vulkano::impl_vertex!(Vertex, position);
impl_vertex!(Vertex, position);
mod vs {
vulkano_shaders::shader! {

View File

@ -12,11 +12,7 @@
// The main code is in the `system` module, while the other modules implement the different kinds
// of lighting sources.
pub use self::system::DrawPass;
pub use self::system::Frame;
pub use self::system::FrameSystem;
pub use self::system::LightingPass;
pub use self::system::Pass;
pub use self::system::{DrawPass, Frame, FrameSystem, LightingPass, Pass};
mod ambient_lighting_system;
mod directional_lighting_system;

View File

@ -7,23 +7,27 @@
// notice may not be copied, modified, or distributed except
// according to those terms.
use bytemuck::{Pod, Zeroable};
use cgmath::{Matrix4, Vector3};
use std::sync::Arc;
use vulkano::buffer::{BufferUsage, CpuAccessibleBuffer, TypedBufferAccess};
use vulkano::command_buffer::{
AutoCommandBufferBuilder, CommandBufferUsage, SecondaryAutoCommandBuffer,
use vulkano::{
buffer::{BufferUsage, CpuAccessibleBuffer, TypedBufferAccess},
command_buffer::{AutoCommandBufferBuilder, CommandBufferUsage, SecondaryAutoCommandBuffer},
descriptor_set::{PersistentDescriptorSet, WriteDescriptorSet},
device::Queue,
image::ImageViewAbstract,
impl_vertex,
pipeline::{
graphics::{
color_blend::{AttachmentBlend, BlendFactor, BlendOp, ColorBlendState},
input_assembly::InputAssemblyState,
vertex_input::BuffersDefinition,
viewport::{Viewport, ViewportState},
},
GraphicsPipeline, Pipeline, PipelineBindPoint,
},
render_pass::Subpass,
};
use vulkano::descriptor_set::{PersistentDescriptorSet, WriteDescriptorSet};
use vulkano::device::Queue;
use vulkano::image::ImageViewAbstract;
use vulkano::pipeline::graphics::color_blend::{
AttachmentBlend, BlendFactor, BlendOp, ColorBlendState,
};
use vulkano::pipeline::graphics::input_assembly::InputAssemblyState;
use vulkano::pipeline::graphics::vertex_input::BuffersDefinition;
use vulkano::pipeline::graphics::viewport::{Viewport, ViewportState};
use vulkano::pipeline::{GraphicsPipeline, Pipeline, PipelineBindPoint};
use vulkano::render_pass::Subpass;
pub struct PointLightingSystem {
gfx_queue: Arc<Queue>,
@ -36,12 +40,7 @@ impl PointLightingSystem {
pub fn new(gfx_queue: Arc<Queue>, subpass: Subpass) -> PointLightingSystem {
// TODO: vulkano doesn't allow us to draw without a vertex buffer, otherwise we could
// hard-code these values in the shader
let vertex_buffer = {
CpuAccessibleBuffer::from_iter(
gfx_queue.device().clone(),
BufferUsage::all(),
false,
[
let vertices = [
Vertex {
position: [-1.0, -1.0],
},
@ -51,9 +50,13 @@ impl PointLightingSystem {
Vertex {
position: [3.0, -1.0],
},
]
.iter()
.cloned(),
];
let vertex_buffer = {
CpuAccessibleBuffer::from_iter(
gfx_queue.device().clone(),
BufferUsage::all(),
false,
vertices,
)
.expect("failed to create buffer")
};
@ -84,9 +87,9 @@ impl PointLightingSystem {
};
PointLightingSystem {
gfx_queue: gfx_queue,
vertex_buffer: vertex_buffer,
pipeline: pipeline,
gfx_queue,
vertex_buffer,
pipeline,
}
}
@ -176,11 +179,11 @@ impl PointLightingSystem {
}
#[repr(C)]
#[derive(Default, Debug, Clone)]
#[derive(Clone, Copy, Debug, Default, Zeroable, Pod)]
struct Vertex {
position: [f32; 2],
}
vulkano::impl_vertex!(Vertex, position);
impl_vertex!(Vertex, position);
mod vs {
vulkano_shaders::shader! {

View File

@ -7,29 +7,24 @@
// notice may not be copied, modified, or distributed except
// according to those terms.
use crate::frame::ambient_lighting_system::AmbientLightingSystem;
use crate::frame::directional_lighting_system::DirectionalLightingSystem;
use crate::frame::point_lighting_system::PointLightingSystem;
use cgmath::Matrix4;
use cgmath::SquareMatrix;
use cgmath::Vector3;
use std::sync::Arc;
use vulkano::command_buffer::{
AutoCommandBufferBuilder, CommandBufferUsage, PrimaryAutoCommandBuffer, SecondaryCommandBuffer,
SubpassContents,
use super::{
ambient_lighting_system::AmbientLightingSystem,
directional_lighting_system::DirectionalLightingSystem,
point_lighting_system::PointLightingSystem,
};
use cgmath::{Matrix4, SquareMatrix, Vector3};
use std::sync::Arc;
use vulkano::{
command_buffer::{
AutoCommandBufferBuilder, CommandBufferUsage, PrimaryAutoCommandBuffer,
SecondaryCommandBuffer, SubpassContents,
},
device::Queue,
format::Format,
image::{view::ImageView, AttachmentImage, ImageAccess, ImageUsage, ImageViewAbstract},
render_pass::{Framebuffer, FramebufferCreateInfo, RenderPass, Subpass},
sync::GpuFuture,
};
use vulkano::device::Queue;
use vulkano::format::Format;
use vulkano::image::view::ImageView;
use vulkano::image::AttachmentImage;
use vulkano::image::ImageAccess;
use vulkano::image::ImageUsage;
use vulkano::image::ImageViewAbstract;
use vulkano::render_pass::Framebuffer;
use vulkano::render_pass::FramebufferCreateInfo;
use vulkano::render_pass::RenderPass;
use vulkano::render_pass::Subpass;
use vulkano::sync::GpuFuture;
/// System that contains the necessary facilities for rendering a single frame.
pub struct FrameSystem {

View File

@ -25,26 +25,29 @@
// expensive otherwise. It has some drawbacks, which are the fact that transparent objects must be
// drawn after the lighting, and that the whole process consumes more memory.
use crate::frame::*;
use crate::triangle_draw_system::*;
use cgmath::Matrix4;
use cgmath::SquareMatrix;
use cgmath::Vector3;
use vulkano::device::physical::{PhysicalDevice, PhysicalDeviceType};
use vulkano::device::DeviceCreateInfo;
use vulkano::device::QueueCreateInfo;
use vulkano::device::{Device, DeviceExtensions};
use vulkano::image::view::ImageView;
use vulkano::image::ImageUsage;
use vulkano::instance::{Instance, InstanceCreateInfo};
use vulkano::swapchain;
use vulkano::swapchain::{AcquireError, Swapchain, SwapchainCreateInfo, SwapchainCreationError};
use vulkano::sync;
use vulkano::sync::{FlushError, GpuFuture};
use crate::{
frame::{FrameSystem, Pass},
triangle_draw_system::TriangleDrawSystem,
};
use cgmath::{Matrix4, SquareMatrix, Vector3};
use vulkano::{
device::{
physical::{PhysicalDevice, PhysicalDeviceType},
Device, DeviceCreateInfo, DeviceExtensions, QueueCreateInfo,
},
image::{view::ImageView, ImageUsage},
instance::{Instance, InstanceCreateInfo},
swapchain::{
acquire_next_image, AcquireError, Swapchain, SwapchainCreateInfo, SwapchainCreationError,
},
sync::{self, FlushError, GpuFuture},
};
use vulkano_win::VkSurfaceBuild;
use winit::event::{Event, WindowEvent};
use winit::event_loop::{ControlFlow, EventLoop};
use winit::window::WindowBuilder;
use winit::{
event::{Event, WindowEvent},
event_loop::{ControlFlow, EventLoop},
window::WindowBuilder,
};
mod frame;
mod triangle_draw_system;
@ -182,7 +185,7 @@ fn main() {
}
let (image_num, suboptimal, acquire_future) =
match swapchain::acquire_next_image(swapchain.clone(), None) {
match acquire_next_image(swapchain.clone(), None) {
Ok(r) => r,
Err(AcquireError::OutOfDate) => {
recreate_swapchain = true;

View File

@ -7,18 +7,24 @@
// notice may not be copied, modified, or distributed except
// according to those terms.
use bytemuck::{Pod, Zeroable};
use std::sync::Arc;
use vulkano::buffer::{BufferUsage, CpuAccessibleBuffer, TypedBufferAccess};
use vulkano::command_buffer::{
AutoCommandBufferBuilder, CommandBufferUsage, SecondaryAutoCommandBuffer,
use vulkano::{
buffer::{BufferUsage, CpuAccessibleBuffer, TypedBufferAccess},
command_buffer::{AutoCommandBufferBuilder, CommandBufferUsage, SecondaryAutoCommandBuffer},
device::Queue,
impl_vertex,
pipeline::{
graphics::{
depth_stencil::DepthStencilState,
input_assembly::InputAssemblyState,
vertex_input::BuffersDefinition,
viewport::{Viewport, ViewportState},
},
GraphicsPipeline,
},
render_pass::Subpass,
};
use vulkano::device::Queue;
use vulkano::pipeline::graphics::depth_stencil::DepthStencilState;
use vulkano::pipeline::graphics::input_assembly::InputAssemblyState;
use vulkano::pipeline::graphics::vertex_input::BuffersDefinition;
use vulkano::pipeline::graphics::viewport::{Viewport, ViewportState};
use vulkano::pipeline::GraphicsPipeline;
use vulkano::render_pass::Subpass;
pub struct TriangleDrawSystem {
gfx_queue: Arc<Queue>,
@ -29,12 +35,7 @@ pub struct TriangleDrawSystem {
impl TriangleDrawSystem {
/// Initializes a triangle drawing system.
pub fn new(gfx_queue: Arc<Queue>, subpass: Subpass) -> TriangleDrawSystem {
let vertex_buffer = {
CpuAccessibleBuffer::from_iter(
gfx_queue.device().clone(),
BufferUsage::all(),
false,
[
let vertices = [
Vertex {
position: [-0.5, -0.25],
},
@ -44,9 +45,13 @@ impl TriangleDrawSystem {
Vertex {
position: [0.25, -0.1],
},
]
.iter()
.cloned(),
];
let vertex_buffer = {
CpuAccessibleBuffer::from_iter(
gfx_queue.device().clone(),
BufferUsage::all(),
false,
vertices,
)
.expect("failed to create buffer")
};
@ -68,9 +73,9 @@ impl TriangleDrawSystem {
};
TriangleDrawSystem {
gfx_queue: gfx_queue,
vertex_buffer: vertex_buffer,
pipeline: pipeline,
gfx_queue,
vertex_buffer,
pipeline,
}
}
@ -101,11 +106,11 @@ impl TriangleDrawSystem {
}
#[repr(C)]
#[derive(Default, Debug, Clone)]
#[derive(Clone, Copy, Debug, Default, Zeroable, Pod)]
struct Vertex {
position: [f32; 2],
}
vulkano::impl_vertex!(Vertex, position);
impl_vertex!(Vertex, position);
mod vs {
vulkano_shaders::shader! {

View File

@ -14,17 +14,21 @@
// offset into the buffer to read object data from, without having to
// rebind descriptor sets.
use std::mem;
use vulkano::buffer::{BufferUsage, CpuAccessibleBuffer};
use vulkano::command_buffer::{AutoCommandBufferBuilder, CommandBufferUsage};
use vulkano::descriptor_set::layout::DescriptorType;
use vulkano::descriptor_set::{DescriptorSet, PersistentDescriptorSet, WriteDescriptorSet};
use vulkano::device::physical::{PhysicalDevice, PhysicalDeviceType};
use vulkano::device::{Device, DeviceCreateInfo, DeviceExtensions, QueueCreateInfo};
use vulkano::instance::Instance;
use vulkano::pipeline::{ComputePipeline, Pipeline, PipelineBindPoint};
use vulkano::sync;
use vulkano::sync::GpuFuture;
use std::mem::size_of;
use vulkano::{
buffer::{BufferUsage, CpuAccessibleBuffer},
command_buffer::{AutoCommandBufferBuilder, CommandBufferUsage},
descriptor_set::{
layout::DescriptorType, DescriptorSet, PersistentDescriptorSet, WriteDescriptorSet,
},
device::{
physical::{PhysicalDevice, PhysicalDeviceType},
Device, DeviceCreateInfo, DeviceExtensions, QueueCreateInfo,
},
instance::Instance,
pipeline::{ComputePipeline, Pipeline, PipelineBindPoint},
sync::{self, GpuFuture},
};
fn main() {
let instance = Instance::new(Default::default()).unwrap();
@ -124,7 +128,7 @@ fn main() {
);
println!("Input: {:?}", data);
// Round size up to the next multiple of align.
let align = (mem::size_of::<u32>() + min_dynamic_align - 1) & !(min_dynamic_align - 1);
let align = (size_of::<u32>() + min_dynamic_align - 1) & !(min_dynamic_align - 1);
let aligned_data = {
let mut aligned_data = Vec::with_capacity(align * data.len());
for i in 0..data.len() {
@ -211,8 +215,5 @@ fn main() {
future.wait(None).unwrap();
let output_content = output_buffer.read().unwrap();
println!(
"Output: {:?}",
output_content.iter().cloned().collect::<Vec<u32>>()
);
println!("Output: {:?}", &*output_content);
}

View File

@ -14,20 +14,21 @@
// properly is important to achieve maximal performance that particular device
// can provide.
use std::fs::File;
use std::io::BufWriter;
use std::path::Path;
use vulkano::buffer::{BufferUsage, CpuAccessibleBuffer};
use vulkano::command_buffer::{AutoCommandBufferBuilder, CommandBufferUsage};
use vulkano::descriptor_set::{PersistentDescriptorSet, WriteDescriptorSet};
use vulkano::device::physical::{PhysicalDevice, PhysicalDeviceType};
use vulkano::device::{Device, DeviceCreateInfo, DeviceExtensions, QueueCreateInfo};
use vulkano::format::Format;
use vulkano::image::{view::ImageView, ImageDimensions, StorageImage};
use vulkano::instance::{Instance, InstanceCreateInfo, InstanceExtensions};
use vulkano::pipeline::{ComputePipeline, Pipeline, PipelineBindPoint};
use vulkano::sync;
use vulkano::sync::GpuFuture;
use std::{fs::File, io::BufWriter, path::Path};
use vulkano::{
buffer::{BufferUsage, CpuAccessibleBuffer},
command_buffer::{AutoCommandBufferBuilder, CommandBufferUsage},
descriptor_set::{PersistentDescriptorSet, WriteDescriptorSet},
device::{
physical::{PhysicalDevice, PhysicalDeviceType},
Device, DeviceCreateInfo, DeviceExtensions, QueueCreateInfo,
},
format::Format,
image::{view::ImageView, ImageDimensions, StorageImage},
instance::{Instance, InstanceCreateInfo, InstanceExtensions},
pipeline::{ComputePipeline, Pipeline, PipelineBindPoint},
sync::{self, GpuFuture},
};
fn main() {
let instance = Instance::new(InstanceCreateInfo {

View File

@ -1,18 +1,18 @@
#[cfg(not(target_os = "linux"))]
pub fn main() {}
fn main() {
#[cfg(target_os = "linux")]
linux::main();
}
// TODO: Can this be demonstrated for other platforms as well?
#[cfg(target_os = "linux")]
extern crate glium;
#[cfg(target_os = "linux")]
use glium::glutin::{self, platform::unix::HeadlessContextExt};
#[cfg(target_os = "linux")]
use std::{
mod linux {
use bytemuck::{Pod, Zeroable};
use glium::glutin::{self, platform::unix::HeadlessContextExt};
use std::{
sync::{Arc, Barrier},
time::Instant,
};
#[cfg(target_os = "linux")]
use vulkano::{
};
use vulkano::{
buffer::{BufferUsage, CpuAccessibleBuffer, TypedBufferAccess},
command_buffer::{
submit::SubmitCommandBufferBuilder, AutoCommandBufferBuilder, CommandBufferUsage,
@ -25,12 +25,15 @@ use vulkano::{
},
format::Format,
image::{view::ImageView, ImageCreateFlags, ImageUsage, StorageImage, SwapchainImage},
impl_vertex,
instance::{debug::DebugCallback, Instance, InstanceCreateInfo, InstanceExtensions},
pipeline::{
graphics::color_blend::ColorBlendState,
graphics::input_assembly::{InputAssemblyState, PrimitiveTopology},
graphics::vertex_input::BuffersDefinition,
graphics::viewport::{Scissor, Viewport, ViewportState},
graphics::{
color_blend::ColorBlendState,
input_assembly::{InputAssemblyState, PrimitiveTopology},
vertex_input::BuffersDefinition,
viewport::{Scissor, Viewport, ViewportState},
},
GraphicsPipeline, Pipeline, PipelineBindPoint,
},
render_pass::{Framebuffer, RenderPass, Subpass},
@ -40,17 +43,15 @@ use vulkano::{
now, ExternalSemaphoreHandleTypes, FlushError, GpuFuture, PipelineStages, Semaphore,
SemaphoreCreateInfo,
},
};
#[cfg(target_os = "linux")]
use vulkano_win::VkSurfaceBuild;
#[cfg(target_os = "linux")]
use winit::{
};
use vulkano_win::VkSurfaceBuild;
use winit::{
event::{Event, WindowEvent},
event_loop::{ControlFlow, EventLoop},
window::{Window, WindowBuilder},
};
#[cfg(target_os = "linux")]
fn main() {
};
pub fn main() {
let event_loop_gl = glutin::event_loop::EventLoop::new();
// For some reason, this must be created before the vulkan window
let hrb = glutin::ContextBuilder::new()
@ -65,8 +66,10 @@ fn main() {
.build_surfaceless(&event_loop_gl)
.unwrap();
let display =
glium::HeadlessRenderer::with_debug(hrb_vk, glium::debug::DebugCallbackBehavior::PrintAll)
let display = glium::HeadlessRenderer::with_debug(
hrb_vk,
glium::debug::DebugCallbackBehavior::PrintAll,
)
.unwrap(); // Used for checking device and driver UUIDs
let (
device,
@ -213,7 +216,8 @@ fn main() {
.unwrap();
let mut recreate_swapchain = false;
let mut previous_frame_end: Option<Box<dyn GpuFuture>> = Some(Box::new(now(device.clone())));
let mut previous_frame_end: Option<Box<dyn GpuFuture>> =
Some(Box::new(now(device.clone())));
event_loop.run(move |event, _, control_flow| {
match event {
@ -260,7 +264,9 @@ fn main() {
..swapchain.create_info()
}) {
Ok(r) => r,
Err(SwapchainCreationError::ImageExtentNotSupported { .. }) => return,
Err(SwapchainCreationError::ImageExtentNotSupported { .. }) => {
return
}
Err(e) => panic!("Failed to recreate swapchain: {:?}", e),
};
@ -343,20 +349,18 @@ fn main() {
_ => (),
};
});
}
}
#[cfg(target_os = "linux")]
#[derive(Default, Debug, Clone)]
struct Vertex {
#[repr(C)]
#[derive(Clone, Copy, Debug, Default, Zeroable, Pod)]
struct Vertex {
position: [f32; 2],
}
#[cfg(target_os = "linux")]
vulkano::impl_vertex!(Vertex, position);
}
impl_vertex!(Vertex, position);
#[cfg(target_os = "linux")]
fn vk_setup(
fn vk_setup(
display: glium::HeadlessRenderer,
) -> (
) -> (
Arc<vulkano::device::Device>,
Arc<vulkano::instance::Instance>,
Arc<Swapchain<winit::window::Window>>,
@ -369,7 +373,7 @@ fn vk_setup(
Arc<vulkano::sampler::Sampler>,
Arc<GraphicsPipeline>,
Arc<CpuAccessibleBuffer<[Vertex]>>,
) {
) {
let required_extensions = vulkano_win::required_extensions();
let instance = Instance::new(InstanceCreateInfo {
@ -418,7 +422,9 @@ fn vk_setup(
.filter(|&p| p.supported_extensions().is_superset_of(&device_extensions))
.filter_map(|p| {
p.queue_families()
.find(|&q| q.supports_graphics() && q.supports_surface(&surface).unwrap_or(false))
.find(|&q| {
q.supports_graphics() && q.supports_surface(&surface).unwrap_or(false)
})
.map(|q| (p, q))
})
.filter(|(p, _)| p.properties().driver_uuid.unwrap() == display.driver_uuid().unwrap())
@ -485,11 +491,7 @@ fn vk_setup(
.unwrap()
};
let vertex_buffer = CpuAccessibleBuffer::<[Vertex]>::from_iter(
device.clone(),
BufferUsage::all(),
false,
[
let vertices = [
Vertex {
position: [-0.5, -0.5],
},
@ -502,9 +504,12 @@ fn vk_setup(
Vertex {
position: [0.5, 0.5],
},
]
.iter()
.cloned(),
];
let vertex_buffer = CpuAccessibleBuffer::<[Vertex]>::from_iter(
device.clone(),
BufferUsage::all(),
false,
vertices,
)
.unwrap();
@ -543,7 +548,9 @@ fn vk_setup(
let pipeline = GraphicsPipeline::start()
.vertex_input_state(BuffersDefinition::new().vertex::<Vertex>())
.vertex_shader(vs.entry_point("main").unwrap(), ())
.input_assembly_state(InputAssemblyState::new().topology(PrimitiveTopology::TriangleStrip))
.input_assembly_state(
InputAssemblyState::new().topology(PrimitiveTopology::TriangleStrip),
)
.viewport_state(ViewportState::FixedScissor {
scissors: (0..1).map(|_| Scissor::irrelevant()).collect(),
viewport_count_dynamic: false,
@ -575,29 +582,31 @@ fn vk_setup(
pipeline,
vertex_buffer,
)
}
}
#[cfg(target_os = "linux")]
fn build_display<F>(ctx: glutin::Context<glutin::NotCurrent>, f: F)
where
fn build_display<F>(ctx: glutin::Context<glutin::NotCurrent>, f: F)
where
F: FnOnce(Box<dyn glium::backend::Facade>),
F: Send + 'static,
{
{
std::thread::spawn(move || {
let display = Box::new(
glium::HeadlessRenderer::with_debug(ctx, glium::debug::DebugCallbackBehavior::PrintAll)
glium::HeadlessRenderer::with_debug(
ctx,
glium::debug::DebugCallbackBehavior::PrintAll,
)
.unwrap(),
);
f(display);
});
}
#[cfg(target_os = "linux")]
fn window_size_dependent_setup(
}
fn window_size_dependent_setup(
images: &[Arc<SwapchainImage<Window>>],
render_pass: Arc<RenderPass>,
viewport: &mut Viewport,
) -> Vec<Arc<Framebuffer>> {
) -> Vec<Arc<Framebuffer>> {
use vulkano::{image::ImageAccess, render_pass::FramebufferCreateInfo};
let dimensions = images[0].dimensions().width_height();
viewport.dimensions = [dimensions[0] as f32, dimensions[1] as f32];
@ -617,9 +626,9 @@ fn window_size_dependent_setup(
.unwrap()
})
.collect::<Vec<_>>()
}
#[cfg(target_os = "linux")]
mod vs {
}
mod vs {
vulkano_shaders::shader! {
ty: "vertex",
src: "
@ -631,9 +640,9 @@ void main() {
tex_coords = position + vec2(0.5);
}"
}
}
#[cfg(target_os = "linux")]
mod fs {
}
mod fs {
vulkano_shaders::shader! {
ty: "fragment",
src: "
@ -645,4 +654,5 @@ void main() {
f_color = texture(tex, tex_coords);
}"
}
}
}

View File

@ -7,34 +7,46 @@
// notice may not be copied, modified, or distributed except
// according to those terms.
use std::io::Cursor;
use std::sync::Arc;
use vulkano::buffer::{BufferUsage, CpuAccessibleBuffer, TypedBufferAccess};
use vulkano::command_buffer::{
use bytemuck::{Pod, Zeroable};
use std::{io::Cursor, sync::Arc};
use vulkano::{
buffer::{BufferUsage, CpuAccessibleBuffer, TypedBufferAccess},
command_buffer::{
AutoCommandBufferBuilder, CommandBufferUsage, PrimaryCommandBuffer, SubpassContents,
},
descriptor_set::{PersistentDescriptorSet, WriteDescriptorSet},
device::{
physical::{PhysicalDevice, PhysicalDeviceType},
Device, DeviceCreateInfo, DeviceExtensions, QueueCreateInfo,
},
format::{ClearValue, Format},
image::{
view::ImageView, ImageAccess, ImageDimensions, ImageUsage, StorageImage, SwapchainImage,
},
impl_vertex,
instance::{Instance, InstanceCreateInfo},
pipeline::{
graphics::{
color_blend::ColorBlendState,
input_assembly::{InputAssemblyState, PrimitiveTopology},
vertex_input::BuffersDefinition,
viewport::{Viewport, ViewportState},
},
GraphicsPipeline, Pipeline, PipelineBindPoint,
},
render_pass::{Framebuffer, FramebufferCreateInfo, RenderPass, Subpass},
sampler::{Filter, Sampler, SamplerAddressMode, SamplerCreateInfo},
swapchain::{
acquire_next_image, AcquireError, Swapchain, SwapchainCreateInfo, SwapchainCreationError,
},
sync::{self, FlushError, GpuFuture},
};
use vulkano::descriptor_set::{PersistentDescriptorSet, WriteDescriptorSet};
use vulkano::device::physical::{PhysicalDevice, PhysicalDeviceType};
use vulkano::device::{Device, DeviceCreateInfo, DeviceExtensions, QueueCreateInfo};
use vulkano::format::{ClearValue, Format};
use vulkano::image::{view::ImageView, ImageDimensions, ImageUsage, SwapchainImage};
use vulkano::image::{ImageAccess, StorageImage};
use vulkano::instance::{Instance, InstanceCreateInfo};
use vulkano::pipeline::graphics::color_blend::ColorBlendState;
use vulkano::pipeline::graphics::input_assembly::{InputAssemblyState, PrimitiveTopology};
use vulkano::pipeline::graphics::vertex_input::BuffersDefinition;
use vulkano::pipeline::graphics::viewport::{Viewport, ViewportState};
use vulkano::pipeline::{GraphicsPipeline, Pipeline, PipelineBindPoint};
use vulkano::render_pass::{Framebuffer, FramebufferCreateInfo, RenderPass, Subpass};
use vulkano::sampler::{Filter, Sampler, SamplerAddressMode, SamplerCreateInfo};
use vulkano::swapchain::{
self, AcquireError, Swapchain, SwapchainCreateInfo, SwapchainCreationError,
};
use vulkano::sync::{self, FlushError, GpuFuture};
use vulkano_win::VkSurfaceBuild;
use winit::event::{Event, WindowEvent};
use winit::event_loop::{ControlFlow, EventLoop};
use winit::window::{Window, WindowBuilder};
use winit::{
event::{Event, WindowEvent},
event_loop::{ControlFlow, EventLoop},
window::{Window, WindowBuilder},
};
fn main() {
// The start of this example is exactly the same as `triangle`. You should read the
@ -122,17 +134,13 @@ fn main() {
};
#[repr(C)]
#[derive(Default, Debug, Clone)]
#[derive(Clone, Copy, Debug, Default, Zeroable, Pod)]
struct Vertex {
position: [f32; 2],
}
vulkano::impl_vertex!(Vertex, position);
impl_vertex!(Vertex, position);
let vertex_buffer = CpuAccessibleBuffer::<[Vertex]>::from_iter(
device.clone(),
BufferUsage::all(),
false,
[
let vertices = [
Vertex {
position: [-0.5, -0.5],
},
@ -145,9 +153,12 @@ fn main() {
Vertex {
position: [0.5, 0.5],
},
]
.iter()
.cloned(),
];
let vertex_buffer = CpuAccessibleBuffer::<[Vertex]>::from_iter(
device.clone(),
BufferUsage::all(),
false,
vertices,
)
.unwrap();
@ -198,7 +209,7 @@ fn main() {
device.clone(),
BufferUsage::transfer_source(),
false,
image_data.iter().cloned(),
image_data,
)
.unwrap();
@ -340,7 +351,7 @@ fn main() {
}
let (image_num, suboptimal, acquire_future) =
match swapchain::acquire_next_image(swapchain.clone(), None) {
match acquire_next_image(swapchain.clone(), None) {
Ok(r) => r,
Err(AcquireError::OutOfDate) => {
recreate_swapchain = true;

View File

@ -7,35 +7,45 @@
// notice may not be copied, modified, or distributed except
// according to those terms.
use png;
use std::io::Cursor;
use std::sync::Arc;
use vulkano::buffer::{BufferUsage, CpuAccessibleBuffer, TypedBufferAccess};
use vulkano::command_buffer::{AutoCommandBufferBuilder, CommandBufferUsage, SubpassContents};
use vulkano::descriptor_set::{PersistentDescriptorSet, WriteDescriptorSet};
use vulkano::device::physical::{PhysicalDevice, PhysicalDeviceType};
use vulkano::device::{Device, DeviceCreateInfo, DeviceExtensions, QueueCreateInfo};
use vulkano::format::Format;
use vulkano::image::ImageAccess;
use vulkano::image::{
view::ImageView, ImageDimensions, ImageUsage, ImmutableImage, MipmapsCount, SwapchainImage,
use bytemuck::{Pod, Zeroable};
use std::{io::Cursor, sync::Arc};
use vulkano::{
buffer::{BufferUsage, CpuAccessibleBuffer, TypedBufferAccess},
command_buffer::{AutoCommandBufferBuilder, CommandBufferUsage, SubpassContents},
descriptor_set::{PersistentDescriptorSet, WriteDescriptorSet},
device::{
physical::{PhysicalDevice, PhysicalDeviceType},
Device, DeviceCreateInfo, DeviceExtensions, QueueCreateInfo,
},
format::Format,
image::{
view::ImageView, ImageAccess, ImageDimensions, ImageUsage, ImmutableImage, MipmapsCount,
SwapchainImage,
},
impl_vertex,
instance::{Instance, InstanceCreateInfo},
pipeline::{
graphics::{
color_blend::ColorBlendState,
input_assembly::{InputAssemblyState, PrimitiveTopology},
vertex_input::BuffersDefinition,
viewport::{Viewport, ViewportState},
},
GraphicsPipeline, Pipeline, PipelineBindPoint,
},
render_pass::{Framebuffer, FramebufferCreateInfo, RenderPass, Subpass},
sampler::{Filter, Sampler, SamplerAddressMode, SamplerCreateInfo},
swapchain::{
acquire_next_image, AcquireError, Swapchain, SwapchainCreateInfo, SwapchainCreationError,
},
sync::{self, FlushError, GpuFuture},
};
use vulkano::instance::{Instance, InstanceCreateInfo};
use vulkano::pipeline::graphics::color_blend::ColorBlendState;
use vulkano::pipeline::graphics::input_assembly::{InputAssemblyState, PrimitiveTopology};
use vulkano::pipeline::graphics::vertex_input::BuffersDefinition;
use vulkano::pipeline::graphics::viewport::{Viewport, ViewportState};
use vulkano::pipeline::{GraphicsPipeline, Pipeline, PipelineBindPoint};
use vulkano::render_pass::{Framebuffer, FramebufferCreateInfo, RenderPass, Subpass};
use vulkano::sampler::{Filter, Sampler, SamplerAddressMode, SamplerCreateInfo};
use vulkano::swapchain::{
self, AcquireError, Swapchain, SwapchainCreateInfo, SwapchainCreationError,
};
use vulkano::sync::{self, FlushError, GpuFuture};
use vulkano_win::VkSurfaceBuild;
use winit::event::{Event, WindowEvent};
use winit::event_loop::{ControlFlow, EventLoop};
use winit::window::{Window, WindowBuilder};
use winit::{
event::{Event, WindowEvent},
event_loop::{ControlFlow, EventLoop},
window::{Window, WindowBuilder},
};
fn main() {
// The start of this example is exactly the same as `triangle`. You should read the
@ -123,17 +133,13 @@ fn main() {
};
#[repr(C)]
#[derive(Default, Debug, Clone)]
#[derive(Clone, Copy, Debug, Default, Zeroable, Pod)]
struct Vertex {
position: [f32; 2],
}
vulkano::impl_vertex!(Vertex, position);
impl_vertex!(Vertex, position);
let vertex_buffer = CpuAccessibleBuffer::<[Vertex]>::from_iter(
device.clone(),
BufferUsage::all(),
false,
[
let vertices = [
Vertex {
position: [-0.5, -0.5],
},
@ -146,9 +152,12 @@ fn main() {
Vertex {
position: [0.5, 0.5],
},
]
.iter()
.cloned(),
];
let vertex_buffer = CpuAccessibleBuffer::<[Vertex]>::from_iter(
device.clone(),
BufferUsage::all(),
false,
vertices,
)
.unwrap();
@ -187,7 +196,7 @@ fn main() {
reader.next_frame(&mut image_data).unwrap();
let (image, future) = ImmutableImage::from_iter(
image_data.iter().cloned(),
image_data,
dimensions,
MipmapsCount::One,
Format::R8G8B8A8_SRGB,
@ -274,7 +283,7 @@ fn main() {
}
let (image_num, suboptimal, acquire_future) =
match swapchain::acquire_next_image(swapchain.clone(), None) {
match acquire_next_image(swapchain.clone(), None) {
Ok(r) => r,
Err(AcquireError::OutOfDate) => {
recreate_swapchain = true;

View File

@ -9,15 +9,18 @@
// This example demonstrates how to initialize immutable buffers.
use vulkano::buffer::{BufferUsage, CpuAccessibleBuffer, ImmutableBuffer};
use vulkano::command_buffer::{AutoCommandBufferBuilder, CommandBufferUsage};
use vulkano::descriptor_set::{PersistentDescriptorSet, WriteDescriptorSet};
use vulkano::device::physical::{PhysicalDevice, PhysicalDeviceType};
use vulkano::device::{Device, DeviceCreateInfo, DeviceExtensions, QueueCreateInfo};
use vulkano::instance::Instance;
use vulkano::pipeline::{ComputePipeline, Pipeline, PipelineBindPoint};
use vulkano::sync;
use vulkano::sync::GpuFuture;
use vulkano::{
buffer::{BufferUsage, CpuAccessibleBuffer, ImmutableBuffer},
command_buffer::{AutoCommandBufferBuilder, CommandBufferUsage},
descriptor_set::{PersistentDescriptorSet, WriteDescriptorSet},
device::{
physical::{PhysicalDevice, PhysicalDeviceType},
Device, DeviceCreateInfo, DeviceExtensions, QueueCreateInfo,
},
instance::Instance,
pipeline::{ComputePipeline, Pipeline, PipelineBindPoint},
sync::{self, GpuFuture},
};
fn main() {
// The most part of this example is exactly the same as `basic-compute-shader`. You should read the
@ -127,7 +130,7 @@ void main() {
// We can use copy_buffer(), fill_buffer() and some other functions that copies data to
// buffer also.
builder
.update_buffer(immutable_data_buffer_init, &3)
.update_buffer(immutable_data_buffer_init, &3u32)
.unwrap();
let command_buffer = builder.build().unwrap();

View File

@ -16,35 +16,45 @@
// - The sampler is added to the descriptor set layout at pipeline creation.
// - No sampler is included when building a descriptor set.
use png;
use std::io::Cursor;
use std::sync::Arc;
use vulkano::buffer::{BufferUsage, CpuAccessibleBuffer, TypedBufferAccess};
use vulkano::command_buffer::{AutoCommandBufferBuilder, CommandBufferUsage, SubpassContents};
use vulkano::descriptor_set::{PersistentDescriptorSet, WriteDescriptorSet};
use vulkano::device::physical::{PhysicalDevice, PhysicalDeviceType};
use vulkano::device::{Device, DeviceCreateInfo, DeviceExtensions, QueueCreateInfo};
use vulkano::format::Format;
use vulkano::image::ImageAccess;
use vulkano::image::{
view::ImageView, ImageDimensions, ImageUsage, ImmutableImage, MipmapsCount, SwapchainImage,
use bytemuck::{Pod, Zeroable};
use std::{io::Cursor, sync::Arc};
use vulkano::{
buffer::{BufferUsage, CpuAccessibleBuffer, TypedBufferAccess},
command_buffer::{AutoCommandBufferBuilder, CommandBufferUsage, SubpassContents},
descriptor_set::{PersistentDescriptorSet, WriteDescriptorSet},
device::{
physical::{PhysicalDevice, PhysicalDeviceType},
Device, DeviceCreateInfo, DeviceExtensions, QueueCreateInfo,
},
format::Format,
image::{
view::ImageView, ImageAccess, ImageDimensions, ImageUsage, ImmutableImage, MipmapsCount,
SwapchainImage,
},
impl_vertex,
instance::{Instance, InstanceCreateInfo},
pipeline::{
graphics::{
color_blend::ColorBlendState,
input_assembly::{InputAssemblyState, PrimitiveTopology},
vertex_input::BuffersDefinition,
viewport::{Viewport, ViewportState},
},
GraphicsPipeline, Pipeline, PipelineBindPoint,
},
render_pass::{Framebuffer, FramebufferCreateInfo, RenderPass, Subpass},
sampler::{Filter, Sampler, SamplerAddressMode, SamplerCreateInfo},
swapchain::{
acquire_next_image, AcquireError, Swapchain, SwapchainCreateInfo, SwapchainCreationError,
},
sync::{self, FlushError, GpuFuture},
};
use vulkano::instance::{Instance, InstanceCreateInfo};
use vulkano::pipeline::graphics::color_blend::ColorBlendState;
use vulkano::pipeline::graphics::input_assembly::{InputAssemblyState, PrimitiveTopology};
use vulkano::pipeline::graphics::vertex_input::BuffersDefinition;
use vulkano::pipeline::graphics::viewport::{Viewport, ViewportState};
use vulkano::pipeline::{GraphicsPipeline, Pipeline, PipelineBindPoint};
use vulkano::render_pass::{Framebuffer, FramebufferCreateInfo, RenderPass, Subpass};
use vulkano::sampler::{Filter, Sampler, SamplerAddressMode, SamplerCreateInfo};
use vulkano::swapchain::{
self, AcquireError, Swapchain, SwapchainCreateInfo, SwapchainCreationError,
};
use vulkano::sync::{self, FlushError, GpuFuture};
use vulkano_win::VkSurfaceBuild;
use winit::event::{Event, WindowEvent};
use winit::event_loop::{ControlFlow, EventLoop};
use winit::window::{Window, WindowBuilder};
use winit::{
event::{Event, WindowEvent},
event_loop::{ControlFlow, EventLoop},
window::{Window, WindowBuilder},
};
fn main() {
let required_extensions = vulkano_win::required_extensions();
@ -129,17 +139,13 @@ fn main() {
};
#[repr(C)]
#[derive(Default, Debug, Clone)]
#[derive(Clone, Copy, Debug, Default, Zeroable, Pod)]
struct Vertex {
position: [f32; 2],
}
vulkano::impl_vertex!(Vertex, position);
impl_vertex!(Vertex, position);
let vertex_buffer = CpuAccessibleBuffer::<[Vertex]>::from_iter(
device.clone(),
BufferUsage::all(),
false,
[
let vertices = [
Vertex {
position: [-0.5, -0.5],
},
@ -152,9 +158,12 @@ fn main() {
Vertex {
position: [0.5, 0.5],
},
]
.iter()
.cloned(),
];
let vertex_buffer = CpuAccessibleBuffer::<[Vertex]>::from_iter(
device.clone(),
BufferUsage::all(),
false,
vertices,
)
.unwrap();
@ -193,7 +202,7 @@ fn main() {
reader.next_frame(&mut image_data).unwrap();
let (image, future) = ImmutableImage::from_iter(
image_data.iter().cloned(),
image_data,
dimensions,
MipmapsCount::One,
Format::R8G8B8A8_SRGB,
@ -283,7 +292,7 @@ fn main() {
}
let (image_num, suboptimal, acquire_future) =
match swapchain::acquire_next_image(swapchain.clone(), None) {
match acquire_next_image(swapchain.clone(), None) {
Ok(r) => r,
Err(AcquireError::OutOfDate) => {
recreate_swapchain = true;

View File

@ -24,42 +24,47 @@
// example.
//
#[macro_use]
extern crate vulkano;
extern crate vulkano_shaders;
extern crate vulkano_win;
extern crate winit;
use std::iter;
use bytemuck::{Pod, Zeroable};
use std::sync::Arc;
use vulkano::buffer::{BufferUsage, CpuBufferPool};
use vulkano::command_buffer::{
use vulkano::{
buffer::{BufferUsage, CpuBufferPool},
command_buffer::{
AutoCommandBufferBuilder, CommandBufferUsage, DrawIndirectCommand, SubpassContents,
},
descriptor_set::{PersistentDescriptorSet, WriteDescriptorSet},
device::{
physical::{PhysicalDevice, PhysicalDeviceType},
Device, DeviceCreateInfo, DeviceExtensions, QueueCreateInfo,
},
image::{view::ImageView, ImageAccess, ImageUsage, SwapchainImage},
impl_vertex,
instance::{Instance, InstanceCreateInfo},
pipeline::{
graphics::{
input_assembly::InputAssemblyState,
vertex_input::BuffersDefinition,
viewport::{Viewport, ViewportState},
},
ComputePipeline, GraphicsPipeline, Pipeline, PipelineBindPoint,
},
render_pass::{Framebuffer, FramebufferCreateInfo, RenderPass, Subpass},
single_pass_renderpass,
swapchain::{
acquire_next_image, AcquireError, Swapchain, SwapchainCreateInfo, SwapchainCreationError,
},
sync::{self, FlushError, GpuFuture},
};
use vulkano::descriptor_set::{PersistentDescriptorSet, WriteDescriptorSet};
use vulkano::device::physical::{PhysicalDevice, PhysicalDeviceType};
use vulkano::device::{Device, DeviceCreateInfo, DeviceExtensions, QueueCreateInfo};
use vulkano::image::view::ImageView;
use vulkano::image::{ImageAccess, ImageUsage, SwapchainImage};
use vulkano::instance::{Instance, InstanceCreateInfo};
use vulkano::pipeline::graphics::input_assembly::InputAssemblyState;
use vulkano::pipeline::graphics::vertex_input::BuffersDefinition;
use vulkano::pipeline::graphics::viewport::{Viewport, ViewportState};
use vulkano::pipeline::{ComputePipeline, GraphicsPipeline, Pipeline, PipelineBindPoint};
use vulkano::render_pass::{Framebuffer, FramebufferCreateInfo, RenderPass, Subpass};
use vulkano::swapchain::{
self, AcquireError, Swapchain, SwapchainCreateInfo, SwapchainCreationError,
};
use vulkano::sync::{self, FlushError, GpuFuture};
use vulkano_win::VkSurfaceBuild;
use winit::event::{Event, WindowEvent};
use winit::event_loop::{ControlFlow, EventLoop};
use winit::window::{Window, WindowBuilder};
use winit::{
event::{Event, WindowEvent},
event_loop::{ControlFlow, EventLoop},
window::{Window, WindowBuilder},
};
// # Vertex Types
// `Vertex` is the vertex type that will be output from the compute shader and be input to the vertex shader.
#[repr(C)]
#[derive(Default, Debug, Clone)]
#[derive(Clone, Copy, Debug, Default, Zeroable, Pod)]
struct Vertex {
position: [f32; 2],
}
@ -314,7 +319,7 @@ fn main() {
}
let (image_num, suboptimal, acquire_future) =
match swapchain::acquire_next_image(swapchain.clone(), None) {
match acquire_next_image(swapchain.clone(), None) {
Ok(r) => r,
Err(AcquireError::OutOfDate) => {
recreate_swapchain = true;
@ -331,14 +336,13 @@ fn main() {
// Allocate a GPU buffer to hold the arguments for this frames draw call. The compute
// shader will only update vertex_count, so set the other parameters correctly here.
let indirect_args = indirect_args_pool
.chunk(iter::once(DrawIndirectCommand {
let indirect_commands = [DrawIndirectCommand {
vertex_count: 0,
instance_count: 1,
first_vertex: 0,
first_instance: 0,
}))
.unwrap();
}];
let indirect_buffer = indirect_args_pool.chunk(indirect_commands).unwrap();
// Allocate a GPU buffer to hold this frames vertices. This needs to be large enough to hold
// the worst case number of vertices generated by the compute shader
@ -352,7 +356,7 @@ fn main() {
layout.clone(),
[
WriteDescriptorSet::buffer(0, vertices.clone()),
WriteDescriptorSet::buffer(1, indirect_args.clone()),
WriteDescriptorSet::buffer(1, indirect_buffer.clone()),
],
)
.unwrap();
@ -387,7 +391,7 @@ fn main() {
.set_viewport(0, [viewport.clone()])
.bind_pipeline_graphics(render_pipeline.clone())
.bind_vertex_buffers(0, vertices.clone())
.draw_indirect(indirect_args.clone())
.draw_indirect(indirect_buffer.clone())
.unwrap()
.end_render_pass()
.unwrap();

View File

@ -12,33 +12,39 @@
// This is a simple, modified version of the `triangle.rs` example that demonstrates how we can use
// the "instancing" technique with vulkano to draw many instances of the triangle.
#[macro_use]
extern crate vulkano;
extern crate vulkano_shaders;
extern crate vulkano_win;
extern crate winit;
use bytemuck::{Pod, Zeroable};
use std::sync::Arc;
use vulkano::buffer::{BufferUsage, CpuAccessibleBuffer, TypedBufferAccess};
use vulkano::command_buffer::{AutoCommandBufferBuilder, CommandBufferUsage, SubpassContents};
use vulkano::device::physical::{PhysicalDevice, PhysicalDeviceType};
use vulkano::device::{Device, DeviceCreateInfo, DeviceExtensions, QueueCreateInfo};
use vulkano::image::view::ImageView;
use vulkano::image::{ImageAccess, ImageUsage, SwapchainImage};
use vulkano::instance::{Instance, InstanceCreateInfo};
use vulkano::pipeline::graphics::input_assembly::InputAssemblyState;
use vulkano::pipeline::graphics::vertex_input::BuffersDefinition;
use vulkano::pipeline::graphics::viewport::{Viewport, ViewportState};
use vulkano::pipeline::GraphicsPipeline;
use vulkano::render_pass::{Framebuffer, FramebufferCreateInfo, RenderPass, Subpass};
use vulkano::swapchain::{
self, AcquireError, Swapchain, SwapchainCreateInfo, SwapchainCreationError,
use vulkano::{
buffer::{BufferUsage, CpuAccessibleBuffer, TypedBufferAccess},
command_buffer::{AutoCommandBufferBuilder, CommandBufferUsage, SubpassContents},
device::{
physical::{PhysicalDevice, PhysicalDeviceType},
Device, DeviceCreateInfo, DeviceExtensions, QueueCreateInfo,
},
image::{view::ImageView, ImageAccess, ImageUsage, SwapchainImage},
impl_vertex,
instance::{Instance, InstanceCreateInfo},
pipeline::{
graphics::{
input_assembly::InputAssemblyState,
vertex_input::BuffersDefinition,
viewport::{Viewport, ViewportState},
},
GraphicsPipeline,
},
render_pass::{Framebuffer, FramebufferCreateInfo, RenderPass, Subpass},
single_pass_renderpass,
swapchain::{
acquire_next_image, AcquireError, Swapchain, SwapchainCreateInfo, SwapchainCreationError,
},
sync::{self, FlushError, GpuFuture},
};
use vulkano::sync::{self, FlushError, GpuFuture};
use vulkano_win::VkSurfaceBuild;
use winit::event::{Event, WindowEvent};
use winit::event_loop::{ControlFlow, EventLoop};
use winit::window::{Window, WindowBuilder};
use winit::{
event::{Event, WindowEvent},
event_loop::{ControlFlow, EventLoop},
window::{Window, WindowBuilder},
};
// # Vertex Types
//
@ -47,7 +53,7 @@ use winit::window::{Window, WindowBuilder};
//
// 1. `Vertex` is the vertex type that we will use to describe the triangle's geometry.
#[repr(C)]
#[derive(Default, Debug, Clone)]
#[derive(Clone, Copy, Debug, Default, Zeroable, Pod)]
struct Vertex {
position: [f32; 2],
}
@ -55,7 +61,7 @@ impl_vertex!(Vertex, position);
// 2. `InstanceData` is the vertex type that describes the unique data per instance.
#[repr(C)]
#[derive(Default, Debug, Clone)]
#[derive(Clone, Copy, Debug, Default, Zeroable, Pod)]
struct InstanceData {
position_offset: [f32; 2],
scale: f32,
@ -147,12 +153,7 @@ fn main() {
// We now create a buffer that will store the shape of our triangle.
// This triangle is identical to the one in the `triangle.rs` example.
let triangle_vertex_buffer = {
CpuAccessibleBuffer::from_iter(
device.clone(),
BufferUsage::all(),
false,
[
let vertices = [
Vertex {
position: [-0.5, -0.25],
},
@ -162,16 +163,14 @@ fn main() {
Vertex {
position: [0.25, -0.1],
},
]
.iter()
.cloned(),
)
.unwrap()
];
let vertex_buffer = {
CpuAccessibleBuffer::from_iter(device.clone(), BufferUsage::all(), false, vertices).unwrap()
};
// Now we create another buffer that will store the unique data per instance.
// For this example, we'll have the instances form a 10x10 grid that slowly gets larger.
let instance_data_buffer = {
let instances = {
let rows = 10;
let cols = 10;
let n_instances = rows * cols;
@ -190,14 +189,11 @@ fn main() {
});
}
}
CpuAccessibleBuffer::from_iter(
device.clone(),
BufferUsage::all(),
false,
data.iter().cloned(),
)
.unwrap()
data
};
let instance_buffer =
CpuAccessibleBuffer::from_iter(device.clone(), BufferUsage::all(), false, instances)
.unwrap();
mod vs {
vulkano_shaders::shader! {
@ -318,7 +314,7 @@ fn main() {
}
let (image_num, suboptimal, acquire_future) =
match swapchain::acquire_next_image(swapchain.clone(), None) {
match acquire_next_image(swapchain.clone(), None) {
Ok(r) => r,
Err(AcquireError::OutOfDate) => {
recreate_swapchain = true;
@ -349,13 +345,10 @@ fn main() {
.set_viewport(0, [viewport.clone()])
.bind_pipeline_graphics(pipeline.clone())
// We pass both our lists of vertices here.
.bind_vertex_buffers(
0,
(triangle_vertex_buffer.clone(), instance_data_buffer.clone()),
)
.bind_vertex_buffers(0, (vertex_buffer.clone(), instance_buffer.clone()))
.draw(
triangle_vertex_buffer.len() as u32,
instance_data_buffer.len() as u32,
vertex_buffer.len() as u32,
instance_buffer.len() as u32,
0,
0,
)

View File

@ -7,14 +7,19 @@
// notice may not be copied, modified, or distributed except
// according to those terms.
use crate::fractal_compute_pipeline::FractalComputePipeline;
use crate::renderer::{InterimImageView, RenderOptions, Renderer};
use crate::{
fractal_compute_pipeline::FractalComputePipeline,
renderer::{InterimImageView, RenderOptions, Renderer},
};
use cgmath::Vector2;
use time::Instant;
use std::time::Instant;
use vulkano::sync::GpuFuture;
use winit::dpi::PhysicalPosition;
use winit::event::{
ElementState, Event, KeyboardInput, MouseButton, MouseScrollDelta, VirtualKeyCode, WindowEvent,
use winit::{
dpi::PhysicalPosition,
event::{
ElementState, Event, KeyboardInput, MouseButton, MouseScrollDelta, VirtualKeyCode,
WindowEvent,
},
};
const MAX_ITERS_INIT: u32 = 200;
@ -116,7 +121,7 @@ Usage:
self.frame_count = 0.0;
self.dt_sum = 0.0;
}
self.dt = self.time.elapsed().as_seconds_f32();
self.dt = self.time.elapsed().as_secs_f32();
self.dt_sum += self.dt;
self.frame_count += 1.0;
self.time = Instant::now();

View File

@ -11,19 +11,21 @@ use crate::renderer::InterimImageView;
use cgmath::Vector2;
use rand::Rng;
use std::sync::Arc;
use vulkano::buffer::{BufferUsage, CpuAccessibleBuffer, TypedBufferAccess};
use vulkano::command_buffer::PrimaryCommandBuffer;
use vulkano::command_buffer::{AutoCommandBufferBuilder, CommandBufferUsage};
use vulkano::descriptor_set::{PersistentDescriptorSet, WriteDescriptorSet};
use vulkano::device::Queue;
use vulkano::image::ImageAccess;
use vulkano::pipeline::{ComputePipeline, Pipeline, PipelineBindPoint};
use vulkano::sync::GpuFuture;
use vulkano::{
buffer::{BufferUsage, CpuAccessibleBuffer},
command_buffer::{AutoCommandBufferBuilder, CommandBufferUsage, PrimaryCommandBuffer},
descriptor_set::{PersistentDescriptorSet, WriteDescriptorSet},
device::Queue,
image::ImageAccess,
pipeline::{ComputePipeline, Pipeline, PipelineBindPoint},
sync::GpuFuture,
};
pub struct FractalComputePipeline {
gfx_queue: Arc<Queue>,
pipeline: Arc<ComputePipeline>,
palette: Arc<CpuAccessibleBuffer<[[f32; 4]]>>,
palette_size: i32,
end_color: [f32; 4],
}
@ -38,11 +40,12 @@ impl FractalComputePipeline {
[0.0, 0.0, 1.0, 1.0],
[1.0, 0.0, 1.0, 1.0],
];
let palette_size = colors.len() as i32;
let palette = CpuAccessibleBuffer::from_iter(
gfx_queue.device().clone(),
BufferUsage::all(),
false,
colors.into_iter(),
colors,
)
.unwrap();
let end_color = [0.0; 4];
@ -62,6 +65,7 @@ impl FractalComputePipeline {
gfx_queue,
pipeline,
palette,
palette_size,
end_color,
}
}
@ -69,7 +73,7 @@ impl FractalComputePipeline {
/// Randomizes our color palette
pub fn randomize_palette(&mut self) {
let mut colors = vec![];
for _ in 0..self.palette.len() {
for _ in 0..self.palette_size {
let r = rand::thread_rng().gen::<f32>();
let g = rand::thread_rng().gen::<f32>();
let b = rand::thread_rng().gen::<f32>();
@ -118,7 +122,7 @@ impl FractalComputePipeline {
scale: scale.into(),
translation: translation.into(),
end_color: self.end_color,
palette_size: self.palette.len() as i32,
palette_size: self.palette_size,
max_iters: max_iters as i32,
is_julia: is_julia as u32,
_dummy0: [0u8; 8], // Required for alignment

View File

@ -7,8 +7,10 @@
// notice may not be copied, modified, or distributed except
// according to those terms.
use crate::app::FractalApp;
use crate::renderer::{image_over_frame_renderpass, RenderOptions, Renderer};
use crate::{
app::FractalApp,
renderer::{image_over_frame_renderpass, RenderOptions, Renderer},
};
use vulkano::sync::GpuFuture;
use winit::{
event::{Event, WindowEvent},

View File

@ -7,29 +7,35 @@
// notice may not be copied, modified, or distributed except
// according to those terms.
use bytemuck::{Pod, Zeroable};
use std::sync::Arc;
use vulkano::buffer::{BufferUsage, CpuAccessibleBuffer, TypedBufferAccess};
use vulkano::command_buffer::{
AutoCommandBufferBuilder, CommandBufferUsage, SecondaryAutoCommandBuffer,
use vulkano::{
buffer::{BufferUsage, CpuAccessibleBuffer, TypedBufferAccess},
command_buffer::{AutoCommandBufferBuilder, CommandBufferUsage, SecondaryAutoCommandBuffer},
descriptor_set::{PersistentDescriptorSet, WriteDescriptorSet},
device::Queue,
image::ImageViewAbstract,
impl_vertex,
pipeline::{
graphics::{
input_assembly::InputAssemblyState,
vertex_input::BuffersDefinition,
viewport::{Viewport, ViewportState},
},
GraphicsPipeline, Pipeline, PipelineBindPoint,
},
render_pass::Subpass,
sampler::{Filter, Sampler, SamplerAddressMode, SamplerCreateInfo, SamplerMipmapMode},
};
use vulkano::descriptor_set::{PersistentDescriptorSet, WriteDescriptorSet};
use vulkano::device::Queue;
use vulkano::image::ImageViewAbstract;
use vulkano::pipeline::graphics::input_assembly::InputAssemblyState;
use vulkano::pipeline::graphics::vertex_input::BuffersDefinition;
use vulkano::pipeline::graphics::viewport::{Viewport, ViewportState};
use vulkano::pipeline::{GraphicsPipeline, Pipeline, PipelineBindPoint};
use vulkano::render_pass::Subpass;
use vulkano::sampler::{Filter, Sampler, SamplerAddressMode, SamplerCreateInfo, SamplerMipmapMode};
/// Vertex for textured quads
#[repr(C)]
#[derive(Default, Debug, Clone, Copy)]
#[derive(Clone, Copy, Debug, Default, Zeroable, Pod)]
pub struct TexturedVertex {
pub position: [f32; 2],
pub tex_coords: [f32; 2],
}
vulkano::impl_vertex!(TexturedVertex, position, tex_coords);
impl_vertex!(TexturedVertex, position, tex_coords);
pub fn textured_quad(width: f32, height: f32) -> (Vec<TexturedVertex>, Vec<u32>) {
(
@ -70,14 +76,14 @@ impl PixelsDrawPipeline {
gfx_queue.device().clone(),
BufferUsage::vertex_buffer(),
false,
vertices.into_iter(),
vertices,
)
.unwrap();
let index_buffer = CpuAccessibleBuffer::<[u32]>::from_iter(
gfx_queue.device().clone(),
BufferUsage::index_buffer(),
false,
indices.into_iter(),
indices,
)
.unwrap();

View File

@ -7,8 +7,11 @@
// notice may not be copied, modified, or distributed except
// according to those terms.
use crate::{
pixels_draw_pipeline::PixelsDrawPipeline,
renderer::{FinalImageView, InterimImageView},
};
use std::sync::Arc;
use vulkano::{
command_buffer::{AutoCommandBufferBuilder, CommandBufferUsage, SubpassContents},
device::Queue,
@ -18,9 +21,6 @@ use vulkano::{
sync::GpuFuture,
};
use crate::pixels_draw_pipeline::PixelsDrawPipeline;
use crate::renderer::{FinalImageView, InterimImageView};
/// A render pass which places an incoming image over frame filling it
pub struct RenderPassPlaceOverFrame {
gfx_queue: Arc<Queue>,

View File

@ -8,29 +8,29 @@
// according to those terms.
use crate::place_over_frame::RenderPassPlaceOverFrame;
use vulkano_win::VkSurfaceBuild;
use std::collections::HashMap;
use std::sync::Arc;
use vulkano::device::physical::{PhysicalDevice, PhysicalDeviceType};
use vulkano::device::{
use std::{collections::HashMap, sync::Arc};
use vulkano::{
device::{
physical::{PhysicalDevice, PhysicalDeviceType},
Device, DeviceCreateInfo, DeviceExtensions, Features, Queue, QueueCreateInfo,
},
format::Format,
image::{
view::ImageView, AttachmentImage, ImageAccess, ImageUsage, ImageViewAbstract, SampleCount,
SwapchainImage,
},
instance::{Instance, InstanceCreateInfo, InstanceExtensions},
swapchain::{
acquire_next_image, AcquireError, PresentMode, Surface, Swapchain, SwapchainCreateInfo,
SwapchainCreationError,
},
sync::{self, FlushError, GpuFuture},
};
use vulkano::format::Format;
use vulkano::image::view::ImageView;
use vulkano::image::{
AttachmentImage, ImageAccess, ImageUsage, ImageViewAbstract, SampleCount, SwapchainImage,
use vulkano_win::VkSurfaceBuild;
use winit::{
event_loop::EventLoop,
window::{Fullscreen, Window, WindowBuilder},
};
use vulkano::instance::InstanceExtensions;
use vulkano::instance::{Instance, InstanceCreateInfo};
use vulkano::swapchain::{
AcquireError, PresentMode, Surface, Swapchain, SwapchainCreateInfo, SwapchainCreationError,
};
use vulkano::sync::{FlushError, GpuFuture};
use vulkano::{swapchain, sync};
use winit::event_loop::EventLoop;
use winit::window::{Fullscreen, Window, WindowBuilder};
/// Final render target (swapchain image)
pub type FinalImageView = Arc<ImageView<SwapchainImage<Window>>>;
@ -374,7 +374,7 @@ impl Renderer {
// Acquire next image in the swapchain
let (image_num, suboptimal, acquire_future) =
match swapchain::acquire_next_image(self.swapchain.clone(), None) {
match acquire_next_image(self.swapchain.clone(), None) {
Ok(r) => r,
Err(AcquireError::OutOfDate) => {
self.recreate_swapchain = true;

View File

@ -64,27 +64,31 @@
//! an error), instead it is called *resolving* the image.
//!
use png;
use std::fs::File;
use std::io::BufWriter;
use std::path::Path;
use vulkano::buffer::{BufferUsage, CpuAccessibleBuffer, TypedBufferAccess};
use vulkano::command_buffer::{
use bytemuck::{Pod, Zeroable};
use std::{fs::File, io::BufWriter, path::Path};
use vulkano::{
buffer::{BufferUsage, CpuAccessibleBuffer, TypedBufferAccess},
command_buffer::{
AutoCommandBufferBuilder, CommandBufferUsage, PrimaryCommandBuffer, SubpassContents,
},
device::{
physical::{PhysicalDevice, PhysicalDeviceType},
Device, DeviceCreateInfo, DeviceExtensions, QueueCreateInfo,
},
format::{ClearValue, Format},
image::{view::ImageView, AttachmentImage, ImageDimensions, SampleCount, StorageImage},
impl_vertex,
instance::{Instance, InstanceCreateInfo},
pipeline::{
graphics::{
vertex_input::BuffersDefinition,
viewport::{Viewport, ViewportState},
},
GraphicsPipeline,
},
render_pass::{Framebuffer, FramebufferCreateInfo, Subpass},
sync::GpuFuture,
};
use vulkano::device::physical::{PhysicalDevice, PhysicalDeviceType};
use vulkano::device::{Device, DeviceCreateInfo, DeviceExtensions, QueueCreateInfo};
use vulkano::format::ClearValue;
use vulkano::format::Format;
use vulkano::image::{
view::ImageView, AttachmentImage, ImageDimensions, SampleCount, StorageImage,
};
use vulkano::instance::{Instance, InstanceCreateInfo};
use vulkano::pipeline::graphics::vertex_input::BuffersDefinition;
use vulkano::pipeline::graphics::viewport::{Viewport, ViewportState};
use vulkano::pipeline::GraphicsPipeline;
use vulkano::render_pass::{Framebuffer, FramebufferCreateInfo, Subpass};
use vulkano::sync::GpuFuture;
fn main() {
// The usual Vulkan initialization.
@ -249,27 +253,25 @@ fn main() {
let fs = fs::load(device.clone()).unwrap();
#[repr(C)]
#[derive(Default, Copy, Clone)]
#[derive(Clone, Copy, Debug, Default, Zeroable, Pod)]
struct Vertex {
position: [f32; 2],
}
vulkano::impl_vertex!(Vertex, position);
impl_vertex!(Vertex, position);
let vertex1 = Vertex {
let vertices = [
Vertex {
position: [-0.5, -0.5],
};
let vertex2 = Vertex {
},
Vertex {
position: [0.0, 0.5],
};
let vertex3 = Vertex {
},
Vertex {
position: [0.5, -0.25],
};
let vertex_buffer = CpuAccessibleBuffer::from_iter(
device.clone(),
BufferUsage::all(),
false,
vec![vertex1, vertex2, vertex3].into_iter(),
)
},
];
let vertex_buffer =
CpuAccessibleBuffer::from_iter(device.clone(), BufferUsage::all(), false, vertices)
.unwrap();
let pipeline = GraphicsPipeline::start()

View File

@ -16,30 +16,39 @@
// and that you want to learn Vulkan. This means that for example it won't go into details about
// what a vertex or a shader is.
use std::collections::HashMap;
use std::sync::Arc;
use vulkano::buffer::{BufferUsage, CpuAccessibleBuffer, TypedBufferAccess};
use vulkano::command_buffer::{AutoCommandBufferBuilder, CommandBufferUsage, SubpassContents};
use vulkano::device::physical::{PhysicalDevice, PhysicalDeviceType};
use vulkano::device::{Device, DeviceCreateInfo, DeviceExtensions, QueueCreateInfo};
use vulkano::image::view::ImageView;
use vulkano::image::{ImageAccess, ImageUsage, SwapchainImage};
use vulkano::instance::{Instance, InstanceCreateInfo};
use vulkano::pipeline::graphics::input_assembly::InputAssemblyState;
use vulkano::pipeline::graphics::vertex_input::BuffersDefinition;
use vulkano::pipeline::graphics::viewport::{Viewport, ViewportState};
use vulkano::pipeline::GraphicsPipeline;
use vulkano::render_pass::{Framebuffer, FramebufferCreateInfo, RenderPass, Subpass};
use vulkano::swapchain::{
self, AcquireError, Surface, Swapchain, SwapchainCreateInfo, SwapchainCreationError,
use bytemuck::{Pod, Zeroable};
use std::{collections::HashMap, sync::Arc};
use vulkano::{
buffer::{BufferUsage, CpuAccessibleBuffer, TypedBufferAccess},
command_buffer::{AutoCommandBufferBuilder, CommandBufferUsage, SubpassContents},
device::{
physical::{PhysicalDevice, PhysicalDeviceType},
Device, DeviceCreateInfo, DeviceExtensions, QueueCreateInfo,
},
image::{view::ImageView, ImageAccess, ImageUsage, SwapchainImage},
impl_vertex,
instance::{Instance, InstanceCreateInfo},
pipeline::{
graphics::{
input_assembly::InputAssemblyState,
vertex_input::BuffersDefinition,
viewport::{Viewport, ViewportState},
},
GraphicsPipeline,
},
render_pass::{Framebuffer, FramebufferCreateInfo, RenderPass, Subpass},
swapchain::{
acquire_next_image, AcquireError, Surface, Swapchain, SwapchainCreateInfo,
SwapchainCreationError,
},
sync::{self, FlushError, GpuFuture},
};
use vulkano::sync::{self, FlushError, GpuFuture};
use vulkano_win::VkSurfaceBuild;
use winit::event::ElementState;
use winit::event::KeyboardInput;
use winit::event::{Event, WindowEvent};
use winit::event_loop::{ControlFlow, EventLoop};
use winit::window::{Window, WindowBuilder};
use winit::{
event::{ElementState, Event, KeyboardInput, WindowEvent},
event_loop::{ControlFlow, EventLoop},
window::{Window, WindowBuilder},
};
// A struct to contain resources related to a window
struct WindowSurface {
@ -152,17 +161,13 @@ fn main() {
};
#[repr(C)]
#[derive(Default, Debug, Clone)]
#[derive(Clone, Copy, Debug, Default, Zeroable, Pod)]
struct Vertex {
position: [f32; 2],
}
vulkano::impl_vertex!(Vertex, position);
impl_vertex!(Vertex, position);
let vertex_buffer = CpuAccessibleBuffer::from_iter(
device.clone(),
BufferUsage::all(),
false,
[
let vertices = [
Vertex {
position: [-0.5, -0.25],
},
@ -172,10 +177,9 @@ fn main() {
Vertex {
position: [0.25, -0.1],
},
]
.iter()
.cloned(),
)
];
let vertex_buffer =
CpuAccessibleBuffer::from_iter(device.clone(), BufferUsage::all(), false, vertices)
.unwrap();
mod vs {
@ -365,7 +369,7 @@ fn main() {
}
let (image_num, suboptimal, acquire_future) =
match swapchain::acquire_next_image(swapchain.clone(), None) {
match acquire_next_image(swapchain.clone(), None) {
Ok(r) => r,
Err(AcquireError::OutOfDate) => {
*recreate_swapchain = true;

View File

@ -7,18 +7,17 @@
// notice may not be copied, modified, or distributed except
// according to those terms.
use crate::game_of_life::GameOfLifeComputePipeline;
use crate::render_pass::RenderPassPlaceOverFrame;
use crate::vulkano_config::VulkanoConfig;
use crate::vulkano_context::VulkanoContext;
use crate::vulkano_window::VulkanoWindow;
use crate::{SCALING, WINDOW2_HEIGHT, WINDOW2_WIDTH, WINDOW_HEIGHT, WINDOW_WIDTH};
use std::collections::HashMap;
use std::sync::Arc;
use vulkano::device::Queue;
use vulkano::format::Format;
use winit::event_loop::EventLoop;
use winit::window::{WindowBuilder, WindowId};
use crate::{
game_of_life::GameOfLifeComputePipeline, render_pass::RenderPassPlaceOverFrame,
vulkano_config::VulkanoConfig, vulkano_context::VulkanoContext, vulkano_window::VulkanoWindow,
SCALING, WINDOW2_HEIGHT, WINDOW2_WIDTH, WINDOW_HEIGHT, WINDOW_WIDTH,
};
use std::{collections::HashMap, sync::Arc};
use vulkano::{device::Queue, format::Format};
use winit::{
event_loop::EventLoop,
window::{WindowBuilder, WindowId},
};
pub struct RenderPipeline {
pub compute: GameOfLifeComputePipeline,

View File

@ -7,20 +7,20 @@
// notice may not be copied, modified, or distributed except
// according to those terms.
use crate::vulkano_context::DeviceImageView;
use crate::vulkano_window::create_device_image;
use crate::{vulkano_context::DeviceImageView, vulkano_window::create_device_image};
use cgmath::Vector2;
use rand::Rng;
use std::sync::Arc;
use vulkano::buffer::{BufferUsage, CpuAccessibleBuffer};
use vulkano::command_buffer::PrimaryAutoCommandBuffer;
use vulkano::command_buffer::{AutoCommandBufferBuilder, CommandBufferUsage};
use vulkano::descriptor_set::{PersistentDescriptorSet, WriteDescriptorSet};
use vulkano::device::Queue;
use vulkano::format::Format;
use vulkano::image::ImageAccess;
use vulkano::pipeline::{ComputePipeline, Pipeline, PipelineBindPoint};
use vulkano::sync::GpuFuture;
use vulkano::{
buffer::{BufferUsage, CpuAccessibleBuffer},
command_buffer::{AutoCommandBufferBuilder, CommandBufferUsage, PrimaryAutoCommandBuffer},
descriptor_set::{PersistentDescriptorSet, WriteDescriptorSet},
device::Queue,
format::Format,
image::ImageAccess,
pipeline::{ComputePipeline, Pipeline, PipelineBindPoint},
sync::GpuFuture,
};
/// Pipeline holding double buffered grid & color image.
/// Grids are used to calculate the state, and color image is used to show the output.

View File

@ -17,14 +17,15 @@ mod vulkano_context;
#[allow(unused)]
mod vulkano_window;
use crate::app::{App, RenderPipeline};
use crate::vulkano_window::VulkanoWindow;
use crate::{
app::{App, RenderPipeline},
vulkano_window::VulkanoWindow,
};
use cgmath::Vector2;
use time::Instant;
use std::time::Instant;
use vulkano::image::ImageAccess;
use winit::event::{ElementState, MouseButton};
use winit::{
event::{Event, WindowEvent},
event::{ElementState, Event, MouseButton, WindowEvent},
event_loop::{ControlFlow, EventLoop},
platform::run_return::EventLoopExtRunReturn,
};
@ -81,7 +82,7 @@ fn main() {
mouse_is_pressed_w2,
);
// Compute life & render 60fps
if (Instant::now() - time).as_seconds_f64() > 1.0 / 60.0 {
if (Instant::now() - time).as_secs_f64() > 1.0 / 60.0 {
compute_then_render_per_window(&mut app);
time = Instant::now();
}

View File

@ -7,29 +7,35 @@
// notice may not be copied, modified, or distributed except
// according to those terms.
use bytemuck::{Pod, Zeroable};
use std::sync::Arc;
use vulkano::buffer::{BufferUsage, CpuAccessibleBuffer, TypedBufferAccess};
use vulkano::command_buffer::{
AutoCommandBufferBuilder, CommandBufferUsage, SecondaryAutoCommandBuffer,
use vulkano::{
buffer::{BufferUsage, CpuAccessibleBuffer, TypedBufferAccess},
command_buffer::{AutoCommandBufferBuilder, CommandBufferUsage, SecondaryAutoCommandBuffer},
descriptor_set::{PersistentDescriptorSet, WriteDescriptorSet},
device::Queue,
image::ImageViewAbstract,
impl_vertex,
pipeline::{
graphics::{
input_assembly::InputAssemblyState,
vertex_input::BuffersDefinition,
viewport::{Viewport, ViewportState},
},
GraphicsPipeline, Pipeline, PipelineBindPoint,
},
render_pass::Subpass,
sampler::{Filter, Sampler, SamplerAddressMode, SamplerCreateInfo, SamplerMipmapMode},
};
use vulkano::descriptor_set::{PersistentDescriptorSet, WriteDescriptorSet};
use vulkano::device::Queue;
use vulkano::image::ImageViewAbstract;
use vulkano::pipeline::graphics::input_assembly::InputAssemblyState;
use vulkano::pipeline::graphics::vertex_input::BuffersDefinition;
use vulkano::pipeline::graphics::viewport::{Viewport, ViewportState};
use vulkano::pipeline::{GraphicsPipeline, Pipeline, PipelineBindPoint};
use vulkano::render_pass::Subpass;
use vulkano::sampler::{Filter, Sampler, SamplerAddressMode, SamplerCreateInfo, SamplerMipmapMode};
/// Vertex for textured quads
#[repr(C)]
#[derive(Default, Debug, Clone, Copy)]
#[derive(Clone, Copy, Debug, Default, Zeroable, Pod)]
pub struct TexturedVertex {
pub position: [f32; 2],
pub tex_coords: [f32; 2],
}
vulkano::impl_vertex!(TexturedVertex, position, tex_coords);
impl_vertex!(TexturedVertex, position, tex_coords);
pub fn textured_quad(width: f32, height: f32) -> (Vec<TexturedVertex>, Vec<u32>) {
(

View File

@ -7,8 +7,11 @@
// notice may not be copied, modified, or distributed except
// according to those terms.
use crate::{
pixels_draw::PixelsDrawPipeline,
vulkano_context::{DeviceImageView, FinalImageView},
};
use std::sync::Arc;
use vulkano::{
command_buffer::{AutoCommandBufferBuilder, CommandBufferUsage, SubpassContents},
device::Queue,
@ -18,9 +21,6 @@ use vulkano::{
sync::GpuFuture,
};
use crate::pixels_draw::PixelsDrawPipeline;
use crate::vulkano_context::{DeviceImageView, FinalImageView};
/// A render pass which places an incoming image over frame filling it
pub struct RenderPassPlaceOverFrame {
gfx_queue: Arc<Queue>,

View File

@ -6,19 +6,18 @@
// at your option. All files in the project carrying such
// notice may not be copied, modified, or distributed except
// according to those terms.
use crate::vulkano_config::VulkanoConfig;
use std::{
ffi::{CStr, CString},
sync::Arc,
};
#[cfg(target_os = "macos")]
use vulkano::instance::InstanceCreationError;
use vulkano::{
device::{
physical::{PhysicalDevice, PhysicalDeviceType},
Device, DeviceCreateInfo, DeviceExtensions, Features, Queue, QueueCreateInfo,
},
image::{view::ImageView, ImageUsage},
image::{view::ImageView, ImageUsage, StorageImage, SwapchainImage},
instance::{
debug::{DebugCallback, MessageSeverity, MessageType},
Instance, InstanceCreateInfo, InstanceExtensions,
@ -31,9 +30,6 @@ use vulkano::{
};
use winit::window::Window;
use crate::vulkano_config::VulkanoConfig;
use vulkano::image::{StorageImage, SwapchainImage};
/// Final render target onto which whole app is rendered (per window)
pub type FinalImageView = Arc<ImageView<SwapchainImage<Window>>>;
/// Multipurpose image view
@ -257,7 +253,10 @@ pub fn create_vk_instance(
// Handle errors. On mac os, it will ask you to install vulkan sdk if you have not done so.
#[cfg(target_os = "macos")]
let instance = match result {
let instance = {
use vulkano::instance::InstanceCreationError;
match result {
Err(e) => match e {
InstanceCreationError::LoadingError(le) => {
println!(
@ -269,6 +268,7 @@ pub fn create_vk_instance(
_ => Err(e).expect("Failed to create instance"),
},
Ok(i) => i,
}
};
#[cfg(not(target_os = "macos"))]
let instance = result.expect("Failed to create instance");

View File

@ -6,12 +6,16 @@
// at your option. All files in the project carrying such
// notice may not be copied, modified, or distributed except
// according to those terms.
use std::sync::Arc;
use crate::vulkano_context::{DeviceImageView, FinalImageView, VulkanoContext};
use std::{collections::HashMap, sync::Arc};
use vulkano::{
device::{DeviceOwned, Queue},
format::Format,
image::{view::ImageView, ImageAccess, ImageViewAbstract},
image::{
view::ImageView, ImageAccess, ImageCreateFlags, ImageDimensions, ImageUsage,
ImageViewAbstract, StorageImage,
},
swapchain,
swapchain::{
AcquireError, PresentMode, Surface, Swapchain, SwapchainCreateInfo, SwapchainCreationError,
@ -22,11 +26,6 @@ use vulkano::{
use vulkano_win::create_surface_from_handle;
use winit::window::Window;
use crate::vulkano_context::{DeviceImageView, FinalImageView, VulkanoContext};
use std::collections::HashMap;
use vulkano::image::{ImageCreateFlags, ImageDimensions, ImageUsage, StorageImage};
pub struct VulkanoWindow {
surface: Arc<Surface<Window>>,
graphics_queue: Arc<Queue>,

View File

@ -13,30 +13,36 @@
//! or other types of stereoscopic rendering where the left and right eye only differ
//! in a small position offset.
use std::fs::File;
use std::io::BufWriter;
use std::path::Path;
use std::sync::Arc;
use vulkano::buffer::{BufferUsage, CpuAccessibleBuffer, TypedBufferAccess};
use vulkano::command_buffer::{AutoCommandBufferBuilder, CommandBufferUsage, SubpassContents};
use vulkano::device::physical::{PhysicalDevice, PhysicalDeviceType};
use vulkano::device::{Device, DeviceCreateInfo, DeviceExtensions, Features, QueueCreateInfo};
use vulkano::format::Format;
use vulkano::image::view::ImageView;
use vulkano::image::{
ImageAccess, ImageCreateFlags, ImageDimensions, ImageLayout, ImageUsage, SampleCount,
StorageImage,
};
use vulkano::instance::{Instance, InstanceCreateInfo, InstanceExtensions};
use vulkano::pipeline::graphics::input_assembly::InputAssemblyState;
use vulkano::pipeline::graphics::vertex_input::BuffersDefinition;
use vulkano::pipeline::graphics::viewport::{Viewport, ViewportState};
use vulkano::pipeline::GraphicsPipeline;
use vulkano::render_pass::{
use bytemuck::{Pod, Zeroable};
use std::{fs::File, io::BufWriter, path::Path, sync::Arc};
use vulkano::{
buffer::{BufferUsage, CpuAccessibleBuffer, TypedBufferAccess},
command_buffer::{AutoCommandBufferBuilder, CommandBufferUsage, SubpassContents},
device::{
physical::{PhysicalDevice, PhysicalDeviceType},
Device, DeviceCreateInfo, DeviceExtensions, Features, QueueCreateInfo,
},
format::Format,
image::{
view::ImageView, ImageAccess, ImageCreateFlags, ImageDimensions, ImageLayout, ImageUsage,
SampleCount, StorageImage,
},
impl_vertex,
instance::{Instance, InstanceCreateInfo, InstanceExtensions},
pipeline::{
graphics::{
input_assembly::InputAssemblyState,
vertex_input::BuffersDefinition,
viewport::{Viewport, ViewportState},
},
GraphicsPipeline,
},
render_pass::{
AttachmentDescription, AttachmentReference, Framebuffer, FramebufferCreateInfo, LoadOp,
RenderPass, RenderPassCreateInfo, StoreOp, Subpass, SubpassDescription,
},
sync::{self, GpuFuture},
};
use vulkano::sync::{self, GpuFuture};
fn main() {
let instance = Instance::new(InstanceCreateInfo {
@ -131,17 +137,13 @@ fn main() {
let image_view = ImageView::new_default(image.clone()).unwrap();
#[repr(C)]
#[derive(Default, Debug, Clone)]
#[derive(Clone, Copy, Debug, Default, Zeroable, Pod)]
struct Vertex {
position: [f32; 2],
}
vulkano::impl_vertex!(Vertex, position);
impl_vertex!(Vertex, position);
let vertex_buffer = CpuAccessibleBuffer::from_iter(
device.clone(),
BufferUsage::all(),
false,
[
let vertices = [
Vertex {
position: [-0.5, -0.25],
},
@ -151,10 +153,9 @@ fn main() {
Vertex {
position: [0.25, -0.1],
},
]
.iter()
.cloned(),
)
];
let vertex_buffer =
CpuAccessibleBuffer::from_iter(device.clone(), BufferUsage::all(), false, vertices)
.unwrap();
// Note the `#extension GL_EXT_multiview : enable` that enables the multiview extension

View File

@ -11,32 +11,41 @@
// Occlusion queries allow you to query whether, and sometimes how many, pixels pass the depth test
// in a range of draw calls.
use bytemuck::{Pod, Zeroable};
use std::sync::Arc;
use vulkano::buffer::{BufferAccess, BufferUsage, CpuAccessibleBuffer};
use vulkano::command_buffer::{AutoCommandBufferBuilder, CommandBufferUsage, SubpassContents};
use vulkano::device::physical::{PhysicalDevice, PhysicalDeviceType};
use vulkano::device::{Device, DeviceCreateInfo, DeviceExtensions, DeviceOwned, QueueCreateInfo};
use vulkano::format::Format;
use vulkano::image::ImageAccess;
use vulkano::image::{view::ImageView, AttachmentImage, ImageUsage, SwapchainImage};
use vulkano::instance::{Instance, InstanceCreateInfo};
use vulkano::pipeline::graphics::depth_stencil::DepthStencilState;
use vulkano::pipeline::graphics::input_assembly::InputAssemblyState;
use vulkano::pipeline::graphics::vertex_input::BuffersDefinition;
use vulkano::pipeline::graphics::viewport::{Viewport, ViewportState};
use vulkano::pipeline::GraphicsPipeline;
use vulkano::query::{
QueryControlFlags, QueryPool, QueryPoolCreateInfo, QueryResultFlags, QueryType,
use vulkano::{
buffer::{BufferAccess, BufferUsage, CpuAccessibleBuffer},
command_buffer::{AutoCommandBufferBuilder, CommandBufferUsage, SubpassContents},
device::{
physical::{PhysicalDevice, PhysicalDeviceType},
Device, DeviceCreateInfo, DeviceExtensions, DeviceOwned, QueueCreateInfo,
},
format::Format,
image::{view::ImageView, AttachmentImage, ImageAccess, ImageUsage, SwapchainImage},
impl_vertex,
instance::{Instance, InstanceCreateInfo},
pipeline::{
graphics::{
depth_stencil::DepthStencilState,
input_assembly::InputAssemblyState,
vertex_input::BuffersDefinition,
viewport::{Viewport, ViewportState},
},
GraphicsPipeline,
},
query::{QueryControlFlags, QueryPool, QueryPoolCreateInfo, QueryResultFlags, QueryType},
render_pass::{Framebuffer, FramebufferCreateInfo, RenderPass, Subpass},
swapchain::{
acquire_next_image, AcquireError, Swapchain, SwapchainCreateInfo, SwapchainCreationError,
},
sync::{self, FlushError, GpuFuture},
};
use vulkano::render_pass::{Framebuffer, FramebufferCreateInfo, RenderPass, Subpass};
use vulkano::swapchain::{
self, AcquireError, Swapchain, SwapchainCreateInfo, SwapchainCreationError,
};
use vulkano::sync::{self, FlushError, GpuFuture};
use vulkano_win::VkSurfaceBuild;
use winit::event::{Event, WindowEvent};
use winit::event_loop::{ControlFlow, EventLoop};
use winit::window::{Window, WindowBuilder};
use winit::{
event::{Event, WindowEvent},
event_loop::{ControlFlow, EventLoop},
window::{Window, WindowBuilder},
};
fn main() {
let required_extensions = vulkano_win::required_extensions();
@ -121,18 +130,14 @@ fn main() {
};
#[repr(C)]
#[derive(Default, Debug, Clone)]
#[derive(Clone, Copy, Debug, Default, Zeroable, Pod)]
struct Vertex {
position: [f32; 3],
color: [f32; 3],
}
vulkano::impl_vertex!(Vertex, position, color);
impl_vertex!(Vertex, position, color);
let vertex_buffer = CpuAccessibleBuffer::from_iter(
device.clone(),
BufferUsage::all(),
false,
[
let vertices = [
// The first triangle (red) is the same one as in the triangle example.
Vertex {
position: [-0.5, -0.25, 0.5],
@ -177,16 +182,15 @@ fn main() {
position: [0.5, -0.1, 0.7],
color: [0.0, 1.0, 0.0],
},
]
.iter()
.cloned(),
)
];
let vertex_buffer =
CpuAccessibleBuffer::from_iter(device.clone(), BufferUsage::all(), false, vertices)
.unwrap();
// Create three buffer slices, one for each triangle.
let triangle1 = vertex_buffer.slice(0..3).unwrap();
let triangle2 = vertex_buffer.slice(3..6).unwrap();
let triangle3 = vertex_buffer.slice(6..9).unwrap();
let triangle1 = vertex_buffer.slice::<Vertex>(0..3).unwrap();
let triangle2 = vertex_buffer.slice::<Vertex>(3..6).unwrap();
let triangle3 = vertex_buffer.slice::<Vertex>(6..9).unwrap();
// Create a query pool for occlusion queries, with 3 slots.
let query_pool = QueryPool::new(
@ -201,7 +205,7 @@ fn main() {
// Create a buffer on the CPU to hold the results of the three queries.
// Query results are always represented as either `u32` or `u64`.
// For occlusion queries, you always need one element per query. You can ask for the number of
// elements needed at runtime by calling `QueryType::result_size`.
// elements needed at runtime by calling `QueryType::result_len`.
// If you retrieve query results with `with_availability` enabled, then this array needs to
// be 6 elements long instead of 3.
let mut query_results = [0u32; 3];
@ -325,7 +329,7 @@ fn main() {
}
let (image_num, suboptimal, acquire_future) =
match swapchain::acquire_next_image(swapchain.clone(), None) {
match acquire_next_image(swapchain.clone(), None) {
Ok(r) => r,
Err(AcquireError::OutOfDate) => {
recreate_swapchain = true;
@ -433,8 +437,10 @@ fn main() {
// Note: if not all the queries have actually been executed, then this
// will wait forever for something that never happens!
wait: true,
// Blocking and waiting will never give partial results.
partial: false,
// Blocking and waiting will ensure the results are always available after
// the function returns.
//

View File

@ -27,17 +27,18 @@
// In the future, vulkano might implement those safety checks, but for
// now, you would have to do that yourself or trust the data and the user.
use std::fs;
use std::fs::File;
use std::io::Read;
use std::io::Write;
use vulkano::device::physical::{PhysicalDevice, PhysicalDeviceType};
use vulkano::device::DeviceCreateInfo;
use vulkano::device::QueueCreateInfo;
use vulkano::device::{Device, DeviceExtensions};
use vulkano::instance::Instance;
use vulkano::pipeline::cache::PipelineCache;
use vulkano::pipeline::ComputePipeline;
use std::{
fs::{remove_file, rename, File},
io::{Read, Write},
};
use vulkano::{
device::{
physical::{PhysicalDevice, PhysicalDeviceType},
Device, DeviceCreateInfo, DeviceExtensions, QueueCreateInfo,
},
instance::Instance,
pipeline::{cache::PipelineCache, ComputePipeline},
};
fn main() {
// As with other examples, the first step is to create an instance.
@ -137,9 +138,9 @@ fn main() {
if let Ok(data) = pipeline_cache.get_data() {
if let Ok(mut file) = File::create("pipeline_cache.bin.tmp") {
if let Ok(_) = file.write_all(&data) {
let _ = fs::rename("pipeline_cache.bin.tmp", "pipeline_cache.bin");
let _ = rename("pipeline_cache.bin.tmp", "pipeline_cache.bin");
} else {
let _ = fs::remove_file("pipeline_cache.bin.tmp");
let _ = remove_file("pipeline_cache.bin.tmp");
}
}
}

View File

@ -9,15 +9,18 @@
// TODO: Give a paragraph about what push constants are and what problems they solve
use vulkano::buffer::{BufferUsage, CpuAccessibleBuffer};
use vulkano::command_buffer::{AutoCommandBufferBuilder, CommandBufferUsage};
use vulkano::descriptor_set::{PersistentDescriptorSet, WriteDescriptorSet};
use vulkano::device::physical::{PhysicalDevice, PhysicalDeviceType};
use vulkano::device::{Device, DeviceCreateInfo, DeviceExtensions, QueueCreateInfo};
use vulkano::instance::Instance;
use vulkano::pipeline::{ComputePipeline, Pipeline, PipelineBindPoint};
use vulkano::sync;
use vulkano::sync::GpuFuture;
use vulkano::{
buffer::{BufferUsage, CpuAccessibleBuffer},
command_buffer::{AutoCommandBufferBuilder, CommandBufferUsage},
descriptor_set::{PersistentDescriptorSet, WriteDescriptorSet},
device::{
physical::{PhysicalDevice, PhysicalDeviceType},
Device, DeviceCreateInfo, DeviceExtensions, QueueCreateInfo,
},
instance::Instance,
pipeline::{ComputePipeline, Pipeline, PipelineBindPoint},
sync::{self, GpuFuture},
};
fn main() {
let instance = Instance::new(Default::default()).unwrap();

View File

@ -7,35 +7,45 @@
// notice may not be copied, modified, or distributed except
// according to those terms.
use png;
use std::io::Cursor;
use std::sync::Arc;
use vulkano::buffer::{BufferUsage, CpuAccessibleBuffer, TypedBufferAccess};
use vulkano::command_buffer::{AutoCommandBufferBuilder, CommandBufferUsage, SubpassContents};
use vulkano::descriptor_set::WriteDescriptorSet;
use vulkano::device::physical::{PhysicalDevice, PhysicalDeviceType};
use vulkano::device::{Device, DeviceCreateInfo, DeviceExtensions, QueueCreateInfo};
use vulkano::format::Format;
use vulkano::image::ImageAccess;
use vulkano::image::{
view::ImageView, ImageDimensions, ImageUsage, ImmutableImage, MipmapsCount, SwapchainImage,
use bytemuck::{Pod, Zeroable};
use std::{io::Cursor, sync::Arc};
use vulkano::{
buffer::{BufferUsage, CpuAccessibleBuffer, TypedBufferAccess},
command_buffer::{AutoCommandBufferBuilder, CommandBufferUsage, SubpassContents},
descriptor_set::WriteDescriptorSet,
device::{
physical::{PhysicalDevice, PhysicalDeviceType},
Device, DeviceCreateInfo, DeviceExtensions, QueueCreateInfo,
},
format::Format,
image::{
view::ImageView, ImageAccess, ImageDimensions, ImageUsage, ImmutableImage, MipmapsCount,
SwapchainImage,
},
impl_vertex,
instance::{Instance, InstanceCreateInfo},
pipeline::{
graphics::{
color_blend::ColorBlendState,
input_assembly::{InputAssemblyState, PrimitiveTopology},
vertex_input::BuffersDefinition,
viewport::{Viewport, ViewportState},
},
GraphicsPipeline, Pipeline, PipelineBindPoint,
},
render_pass::{Framebuffer, FramebufferCreateInfo, RenderPass, Subpass},
sampler::{Filter, Sampler, SamplerAddressMode, SamplerCreateInfo},
swapchain::{
acquire_next_image, AcquireError, Swapchain, SwapchainCreateInfo, SwapchainCreationError,
},
sync::{self, FlushError, GpuFuture},
};
use vulkano::instance::{Instance, InstanceCreateInfo};
use vulkano::pipeline::graphics::color_blend::ColorBlendState;
use vulkano::pipeline::graphics::input_assembly::{InputAssemblyState, PrimitiveTopology};
use vulkano::pipeline::graphics::vertex_input::BuffersDefinition;
use vulkano::pipeline::graphics::viewport::{Viewport, ViewportState};
use vulkano::pipeline::{GraphicsPipeline, Pipeline, PipelineBindPoint};
use vulkano::render_pass::{Framebuffer, FramebufferCreateInfo, RenderPass, Subpass};
use vulkano::sampler::{Filter, Sampler, SamplerAddressMode, SamplerCreateInfo};
use vulkano::swapchain::{
self, AcquireError, Swapchain, SwapchainCreateInfo, SwapchainCreationError,
};
use vulkano::sync::{self, FlushError, GpuFuture};
use vulkano_win::VkSurfaceBuild;
use winit::event::{Event, WindowEvent};
use winit::event_loop::{ControlFlow, EventLoop};
use winit::window::{Window, WindowBuilder};
use winit::{
event::{Event, WindowEvent},
event_loop::{ControlFlow, EventLoop},
window::{Window, WindowBuilder},
};
fn main() {
let required_extensions = vulkano_win::required_extensions();
@ -121,17 +131,13 @@ fn main() {
};
#[repr(C)]
#[derive(Default, Debug, Clone)]
#[derive(Clone, Copy, Debug, Default, Zeroable, Pod)]
struct Vertex {
position: [f32; 2],
}
vulkano::impl_vertex!(Vertex, position);
impl_vertex!(Vertex, position);
let vertex_buffer = CpuAccessibleBuffer::<[Vertex]>::from_iter(
device.clone(),
BufferUsage::all(),
false,
[
let vertices = [
Vertex {
position: [-0.5, -0.5],
},
@ -144,9 +150,12 @@ fn main() {
Vertex {
position: [0.5, 0.5],
},
]
.iter()
.cloned(),
];
let vertex_buffer = CpuAccessibleBuffer::<[Vertex]>::from_iter(
device.clone(),
BufferUsage::all(),
false,
vertices,
)
.unwrap();
@ -185,7 +194,7 @@ fn main() {
reader.next_frame(&mut image_data).unwrap();
let (image, future) = ImmutableImage::from_iter(
image_data.iter().cloned(),
image_data,
dimensions,
MipmapsCount::One,
Format::R8G8B8A8_SRGB,
@ -266,7 +275,7 @@ fn main() {
}
let (image_num, suboptimal, acquire_future) =
match swapchain::acquire_next_image(swapchain.clone(), None) {
match acquire_next_image(swapchain.clone(), None) {
Ok(r) => r,
Err(AcquireError::OutOfDate) => {
recreate_swapchain = true;

View File

@ -19,41 +19,49 @@
// $ glslangValidator frag.glsl -V -S frag -o frag.spv
// Vulkano uses glslangValidator to build your shaders internally.
use std::fs::File;
use std::io::Read;
use std::sync::Arc;
use vulkano::buffer::cpu_access::CpuAccessibleBuffer;
use vulkano::buffer::{BufferUsage, TypedBufferAccess};
use vulkano::command_buffer::{AutoCommandBufferBuilder, CommandBufferUsage, SubpassContents};
use vulkano::device::physical::{PhysicalDevice, PhysicalDeviceType};
use vulkano::device::{Device, DeviceCreateInfo, DeviceExtensions, QueueCreateInfo};
use vulkano::image::view::ImageView;
use vulkano::image::{ImageAccess, ImageUsage, SwapchainImage};
use vulkano::instance::{Instance, InstanceCreateInfo};
use vulkano::pipeline::graphics::input_assembly::InputAssemblyState;
use vulkano::pipeline::graphics::rasterization::{CullMode, FrontFace, RasterizationState};
use vulkano::pipeline::graphics::vertex_input::BuffersDefinition;
use vulkano::pipeline::graphics::viewport::{Viewport, ViewportState};
use vulkano::pipeline::GraphicsPipeline;
use vulkano::render_pass::{Framebuffer, FramebufferCreateInfo, RenderPass, Subpass};
use vulkano::shader::ShaderModule;
use vulkano::swapchain::{
self, AcquireError, Swapchain, SwapchainCreateInfo, SwapchainCreationError,
use bytemuck::{Pod, Zeroable};
use std::{fs::File, io::Read, sync::Arc};
use vulkano::{
buffer::{BufferUsage, CpuAccessibleBuffer, TypedBufferAccess},
command_buffer::{AutoCommandBufferBuilder, CommandBufferUsage, SubpassContents},
device::{
physical::{PhysicalDevice, PhysicalDeviceType},
Device, DeviceCreateInfo, DeviceExtensions, QueueCreateInfo,
},
image::{view::ImageView, ImageAccess, ImageUsage, SwapchainImage},
impl_vertex,
instance::{Instance, InstanceCreateInfo},
pipeline::{
graphics::{
input_assembly::InputAssemblyState,
rasterization::{CullMode, FrontFace, RasterizationState},
vertex_input::BuffersDefinition,
viewport::{Viewport, ViewportState},
},
GraphicsPipeline,
},
render_pass::{Framebuffer, FramebufferCreateInfo, RenderPass, Subpass},
shader::ShaderModule,
swapchain::{
acquire_next_image, AcquireError, Swapchain, SwapchainCreateInfo, SwapchainCreationError,
},
sync::{self, FlushError, GpuFuture},
};
use vulkano::sync::{self, FlushError, GpuFuture};
use vulkano_win::VkSurfaceBuild;
use winit::event::{Event, WindowEvent};
use winit::event_loop::{ControlFlow, EventLoop};
use winit::window::{Window, WindowBuilder};
use winit::{
event::{Event, WindowEvent},
event_loop::{ControlFlow, EventLoop},
window::{Window, WindowBuilder},
};
#[repr(C)]
#[derive(Default, Copy, Clone)]
#[derive(Clone, Copy, Debug, Default, Zeroable, Pod)]
pub struct Vertex {
pub position: [f32; 2],
pub color: [f32; 3],
}
vulkano::impl_vertex!(Vertex, position, color);
impl_vertex!(Vertex, position, color);
fn main() {
let required_extensions = vulkano_win::required_extensions();
@ -189,11 +197,7 @@ fn main() {
let mut recreate_swapchain = false;
let vertex_buffer = CpuAccessibleBuffer::from_iter(
device.clone(),
BufferUsage::all(),
false,
[
let vertices = [
Vertex {
position: [-1.0, 1.0],
color: [1.0, 0.0, 0.0],
@ -206,10 +210,9 @@ fn main() {
position: [1.0, 1.0],
color: [0.0, 0.0, 1.0],
},
]
.iter()
.cloned(),
)
];
let vertex_buffer =
CpuAccessibleBuffer::from_iter(device.clone(), BufferUsage::all(), false, vertices)
.unwrap();
// NOTE: We don't create any descriptor sets in this example, but you should
@ -257,7 +260,7 @@ fn main() {
}
let (image_num, suboptimal, acquire_future) =
match swapchain::acquire_next_image(swapchain.clone(), None) {
match acquire_next_image(swapchain.clone(), None) {
Ok(r) => r,
Err(AcquireError::OutOfDate) => {
recreate_swapchain = true;

View File

@ -7,38 +7,50 @@
// notice may not be copied, modified, or distributed except
// according to those terms.
use png;
use std::io::Cursor;
use std::sync::Arc;
use vulkano::buffer::{BufferUsage, CpuAccessibleBuffer, TypedBufferAccess};
use vulkano::command_buffer::{AutoCommandBufferBuilder, CommandBufferUsage, SubpassContents};
use vulkano::descriptor_set::layout::{
use bytemuck::{Pod, Zeroable};
use std::{io::Cursor, sync::Arc};
use vulkano::{
buffer::{BufferUsage, CpuAccessibleBuffer, TypedBufferAccess},
command_buffer::{AutoCommandBufferBuilder, CommandBufferUsage, SubpassContents},
descriptor_set::{
layout::{
DescriptorSetLayout, DescriptorSetLayoutCreateInfo, DescriptorSetLayoutCreationError,
},
PersistentDescriptorSet, WriteDescriptorSet,
},
device::{
physical::{PhysicalDevice, PhysicalDeviceType},
Device, DeviceCreateInfo, DeviceExtensions, Features, QueueCreateInfo,
},
format::Format,
image::{
view::ImageView, ImageAccess, ImageDimensions, ImageUsage, ImmutableImage, MipmapsCount,
SwapchainImage,
},
impl_vertex,
instance::{Instance, InstanceCreateInfo},
pipeline::{
graphics::{
color_blend::ColorBlendState,
vertex_input::BuffersDefinition,
viewport::{Viewport, ViewportState},
},
layout::PipelineLayoutCreateInfo,
GraphicsPipeline, Pipeline, PipelineBindPoint, PipelineLayout,
},
render_pass::{Framebuffer, FramebufferCreateInfo, RenderPass, Subpass},
sampler::{Filter, Sampler, SamplerAddressMode, SamplerCreateInfo},
swapchain::{
acquire_next_image, AcquireError, Swapchain, SwapchainCreateInfo, SwapchainCreationError,
},
sync::{self, FlushError, GpuFuture},
};
use vulkano::descriptor_set::{PersistentDescriptorSet, WriteDescriptorSet};
use vulkano::device::physical::{PhysicalDevice, PhysicalDeviceType};
use vulkano::device::{Device, DeviceCreateInfo, DeviceExtensions, Features, QueueCreateInfo};
use vulkano::format::Format;
use vulkano::image::ImageAccess;
use vulkano::image::{
view::ImageView, ImageDimensions, ImageUsage, ImmutableImage, MipmapsCount, SwapchainImage,
};
use vulkano::instance::{Instance, InstanceCreateInfo};
use vulkano::pipeline::graphics::color_blend::ColorBlendState;
use vulkano::pipeline::graphics::vertex_input::BuffersDefinition;
use vulkano::pipeline::graphics::viewport::{Viewport, ViewportState};
use vulkano::pipeline::layout::{PipelineLayout, PipelineLayoutCreateInfo};
use vulkano::pipeline::{GraphicsPipeline, Pipeline, PipelineBindPoint};
use vulkano::render_pass::{Framebuffer, FramebufferCreateInfo, RenderPass, Subpass};
use vulkano::sampler::{Filter, Sampler, SamplerAddressMode, SamplerCreateInfo};
use vulkano::swapchain::{
self, AcquireError, Swapchain, SwapchainCreateInfo, SwapchainCreationError,
};
use vulkano::sync::{self, FlushError, GpuFuture};
use vulkano_win::VkSurfaceBuild;
use winit::event::{Event, WindowEvent};
use winit::event_loop::{ControlFlow, EventLoop};
use winit::window::{Window, WindowBuilder};
use winit::{
event::{Event, WindowEvent},
event_loop::{ControlFlow, EventLoop},
window::{Window, WindowBuilder},
};
fn main() {
// The start of this example is exactly the same as `triangle`. You should read the
@ -133,19 +145,15 @@ fn main() {
};
#[repr(C)]
#[derive(Default, Debug, Clone)]
#[derive(Clone, Copy, Debug, Default, Zeroable, Pod)]
struct Vertex {
position: [f32; 2],
tex_i: u32,
coords: [f32; 2],
}
vulkano::impl_vertex!(Vertex, position, tex_i, coords);
impl_vertex!(Vertex, position, tex_i, coords);
let vertex_buffer = CpuAccessibleBuffer::<[Vertex]>::from_iter(
device.clone(),
BufferUsage::all(),
false,
[
let vertices = [
Vertex {
position: [-0.1, -0.9],
tex_i: 0,
@ -206,9 +214,12 @@ fn main() {
tex_i: 1,
coords: [1.0, 1.0],
},
]
.iter()
.cloned(),
];
let vertex_buffer = CpuAccessibleBuffer::<[Vertex]>::from_iter(
device.clone(),
BufferUsage::all(),
false,
vertices,
)
.unwrap();
@ -247,7 +258,7 @@ fn main() {
reader.next_frame(&mut image_data).unwrap();
let image = ImmutableImage::from_iter(
image_data.iter().cloned(),
image_data,
dimensions,
MipmapsCount::One,
Format::R8G8B8A8_SRGB,
@ -275,7 +286,7 @@ fn main() {
reader.next_frame(&mut image_data).unwrap();
let image = ImmutableImage::from_iter(
image_data.iter().cloned(),
image_data,
dimensions,
MipmapsCount::One,
Format::R8G8B8A8_SRGB,
@ -401,7 +412,7 @@ fn main() {
}
let (image_num, suboptimal, acquire_future) =
match swapchain::acquire_next_image(swapchain.clone(), None) {
match acquire_next_image(swapchain.clone(), None) {
Ok(r) => r,
Err(AcquireError::OutOfDate) => {
recreate_swapchain = true;

View File

@ -10,15 +10,18 @@
// This example is a copy of `basic-compute-shaders.rs`, but initalizes half of the input buffer
// and then we use `copy_buffer_dimensions` to copy the first half of the input buffer to the second half.
use vulkano::buffer::{BufferUsage, CpuAccessibleBuffer};
use vulkano::command_buffer::{AutoCommandBufferBuilder, CommandBufferUsage};
use vulkano::descriptor_set::{PersistentDescriptorSet, WriteDescriptorSet};
use vulkano::device::physical::{PhysicalDevice, PhysicalDeviceType};
use vulkano::device::{Device, DeviceCreateInfo, DeviceExtensions, QueueCreateInfo};
use vulkano::instance::Instance;
use vulkano::pipeline::{ComputePipeline, Pipeline, PipelineBindPoint};
use vulkano::sync;
use vulkano::sync::GpuFuture;
use vulkano::{
buffer::{BufferUsage, CpuAccessibleBuffer},
command_buffer::{AutoCommandBufferBuilder, CommandBufferUsage},
descriptor_set::{PersistentDescriptorSet, WriteDescriptorSet},
device::{
physical::{PhysicalDevice, PhysicalDeviceType},
Device, DeviceCreateInfo, DeviceExtensions, QueueCreateInfo,
},
instance::Instance,
pipeline::{ComputePipeline, Pipeline, PipelineBindPoint},
sync::{self, GpuFuture},
};
fn main() {
let instance = Instance::new(Default::default()).unwrap();

View File

@ -11,15 +11,18 @@
// shader source code. The boilerplate is taken from the "basic-compute-shader.rs" example, where
// most of the boilerplate is explained.
use vulkano::buffer::{BufferUsage, CpuAccessibleBuffer};
use vulkano::command_buffer::{AutoCommandBufferBuilder, CommandBufferUsage};
use vulkano::descriptor_set::{PersistentDescriptorSet, WriteDescriptorSet};
use vulkano::device::physical::{PhysicalDevice, PhysicalDeviceType};
use vulkano::device::{Device, DeviceCreateInfo, DeviceExtensions, QueueCreateInfo};
use vulkano::instance::Instance;
use vulkano::pipeline::{ComputePipeline, Pipeline, PipelineBindPoint};
use vulkano::sync;
use vulkano::sync::GpuFuture;
use vulkano::{
buffer::{BufferUsage, CpuAccessibleBuffer},
command_buffer::{AutoCommandBufferBuilder, CommandBufferUsage},
descriptor_set::{PersistentDescriptorSet, WriteDescriptorSet},
device::{
physical::{PhysicalDevice, PhysicalDeviceType},
Device, DeviceCreateInfo, DeviceExtensions, QueueCreateInfo,
},
instance::Instance,
pipeline::{ComputePipeline, Pipeline, PipelineBindPoint},
sync::{self, GpuFuture},
};
fn main() {
let instance = Instance::new(Default::default()).unwrap();

View File

@ -9,7 +9,7 @@
// This example demonstrates how to put derives onto generated Rust structs from
// the Shader types through the "types-meta" options of
// `vulkano_shaders::shader!` macro.
// `shader!` macro.
// Vulkano Shader macro is capable to generate Rust structs representing each
// type found in the shader source. These structs appear in the `ty` module
@ -30,8 +30,10 @@
// developer can also specify derives of traits from external modules/crates
// whenever such traits provide custom derive feature.
use ron::from_str;
use ron::ser::{to_string_pretty, PrettyConfig};
use ron::{
from_str,
ser::{to_string_pretty, PrettyConfig},
};
use std::fmt::{Debug, Display, Error, Formatter};
vulkano_shaders::shader! {

View File

@ -28,15 +28,18 @@
// `ty` submodule.
use std::sync::Arc;
use vulkano::buffer::{BufferUsage, CpuAccessibleBuffer};
use vulkano::command_buffer::{AutoCommandBufferBuilder, CommandBufferUsage};
use vulkano::descriptor_set::{PersistentDescriptorSet, WriteDescriptorSet};
use vulkano::device::physical::{PhysicalDevice, PhysicalDeviceType};
use vulkano::device::{Device, DeviceCreateInfo, DeviceExtensions, Queue, QueueCreateInfo};
use vulkano::instance::Instance;
use vulkano::pipeline::{ComputePipeline, Pipeline, PipelineBindPoint};
use vulkano::sync;
use vulkano::sync::GpuFuture;
use vulkano::{
buffer::{BufferUsage, CpuAccessibleBuffer},
command_buffer::{AutoCommandBufferBuilder, CommandBufferUsage},
descriptor_set::{PersistentDescriptorSet, WriteDescriptorSet},
device::{
physical::{PhysicalDevice, PhysicalDeviceType},
Device, DeviceCreateInfo, DeviceExtensions, Queue, QueueCreateInfo,
},
instance::Instance,
pipeline::{ComputePipeline, Pipeline, PipelineBindPoint},
sync::{self, GpuFuture},
};
fn main() {
let instance = Instance::new(Default::default()).unwrap();

View File

@ -9,15 +9,18 @@
// TODO: Give a paragraph about what specialization are and what problems they solve
use vulkano::buffer::{BufferUsage, CpuAccessibleBuffer};
use vulkano::command_buffer::{AutoCommandBufferBuilder, CommandBufferUsage};
use vulkano::descriptor_set::{PersistentDescriptorSet, WriteDescriptorSet};
use vulkano::device::physical::{PhysicalDevice, PhysicalDeviceType};
use vulkano::device::{Device, DeviceCreateInfo, DeviceExtensions, QueueCreateInfo};
use vulkano::instance::Instance;
use vulkano::pipeline::{ComputePipeline, Pipeline, PipelineBindPoint};
use vulkano::sync;
use vulkano::sync::GpuFuture;
use vulkano::{
buffer::{BufferUsage, CpuAccessibleBuffer},
command_buffer::{AutoCommandBufferBuilder, CommandBufferUsage},
descriptor_set::{PersistentDescriptorSet, WriteDescriptorSet},
device::{
physical::{PhysicalDevice, PhysicalDeviceType},
Device, DeviceCreateInfo, DeviceExtensions, QueueCreateInfo,
},
instance::Instance,
pipeline::{ComputePipeline, Pipeline, PipelineBindPoint},
sync::{self, GpuFuture},
};
fn main() {
let instance = Instance::new(Default::default()).unwrap();

View File

@ -9,34 +9,40 @@
use cgmath::{Matrix3, Matrix4, Point3, Rad, Vector3};
use examples::{Normal, Vertex, INDICES, NORMALS, VERTICES};
use std::sync::Arc;
use std::time::Instant;
use vulkano::buffer::cpu_pool::CpuBufferPool;
use vulkano::buffer::{BufferUsage, CpuAccessibleBuffer, TypedBufferAccess};
use vulkano::command_buffer::{AutoCommandBufferBuilder, CommandBufferUsage, SubpassContents};
use vulkano::descriptor_set::{PersistentDescriptorSet, WriteDescriptorSet};
use vulkano::device::physical::{PhysicalDevice, PhysicalDeviceType};
use vulkano::device::{Device, DeviceCreateInfo, DeviceExtensions, QueueCreateInfo};
use vulkano::format::Format;
use vulkano::image::attachment::AttachmentImage;
use vulkano::image::view::ImageView;
use vulkano::image::{ImageAccess, ImageUsage, SwapchainImage};
use vulkano::instance::{Instance, InstanceCreateInfo};
use vulkano::pipeline::graphics::depth_stencil::DepthStencilState;
use vulkano::pipeline::graphics::input_assembly::InputAssemblyState;
use vulkano::pipeline::graphics::vertex_input::BuffersDefinition;
use vulkano::pipeline::graphics::viewport::{Viewport, ViewportState};
use vulkano::pipeline::{GraphicsPipeline, Pipeline, PipelineBindPoint};
use vulkano::render_pass::{Framebuffer, FramebufferCreateInfo, RenderPass, Subpass};
use vulkano::shader::ShaderModule;
use vulkano::swapchain::{
self, AcquireError, Swapchain, SwapchainCreateInfo, SwapchainCreationError,
use std::{sync::Arc, time::Instant};
use vulkano::{
buffer::{BufferUsage, CpuAccessibleBuffer, CpuBufferPool, TypedBufferAccess},
command_buffer::{AutoCommandBufferBuilder, CommandBufferUsage, SubpassContents},
descriptor_set::{PersistentDescriptorSet, WriteDescriptorSet},
device::{
physical::{PhysicalDevice, PhysicalDeviceType},
Device, DeviceCreateInfo, DeviceExtensions, QueueCreateInfo,
},
format::Format,
image::{view::ImageView, AttachmentImage, ImageAccess, ImageUsage, SwapchainImage},
instance::{Instance, InstanceCreateInfo},
pipeline::{
graphics::{
depth_stencil::DepthStencilState,
input_assembly::InputAssemblyState,
vertex_input::BuffersDefinition,
viewport::{Viewport, ViewportState},
},
GraphicsPipeline, Pipeline, PipelineBindPoint,
},
render_pass::{Framebuffer, FramebufferCreateInfo, RenderPass, Subpass},
shader::ShaderModule,
swapchain::{
acquire_next_image, AcquireError, Swapchain, SwapchainCreateInfo, SwapchainCreationError,
},
sync::{self, FlushError, GpuFuture},
};
use vulkano::sync::{self, FlushError, GpuFuture};
use vulkano_win::VkSurfaceBuild;
use winit::event::{Event, WindowEvent};
use winit::event_loop::{ControlFlow, EventLoop};
use winit::window::{Window, WindowBuilder};
use winit::{
event::{Event, WindowEvent},
event_loop::{ControlFlow, EventLoop},
window::{Window, WindowBuilder},
};
fn main() {
// The start of this example is exactly the same as `triangle`. You should read the
@ -124,18 +130,13 @@ fn main() {
.unwrap()
};
let vertices = VERTICES.iter().cloned();
let vertex_buffer =
CpuAccessibleBuffer::from_iter(device.clone(), BufferUsage::all(), false, vertices)
CpuAccessibleBuffer::from_iter(device.clone(), BufferUsage::all(), false, VERTICES)
.unwrap();
let normals = NORMALS.iter().cloned();
let normals_buffer =
CpuAccessibleBuffer::from_iter(device.clone(), BufferUsage::all(), false, normals).unwrap();
let indices = INDICES.iter().cloned();
CpuAccessibleBuffer::from_iter(device.clone(), BufferUsage::all(), false, NORMALS).unwrap();
let index_buffer =
CpuAccessibleBuffer::from_iter(device.clone(), BufferUsage::all(), false, indices).unwrap();
CpuAccessibleBuffer::from_iter(device.clone(), BufferUsage::all(), false, INDICES).unwrap();
let uniform_buffer = CpuBufferPool::<vs::ty::Data>::new(device.clone(), BufferUsage::all());
@ -252,7 +253,7 @@ fn main() {
.unwrap();
let (image_num, suboptimal, acquire_future) =
match swapchain::acquire_next_image(swapchain.clone(), None) {
match acquire_next_image(swapchain.clone(), None) {
Ok(r) => r,
Err(AcquireError::OutOfDate) => {
recreate_swapchain = true;
@ -382,7 +383,12 @@ fn window_size_dependent_setup(
mod vs {
vulkano_shaders::shader! {
ty: "vertex",
path: "src/bin/teapot/vert.glsl"
path: "src/bin/teapot/vert.glsl",
types_meta: {
use bytemuck::{Pod, Zeroable};
#[derive(Clone, Copy, Zeroable, Pod)]
},
}
}

View File

@ -18,29 +18,40 @@
// * tessellation control shader and a tessellation evaluation shader
// * tessellation_shaders(..), patch_list(3) and polygon_mode_line() are called on the pipeline builder
use bytemuck::{Pod, Zeroable};
use std::sync::Arc;
use vulkano::buffer::{BufferUsage, CpuAccessibleBuffer, TypedBufferAccess};
use vulkano::command_buffer::{AutoCommandBufferBuilder, CommandBufferUsage, SubpassContents};
use vulkano::device::physical::{PhysicalDevice, PhysicalDeviceType};
use vulkano::device::{Device, DeviceCreateInfo, DeviceExtensions, Features, QueueCreateInfo};
use vulkano::image::view::ImageView;
use vulkano::image::{ImageAccess, ImageUsage, SwapchainImage};
use vulkano::instance::{Instance, InstanceCreateInfo};
use vulkano::pipeline::graphics::input_assembly::{InputAssemblyState, PrimitiveTopology};
use vulkano::pipeline::graphics::rasterization::{PolygonMode, RasterizationState};
use vulkano::pipeline::graphics::tessellation::TessellationState;
use vulkano::pipeline::graphics::vertex_input::BuffersDefinition;
use vulkano::pipeline::graphics::viewport::{Viewport, ViewportState};
use vulkano::pipeline::GraphicsPipeline;
use vulkano::render_pass::{Framebuffer, FramebufferCreateInfo, RenderPass, Subpass};
use vulkano::swapchain::{
self, AcquireError, Swapchain, SwapchainCreateInfo, SwapchainCreationError,
use vulkano::{
buffer::{BufferUsage, CpuAccessibleBuffer, TypedBufferAccess},
command_buffer::{AutoCommandBufferBuilder, CommandBufferUsage, SubpassContents},
device::{
physical::{PhysicalDevice, PhysicalDeviceType},
Device, DeviceCreateInfo, DeviceExtensions, Features, QueueCreateInfo,
},
image::{view::ImageView, ImageAccess, ImageUsage, SwapchainImage},
impl_vertex,
instance::{Instance, InstanceCreateInfo},
pipeline::{
graphics::{
input_assembly::{InputAssemblyState, PrimitiveTopology},
rasterization::{PolygonMode, RasterizationState},
tessellation::TessellationState,
vertex_input::BuffersDefinition,
viewport::{Viewport, ViewportState},
},
GraphicsPipeline,
},
render_pass::{Framebuffer, FramebufferCreateInfo, RenderPass, Subpass},
swapchain::{
acquire_next_image, AcquireError, Swapchain, SwapchainCreateInfo, SwapchainCreationError,
},
sync::{self, FlushError, GpuFuture},
};
use vulkano::sync::{self, FlushError, GpuFuture};
use vulkano_win::VkSurfaceBuild;
use winit::event::{Event, WindowEvent};
use winit::event_loop::{ControlFlow, EventLoop};
use winit::window::{Window, WindowBuilder};
use winit::{
event::{Event, WindowEvent},
event_loop::{ControlFlow, EventLoop},
window::{Window, WindowBuilder},
};
mod vs {
vulkano_shaders::shader! {
@ -226,18 +237,14 @@ fn main() {
.unwrap()
};
#[derive(Default, Debug, Clone)]
#[derive(Clone, Copy, Debug, Default, Zeroable, Pod)]
#[repr(C)]
struct Vertex {
position: [f32; 2],
}
vulkano::impl_vertex!(Vertex, position);
impl_vertex!(Vertex, position);
let vertex_buffer = CpuAccessibleBuffer::from_iter(
device.clone(),
BufferUsage::all(),
false,
[
let vertices = [
Vertex {
position: [-0.5, -0.25],
},
@ -265,10 +272,9 @@ fn main() {
Vertex {
position: [-0.5, 0.9],
},
]
.iter()
.cloned(),
)
];
let vertex_buffer =
CpuAccessibleBuffer::from_iter(device.clone(), BufferUsage::all(), false, vertices)
.unwrap();
let vs = vs::load(device.clone()).unwrap();
@ -360,7 +366,7 @@ fn main() {
}
let (image_num, suboptimal, acquire_future) =
match swapchain::acquire_next_image(swapchain.clone(), None) {
match acquire_next_image(swapchain.clone(), None) {
Ok(r) => r,
Err(AcquireError::OutOfDate) => {
recreate_swapchain = true;

View File

@ -7,37 +7,45 @@
// notice may not be copied, modified, or distributed except
// according to those terms.
use std::io::Cursor;
use std::sync::Arc;
use png;
use winit::event::{Event, WindowEvent};
use winit::event_loop::{ControlFlow, EventLoop};
use winit::window::{Window, WindowBuilder};
use vulkano::buffer::{BufferUsage, CpuAccessibleBuffer, TypedBufferAccess};
use vulkano::command_buffer::{AutoCommandBufferBuilder, CommandBufferUsage, SubpassContents};
use vulkano::descriptor_set::{PersistentDescriptorSet, WriteDescriptorSet};
use vulkano::device::physical::{PhysicalDevice, PhysicalDeviceType};
use vulkano::device::{Device, DeviceCreateInfo, DeviceExtensions, QueueCreateInfo};
use vulkano::format::Format;
use vulkano::image::ImageAccess;
use vulkano::image::{
view::ImageView, ImageDimensions, ImageUsage, ImmutableImage, MipmapsCount, SwapchainImage,
use bytemuck::{Pod, Zeroable};
use std::{io::Cursor, sync::Arc};
use vulkano::{
buffer::{BufferUsage, CpuAccessibleBuffer, TypedBufferAccess},
command_buffer::{AutoCommandBufferBuilder, CommandBufferUsage, SubpassContents},
descriptor_set::{PersistentDescriptorSet, WriteDescriptorSet},
device::{
physical::{PhysicalDevice, PhysicalDeviceType},
Device, DeviceCreateInfo, DeviceExtensions, QueueCreateInfo,
},
format::Format,
image::{
view::ImageView, ImageAccess, ImageDimensions, ImageUsage, ImmutableImage, MipmapsCount,
SwapchainImage,
},
impl_vertex,
instance::{Instance, InstanceCreateInfo},
pipeline::{
graphics::{
color_blend::ColorBlendState,
input_assembly::{InputAssemblyState, PrimitiveTopology},
vertex_input::BuffersDefinition,
viewport::{Viewport, ViewportState},
},
GraphicsPipeline, Pipeline, PipelineBindPoint,
},
render_pass::{Framebuffer, FramebufferCreateInfo, RenderPass, Subpass},
sampler::{Sampler, SamplerCreateInfo},
swapchain::{
acquire_next_image, AcquireError, Swapchain, SwapchainCreateInfo, SwapchainCreationError,
},
sync::{self, FlushError, GpuFuture},
};
use vulkano::instance::{Instance, InstanceCreateInfo};
use vulkano::pipeline::graphics::color_blend::ColorBlendState;
use vulkano::pipeline::graphics::input_assembly::{InputAssemblyState, PrimitiveTopology};
use vulkano::pipeline::graphics::vertex_input::BuffersDefinition;
use vulkano::pipeline::graphics::viewport::{Viewport, ViewportState};
use vulkano::pipeline::{GraphicsPipeline, Pipeline, PipelineBindPoint};
use vulkano::render_pass::{Framebuffer, FramebufferCreateInfo, RenderPass, Subpass};
use vulkano::sampler::{Sampler, SamplerCreateInfo};
use vulkano::swapchain::{
self, AcquireError, Swapchain, SwapchainCreateInfo, SwapchainCreationError,
};
use vulkano::sync::{self, FlushError, GpuFuture};
use vulkano_win::VkSurfaceBuild;
use winit::{
event::{Event, WindowEvent},
event_loop::{ControlFlow, EventLoop},
window::{Window, WindowBuilder},
};
fn main() {
// This example is about this:
@ -127,17 +135,13 @@ fn main() {
};
#[repr(C)]
#[derive(Default, Debug, Clone)]
#[derive(Clone, Copy, Debug, Default, Zeroable, Pod)]
struct Vertex {
position: [f32; 2],
}
vulkano::impl_vertex!(Vertex, position);
impl_vertex!(Vertex, position);
let vertex_buffer = CpuAccessibleBuffer::<[Vertex]>::from_iter(
device.clone(),
BufferUsage::all(),
false,
[
let vertices = [
Vertex {
position: [-0.2, -0.5],
},
@ -150,9 +154,12 @@ fn main() {
Vertex {
position: [0.5, 0.2],
},
]
.iter()
.cloned(),
];
let vertex_buffer = CpuAccessibleBuffer::<[Vertex]>::from_iter(
device.clone(),
BufferUsage::all(),
false,
vertices,
)
.unwrap();
@ -199,7 +206,7 @@ fn main() {
array_layers: 3,
}; // TODO replace with your actual image array dimensions
let (image, future) = ImmutableImage::from_iter(
image_array_data.iter().cloned(),
image_array_data,
dimensions,
MipmapsCount::Log2,
Format::R8G8B8A8_SRGB,
@ -277,7 +284,7 @@ fn main() {
}
let (image_num, suboptimal, acquire_future) =
match swapchain::acquire_next_image(swapchain.clone(), None) {
match acquire_next_image(swapchain.clone(), None) {
Ok(r) => r,
Err(AcquireError::OutOfDate) => {
recreate_swapchain = true;

View File

@ -16,27 +16,38 @@
// and that you want to learn Vulkan. This means that for example it won't go into details about
// what a vertex or a shader is.
use bytemuck::{Pod, Zeroable};
use std::sync::Arc;
use vulkano::buffer::{BufferUsage, CpuAccessibleBuffer, TypedBufferAccess};
use vulkano::command_buffer::{AutoCommandBufferBuilder, CommandBufferUsage, SubpassContents};
use vulkano::device::physical::{PhysicalDevice, PhysicalDeviceType};
use vulkano::device::{Device, DeviceCreateInfo, DeviceExtensions, QueueCreateInfo};
use vulkano::image::view::ImageView;
use vulkano::image::{ImageAccess, ImageUsage, SwapchainImage};
use vulkano::instance::{Instance, InstanceCreateInfo};
use vulkano::pipeline::graphics::input_assembly::InputAssemblyState;
use vulkano::pipeline::graphics::vertex_input::BuffersDefinition;
use vulkano::pipeline::graphics::viewport::{Viewport, ViewportState};
use vulkano::pipeline::GraphicsPipeline;
use vulkano::render_pass::{Framebuffer, FramebufferCreateInfo, RenderPass, Subpass};
use vulkano::swapchain::{
self, AcquireError, Swapchain, SwapchainCreateInfo, SwapchainCreationError,
use vulkano::{
buffer::{BufferUsage, CpuAccessibleBuffer, TypedBufferAccess},
command_buffer::{AutoCommandBufferBuilder, CommandBufferUsage, SubpassContents},
device::{
physical::{PhysicalDevice, PhysicalDeviceType},
Device, DeviceCreateInfo, DeviceExtensions, QueueCreateInfo,
},
image::{view::ImageView, ImageAccess, ImageUsage, SwapchainImage},
impl_vertex,
instance::{Instance, InstanceCreateInfo},
pipeline::{
graphics::{
input_assembly::InputAssemblyState,
vertex_input::BuffersDefinition,
viewport::{Viewport, ViewportState},
},
GraphicsPipeline,
},
render_pass::{Framebuffer, FramebufferCreateInfo, RenderPass, Subpass},
swapchain::{
acquire_next_image, AcquireError, Swapchain, SwapchainCreateInfo, SwapchainCreationError,
},
sync::{self, FlushError, GpuFuture},
};
use vulkano::sync::{self, FlushError, GpuFuture};
use vulkano_win::VkSurfaceBuild;
use winit::event::{Event, WindowEvent};
use winit::event_loop::{ControlFlow, EventLoop};
use winit::window::{Window, WindowBuilder};
use winit::{
event::{Event, WindowEvent},
event_loop::{ControlFlow, EventLoop},
window::{Window, WindowBuilder},
};
fn main() {
// The first step of any Vulkan program is to create an instance.
@ -233,17 +244,13 @@ fn main() {
// We use #[repr(C)] here to force rustc to not do anything funky with our data, although for this
// particular example, it doesn't actually change the in-memory representation.
#[repr(C)]
#[derive(Default, Debug, Clone)]
#[derive(Clone, Copy, Debug, Default, Zeroable, Pod)]
struct Vertex {
position: [f32; 2],
}
vulkano::impl_vertex!(Vertex, position);
impl_vertex!(Vertex, position);
let vertex_buffer = CpuAccessibleBuffer::from_iter(
device.clone(),
BufferUsage::all(),
false,
[
let vertices = [
Vertex {
position: [-0.5, -0.25],
},
@ -253,17 +260,16 @@ fn main() {
Vertex {
position: [0.25, -0.1],
},
]
.iter()
.cloned(),
)
];
let vertex_buffer =
CpuAccessibleBuffer::from_iter(device.clone(), BufferUsage::all(), false, vertices)
.unwrap();
// The next step is to create the shaders.
//
// The raw shader creation API provided by the vulkano library is unsafe, for various reasons.
//
// An overview of what the `vulkano_shaders::shader!` macro generates can be found in the
// An overview of what the `shader!` macro generates can be found in the
// `vulkano-shaders` crate docs. You can view them at https://docs.rs/vulkano-shaders/
//
// TODO: explain this in details
@ -450,7 +456,7 @@ fn main() {
// This function can block if no image is available. The parameter is an optional timeout
// after which the function call will return an error.
let (image_num, suboptimal, acquire_future) =
match swapchain::acquire_next_image(swapchain.clone(), None) {
match acquire_next_image(swapchain.clone(), None) {
Ok(r) => r,
Err(AcquireError::OutOfDate) => {
recreate_swapchain = true;

File diff suppressed because it is too large Load Diff

View File

@ -17,6 +17,7 @@ build = "build.rs"
# When updating Ash, also update vk.xml to the same Vulkan patch version that Ash uses.
# All versions of vk.xml can be found at https://github.com/KhronosGroup/Vulkan-Headers/commits/main/registry/vk.xml.
ash = "0.36"
bytemuck = { version = "1.7", features = ["derive", "extern_crate_std", "min_const_generics"] }
crossbeam-queue = "0.3"
half = "1.8"
lazy_static = "1.4"

View File

@ -16,49 +16,36 @@
//! You can read the buffer multiple times simultaneously. Trying to read and write simultaneously,
//! or write and write simultaneously will block.
use crate::buffer::sys::BufferCreationError;
use crate::buffer::sys::UnsafeBuffer;
use crate::buffer::sys::UnsafeBufferCreateInfo;
use crate::buffer::traits::BufferAccess;
use crate::buffer::traits::BufferAccessObject;
use crate::buffer::traits::BufferInner;
use crate::buffer::traits::TypedBufferAccess;
use crate::buffer::BufferUsage;
use crate::device::physical::QueueFamily;
use crate::device::Device;
use crate::device::DeviceOwned;
use crate::device::Queue;
use crate::memory::pool::AllocFromRequirementsFilter;
use crate::memory::pool::AllocLayout;
use crate::memory::pool::MappingRequirement;
use crate::memory::pool::MemoryPool;
use crate::memory::pool::MemoryPoolAlloc;
use crate::memory::pool::PotentialDedicatedAllocation;
use crate::memory::pool::StdMemoryPoolAlloc;
use crate::memory::Content;
use crate::memory::CpuAccess as MemCpuAccess;
use crate::memory::DedicatedAllocation;
use crate::memory::DeviceMemoryAllocationError;
use crate::sync::AccessError;
use crate::sync::Sharing;
use crate::DeviceSize;
use parking_lot::RwLock;
use parking_lot::RwLockReadGuard;
use parking_lot::RwLockWriteGuard;
use super::{
sys::UnsafeBuffer, BufferAccess, BufferAccessObject, BufferContents, BufferInner, BufferUsage,
};
use crate::{
buffer::{sys::UnsafeBufferCreateInfo, BufferCreationError, TypedBufferAccess},
device::{physical::QueueFamily, Device, DeviceOwned, Queue},
memory::{
pool::{
AllocFromRequirementsFilter, AllocLayout, MappingRequirement, MemoryPoolAlloc,
PotentialDedicatedAllocation, StdMemoryPoolAlloc,
},
DedicatedAllocation, DeviceMemoryAllocationError, MappedDeviceMemory, MemoryPool,
},
sync::{AccessError, Sharing},
DeviceSize,
};
use parking_lot::{RwLock, RwLockReadGuard, RwLockWriteGuard};
use smallvec::SmallVec;
use std::error;
use std::fmt;
use std::hash::Hash;
use std::hash::Hasher;
use std::iter;
use std::marker::PhantomData;
use std::mem;
use std::ops::Deref;
use std::ops::DerefMut;
use std::ptr;
use std::sync::atomic::AtomicUsize;
use std::sync::atomic::Ordering;
use std::sync::Arc;
use std::{
error, fmt,
hash::{Hash, Hasher},
marker::PhantomData,
mem::size_of,
ops::{Deref, DerefMut, Range},
ptr,
sync::{
atomic::{AtomicUsize, Ordering},
Arc,
},
};
/// Buffer whose content is accessible by the CPU.
///
@ -67,7 +54,10 @@ use std::sync::Arc;
/// memory caches GPU data on the CPU side. This can be more performant in cases where
/// the cpu needs to read data coming off the GPU.
#[derive(Debug)]
pub struct CpuAccessibleBuffer<T: ?Sized, A = PotentialDedicatedAllocation<StdMemoryPoolAlloc>> {
pub struct CpuAccessibleBuffer<T, A = PotentialDedicatedAllocation<StdMemoryPoolAlloc>>
where
T: BufferContents + ?Sized,
{
// Inner content.
inner: UnsafeBuffer,
@ -99,7 +89,10 @@ enum CurrentGpuAccess {
},
}
impl<T> CpuAccessibleBuffer<T> {
impl<T> CpuAccessibleBuffer<T>
where
T: BufferContents,
{
/// Builds a new buffer with some data in it. Only allowed for sized data.
///
/// # Panics
@ -110,17 +103,14 @@ impl<T> CpuAccessibleBuffer<T> {
usage: BufferUsage,
host_cached: bool,
data: T,
) -> Result<Arc<CpuAccessibleBuffer<T>>, DeviceMemoryAllocationError>
where
T: Content + Copy + 'static,
{
) -> Result<Arc<CpuAccessibleBuffer<T>>, DeviceMemoryAllocationError> {
unsafe {
let uninitialized = CpuAccessibleBuffer::raw(
device,
mem::size_of::<T>() as DeviceSize,
size_of::<T>() as DeviceSize,
usage,
host_cached,
iter::empty(),
[],
)?;
// Note that we are in panic-unsafety land here. However a panic should never ever
@ -147,17 +137,14 @@ impl<T> CpuAccessibleBuffer<T> {
usage: BufferUsage,
host_cached: bool,
) -> Result<Arc<CpuAccessibleBuffer<T>>, DeviceMemoryAllocationError> {
CpuAccessibleBuffer::raw(
device,
mem::size_of::<T>() as DeviceSize,
usage,
host_cached,
iter::empty(),
)
CpuAccessibleBuffer::raw(device, size_of::<T>() as DeviceSize, usage, host_cached, [])
}
}
impl<T> CpuAccessibleBuffer<[T]> {
impl<T> CpuAccessibleBuffer<[T]>
where
[T]: BufferContents,
{
/// Builds a new buffer that contains an array `T`. The initial data comes from an iterator
/// that produces that list of Ts.
///
@ -174,7 +161,6 @@ impl<T> CpuAccessibleBuffer<[T]> {
where
I: IntoIterator<Item = T>,
I::IntoIter: ExactSizeIterator,
T: Content + 'static,
{
let data = data.into_iter();
@ -217,15 +203,18 @@ impl<T> CpuAccessibleBuffer<[T]> {
) -> Result<Arc<CpuAccessibleBuffer<[T]>>, DeviceMemoryAllocationError> {
CpuAccessibleBuffer::raw(
device,
len * mem::size_of::<T>() as DeviceSize,
len * size_of::<T>() as DeviceSize,
usage,
host_cached,
iter::empty(),
[],
)
}
}
impl<T: ?Sized> CpuAccessibleBuffer<T> {
impl<T> CpuAccessibleBuffer<T>
where
T: BufferContents + ?Sized,
{
/// Builds a new buffer without checking the size.
///
/// # Safety
@ -310,7 +299,10 @@ impl<T: ?Sized> CpuAccessibleBuffer<T> {
}
}
impl<T: ?Sized, A> CpuAccessibleBuffer<T, A> {
impl<T, A> CpuAccessibleBuffer<T, A>
where
T: BufferContents + ?Sized,
{
/// Returns the queue families this buffer can be used on.
// TODO: use a custom iterator
#[inline]
@ -327,9 +319,9 @@ impl<T: ?Sized, A> CpuAccessibleBuffer<T, A> {
}
}
impl<T: ?Sized, A> CpuAccessibleBuffer<T, A>
impl<T, A> CpuAccessibleBuffer<T, A>
where
T: Content + 'static,
T: BufferContents + ?Sized,
A: MemoryPoolAlloc,
{
/// Locks the buffer in order to read its content from the CPU.
@ -355,12 +347,24 @@ where
return Err(ReadLockError::GpuWriteLocked);
}
let mapped_memory = self.memory.mapped_memory().unwrap();
let offset = self.memory.offset();
let range = offset..offset + self.inner.size();
let bytes = unsafe {
// If there are other read locks being held at this point, they also called
// `invalidate_range` when locking. The GPU can't write data while the CPU holds a read
// lock, so there will no new data and this call will do nothing.
// TODO: probably still more efficient to call it only if we're the first to acquire a
// read lock, but the number of CPU locks isn't currently tracked anywhere.
mapped_memory.invalidate_range(range.clone()).unwrap();
mapped_memory.read(range.clone()).unwrap()
};
Ok(ReadLock {
inner: unsafe { self.memory.mapped_memory().unwrap().read_write(range) },
lock: lock,
data: T::from_bytes(bytes).unwrap(),
range,
lock,
})
}
@ -388,19 +392,27 @@ where
_ => return Err(WriteLockError::GpuLocked),
}
let mapped_memory = self.memory.mapped_memory().unwrap();
let offset = self.memory.offset();
let range = offset..offset + self.inner.size();
let bytes = unsafe {
mapped_memory.invalidate_range(range.clone()).unwrap();
mapped_memory.write(range.clone()).unwrap()
};
Ok(WriteLock {
inner: unsafe { self.memory.mapped_memory().unwrap().read_write(range) },
lock: lock,
data: T::from_bytes_mut(bytes).unwrap(),
mapped_memory,
range,
lock,
})
}
}
unsafe impl<T: ?Sized, A> BufferAccess for CpuAccessibleBuffer<T, A>
unsafe impl<T, A> BufferAccess for CpuAccessibleBuffer<T, A>
where
T: Send + Sync + 'static,
T: BufferContents + ?Sized,
A: Send + Sync,
{
#[inline]
@ -515,9 +527,9 @@ where
}
}
impl<T: ?Sized, A> BufferAccessObject for Arc<CpuAccessibleBuffer<T, A>>
impl<T, A> BufferAccessObject for Arc<CpuAccessibleBuffer<T, A>>
where
T: Send + Sync + 'static,
T: BufferContents + ?Sized,
A: Send + Sync + 'static,
{
#[inline]
@ -526,24 +538,27 @@ where
}
}
unsafe impl<T: ?Sized, A> TypedBufferAccess for CpuAccessibleBuffer<T, A>
unsafe impl<T, A> TypedBufferAccess for CpuAccessibleBuffer<T, A>
where
T: Send + Sync + 'static,
T: BufferContents + ?Sized,
A: Send + Sync,
{
type Content = T;
}
unsafe impl<T: ?Sized, A> DeviceOwned for CpuAccessibleBuffer<T, A> {
unsafe impl<T, A> DeviceOwned for CpuAccessibleBuffer<T, A>
where
T: BufferContents + ?Sized,
{
#[inline]
fn device(&self) -> &Arc<Device> {
self.inner.device()
}
}
impl<T: ?Sized, A> PartialEq for CpuAccessibleBuffer<T, A>
impl<T, A> PartialEq for CpuAccessibleBuffer<T, A>
where
T: Send + Sync + 'static,
T: BufferContents + ?Sized,
A: Send + Sync,
{
#[inline]
@ -552,16 +567,16 @@ where
}
}
impl<T: ?Sized, A> Eq for CpuAccessibleBuffer<T, A>
impl<T, A> Eq for CpuAccessibleBuffer<T, A>
where
T: Send + Sync + 'static,
T: BufferContents + ?Sized,
A: Send + Sync,
{
}
impl<T: ?Sized, A> Hash for CpuAccessibleBuffer<T, A>
impl<T, A> Hash for CpuAccessibleBuffer<T, A>
where
T: Send + Sync + 'static,
T: BufferContents + ?Sized,
A: Send + Sync,
{
#[inline]
@ -575,31 +590,74 @@ where
///
/// Note that this object holds a rwlock read guard on the chunk. If another thread tries to access
/// this buffer's content or tries to submit a GPU command that uses this buffer, it will block.
pub struct ReadLock<'a, T: ?Sized + 'a> {
inner: MemCpuAccess<'a, T>,
#[derive(Debug)]
pub struct ReadLock<'a, T>
where
T: BufferContents + ?Sized + 'a,
{
data: &'a T,
range: Range<DeviceSize>,
lock: RwLockReadGuard<'a, CurrentGpuAccess>,
}
impl<'a, T: ?Sized + 'a> ReadLock<'a, T> {
/// Makes a new `ReadLock` to access a sub-part of the current `ReadLock`.
#[inline]
pub fn map<U: ?Sized + 'a, F>(self, f: F) -> ReadLock<'a, U>
where
F: FnOnce(&mut T) -> &mut U,
{
ReadLock {
inner: self.inner.map(|ptr| unsafe { f(&mut *ptr) as *mut _ }),
lock: self.lock,
}
}
}
impl<'a, T: ?Sized + 'a> Deref for ReadLock<'a, T> {
impl<'a, T> Deref for ReadLock<'a, T>
where
T: BufferContents + ?Sized + 'a,
{
type Target = T;
#[inline]
fn deref(&self) -> &T {
self.inner.deref()
self.data
}
}
/// Object that can be used to read or write the content of a `CpuAccessibleBuffer`.
///
/// Note that this object holds a rwlock write guard on the chunk. If another thread tries to access
/// this buffer's content or tries to submit a GPU command that uses this buffer, it will block.
#[derive(Debug)]
pub struct WriteLock<'a, T>
where
T: BufferContents + ?Sized + 'a,
{
data: &'a mut T,
mapped_memory: &'a MappedDeviceMemory,
range: Range<DeviceSize>,
lock: RwLockWriteGuard<'a, CurrentGpuAccess>,
}
impl<'a, T> Drop for WriteLock<'a, T>
where
T: BufferContents + ?Sized + 'a,
{
#[inline]
fn drop(&mut self) {
unsafe {
self.mapped_memory.flush_range(self.range.clone()).unwrap();
}
}
}
impl<'a, T> Deref for WriteLock<'a, T>
where
T: BufferContents + ?Sized + 'a,
{
type Target = T;
#[inline]
fn deref(&self) -> &T {
self.data
}
}
impl<'a, T> DerefMut for WriteLock<'a, T>
where
T: BufferContents + ?Sized + 'a,
{
#[inline]
fn deref_mut(&mut self) -> &mut T {
self.data
}
}
@ -632,45 +690,6 @@ impl fmt::Display for ReadLockError {
}
}
/// Object that can be used to read or write the content of a `CpuAccessibleBuffer`.
///
/// Note that this object holds a rwlock write guard on the chunk. If another thread tries to access
/// this buffer's content or tries to submit a GPU command that uses this buffer, it will block.
pub struct WriteLock<'a, T: ?Sized + 'a> {
inner: MemCpuAccess<'a, T>,
lock: RwLockWriteGuard<'a, CurrentGpuAccess>,
}
impl<'a, T: ?Sized + 'a> WriteLock<'a, T> {
/// Makes a new `WriteLock` to access a sub-part of the current `WriteLock`.
#[inline]
pub fn map<U: ?Sized + 'a, F>(self, f: F) -> WriteLock<'a, U>
where
F: FnOnce(&mut T) -> &mut U,
{
WriteLock {
inner: self.inner.map(|ptr| unsafe { f(&mut *ptr) as *mut _ }),
lock: self.lock,
}
}
}
impl<'a, T: ?Sized + 'a> Deref for WriteLock<'a, T> {
type Target = T;
#[inline]
fn deref(&self) -> &T {
self.inner.deref()
}
}
impl<'a, T: ?Sized + 'a> DerefMut for WriteLock<'a, T> {
#[inline]
fn deref_mut(&mut self) -> &mut T {
self.inner.deref_mut()
}
}
/// Error when attempting to CPU-write a buffer.
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum WriteLockError {
@ -709,7 +728,7 @@ mod tests {
assert_should_panic!({
CpuAccessibleBuffer::from_data(device.clone(), BufferUsage::all(), false, EMPTY)
.unwrap();
CpuAccessibleBuffer::from_iter(device, BufferUsage::all(), false, EMPTY.iter())
CpuAccessibleBuffer::from_iter(device, BufferUsage::all(), false, EMPTY.into_iter())
.unwrap();
});
}

View File

@ -7,41 +7,33 @@
// notice may not be copied, modified, or distributed except
// according to those terms.
use crate::buffer::sys::BufferCreationError;
use crate::buffer::sys::UnsafeBuffer;
use crate::buffer::sys::UnsafeBufferCreateInfo;
use crate::buffer::traits::BufferAccess;
use crate::buffer::traits::BufferAccessObject;
use crate::buffer::traits::BufferInner;
use crate::buffer::traits::TypedBufferAccess;
use crate::buffer::BufferUsage;
use crate::device::Device;
use crate::device::DeviceOwned;
use crate::device::Queue;
use crate::memory::pool::AllocFromRequirementsFilter;
use crate::memory::pool::AllocLayout;
use crate::memory::pool::MappingRequirement;
use crate::memory::pool::MemoryPool;
use crate::memory::pool::MemoryPoolAlloc;
use crate::memory::pool::PotentialDedicatedAllocation;
use crate::memory::pool::StdMemoryPool;
use crate::memory::DedicatedAllocation;
use crate::memory::DeviceMemoryAllocationError;
use crate::sync::AccessError;
use crate::DeviceSize;
use crate::OomError;
use std::cmp;
use std::hash::Hash;
use std::hash::Hasher;
use std::iter;
use std::marker::PhantomData;
use std::mem;
use std::ptr;
use std::sync::atomic::AtomicU64;
use std::sync::atomic::Ordering;
use std::sync::Arc;
use std::sync::Mutex;
use std::sync::MutexGuard;
use super::{
sys::{UnsafeBuffer, UnsafeBufferCreateInfo},
BufferAccess, BufferAccessObject, BufferContents, BufferCreationError, BufferInner,
BufferUsage, TypedBufferAccess,
};
use crate::{
device::{Device, DeviceOwned, Queue},
memory::{
pool::{
AllocFromRequirementsFilter, AllocLayout, MappingRequirement, MemoryPoolAlloc,
PotentialDedicatedAllocation, StdMemoryPool,
},
DedicatedAllocation, DeviceMemoryAllocationError, MemoryPool,
},
sync::AccessError,
DeviceSize, OomError,
};
use std::{
hash::{Hash, Hasher},
marker::PhantomData,
mem::size_of,
ptr,
sync::{
atomic::{AtomicU64, Ordering},
Arc, Mutex, MutexGuard,
},
};
// TODO: Add `CpuBufferPoolSubbuffer::read` to read the content of a subbuffer.
// But that's hard to do because we must prevent `increase_gpu_lock` from working while a
@ -102,6 +94,7 @@ use std::sync::MutexGuard;
///
pub struct CpuBufferPool<T, A = Arc<StdMemoryPool>>
where
[T]: BufferContents,
A: MemoryPool,
{
// The device of the pool.
@ -121,6 +114,7 @@ where
}
// One buffer of the pool.
#[derive(Debug)]
struct ActualBuffer<A>
where
A: MemoryPool,
@ -163,6 +157,7 @@ struct ActualBufferChunk {
/// When this object is destroyed, the subbuffer is automatically reclaimed by the pool.
pub struct CpuBufferPoolChunk<T, A>
where
[T]: BufferContents,
A: MemoryPool,
{
buffer: Arc<ActualBuffer<A>>,
@ -187,13 +182,17 @@ where
/// When this object is destroyed, the subbuffer is automatically reclaimed by the pool.
pub struct CpuBufferPoolSubbuffer<T, A>
where
[T]: BufferContents,
A: MemoryPool,
{
// This struct is just a wrapper around `CpuBufferPoolChunk`.
chunk: CpuBufferPoolChunk<T, A>,
}
impl<T> CpuBufferPool<T> {
impl<T> CpuBufferPool<T>
where
[T]: BufferContents,
{
/// Builds a `CpuBufferPool`.
///
/// # Panics
@ -201,7 +200,7 @@ impl<T> CpuBufferPool<T> {
/// - Panics if `T` has zero size.
#[inline]
pub fn new(device: Arc<Device>, usage: BufferUsage) -> CpuBufferPool<T> {
assert!(mem::size_of::<T>() > 0);
assert!(size_of::<T>() > 0);
let pool = Device::standard_pool(&device);
CpuBufferPool {
@ -281,6 +280,7 @@ impl<T> CpuBufferPool<T> {
impl<T, A> CpuBufferPool<T, A>
where
[T]: BufferContents,
A: MemoryPool,
{
/// Returns the current capacity of the pool, in number of elements.
@ -326,7 +326,7 @@ where
data: T,
) -> Result<Arc<CpuBufferPoolSubbuffer<T, A>>, DeviceMemoryAllocationError> {
Ok(Arc::new(CpuBufferPoolSubbuffer {
chunk: self.chunk_impl(iter::once(data))?,
chunk: self.chunk_impl([data].into_iter())?,
}))
}
@ -386,7 +386,7 @@ where
#[inline]
pub fn try_next(&self, data: T) -> Option<Arc<CpuBufferPoolSubbuffer<T, A>>> {
let mut mutex = self.current_buffer.lock().unwrap();
self.try_next_impl(&mut mutex, iter::once(data))
self.try_next_impl(&mut mutex, [data])
.map(|c| Arc::new(CpuBufferPoolSubbuffer { chunk: c }))
.ok()
}
@ -399,7 +399,7 @@ where
cur_buf_mutex: &mut MutexGuard<Option<Arc<ActualBuffer<A>>>>,
capacity: DeviceSize,
) -> Result<(), DeviceMemoryAllocationError> {
let size = match (mem::size_of::<T>() as DeviceSize).checked_mul(capacity) {
let size = match (size_of::<T>() as DeviceSize).checked_mul(capacity) {
Some(s) => s,
None => {
return Err(DeviceMemoryAllocationError::OomError(
@ -507,32 +507,31 @@ where
let idx = current_buffer.next_index.load(Ordering::SeqCst);
// Find the required alignment in bytes.
let align_bytes = cmp::max(
if self.usage.uniform_buffer {
let align_uniform = if self.usage.uniform_buffer {
self.device()
.physical_device()
.properties()
.min_uniform_buffer_offset_alignment
} else {
1
},
if self.usage.storage_buffer {
};
let align_storage = if self.usage.storage_buffer {
self.device()
.physical_device()
.properties()
.min_storage_buffer_offset_alignment
} else {
1
},
);
};
let align_bytes = align_uniform.max(align_storage);
let tentative_align_offset = (align_bytes
- ((idx * mem::size_of::<T>() as DeviceSize) % align_bytes))
- ((idx * size_of::<T>() as DeviceSize) % align_bytes))
% align_bytes;
let additional_len = if tentative_align_offset == 0 {
0
} else {
1 + (tentative_align_offset - 1) / mem::size_of::<T>() as DeviceSize
1 + (tentative_align_offset - 1) / size_of::<T>() as DeviceSize
};
(idx, requested_len + additional_len, tentative_align_offset)
@ -562,21 +561,21 @@ where
// Write `data` in the memory.
unsafe {
let mem_off = current_buffer.memory.offset();
let range_start = index * mem::size_of::<T>() as DeviceSize + align_offset + mem_off;
let range_end = (index + requested_len) * mem::size_of::<T>() as DeviceSize
+ align_offset
+ mem_off;
let mut mapping = current_buffer
.memory
.mapped_memory()
.unwrap()
.read_write::<[T]>(range_start..range_end);
let range = (index * size_of::<T>() as DeviceSize + align_offset + mem_off)
..((index + requested_len) * size_of::<T>() as DeviceSize + align_offset + mem_off);
let mapped_memory = current_buffer.memory.mapped_memory().unwrap();
let bytes = mapped_memory.write(range.clone()).unwrap();
let mapping = <[T]>::from_bytes_mut(bytes).unwrap();
let mut written = 0;
for (o, i) in mapping.iter_mut().zip(data) {
ptr::write(o, i);
written += 1;
}
mapped_memory.flush_range(range).unwrap();
assert_eq!(
written, requested_len,
"Iterator passed to CpuBufferPool::chunk has a mismatch between reported \
@ -609,6 +608,7 @@ where
// Can't automatically derive `Clone`, otherwise the compiler adds a `T: Clone` requirement.
impl<T, A> Clone for CpuBufferPool<T, A>
where
[T]: BufferContents,
A: MemoryPool + Clone,
{
fn clone(&self) -> Self {
@ -626,6 +626,7 @@ where
unsafe impl<T, A> DeviceOwned for CpuBufferPool<T, A>
where
[T]: BufferContents,
A: MemoryPool,
{
#[inline]
@ -636,6 +637,7 @@ where
impl<T, A> Clone for CpuBufferPoolChunk<T, A>
where
[T]: BufferContents,
A: MemoryPool,
{
fn clone(&self) -> CpuBufferPoolChunk<T, A> {
@ -664,19 +666,20 @@ where
unsafe impl<T, A> BufferAccess for CpuBufferPoolChunk<T, A>
where
T: Send + Sync,
[T]: BufferContents,
A: MemoryPool,
{
#[inline]
fn inner(&self) -> BufferInner {
BufferInner {
buffer: &self.buffer.inner,
offset: self.index * mem::size_of::<T>() as DeviceSize + self.align_offset,
offset: self.index * size_of::<T>() as DeviceSize + self.align_offset,
}
}
#[inline]
fn size(&self) -> DeviceSize {
self.requested_len * mem::size_of::<T>() as DeviceSize
self.requested_len * size_of::<T>() as DeviceSize
}
#[inline]
@ -750,7 +753,8 @@ where
impl<T, A> BufferAccessObject for Arc<CpuBufferPoolChunk<T, A>>
where
T: Send + Sync + 'static,
T: Send + Sync,
[T]: BufferContents,
A: MemoryPool + 'static,
{
#[inline]
@ -761,6 +765,7 @@ where
impl<T, A> Drop for CpuBufferPoolChunk<T, A>
where
[T]: BufferContents,
A: MemoryPool,
{
fn drop(&mut self) {
@ -787,6 +792,7 @@ where
unsafe impl<T, A> TypedBufferAccess for CpuBufferPoolChunk<T, A>
where
T: Send + Sync,
[T]: BufferContents,
A: MemoryPool,
{
type Content = [T];
@ -794,6 +800,7 @@ where
unsafe impl<T, A> DeviceOwned for CpuBufferPoolChunk<T, A>
where
[T]: BufferContents,
A: MemoryPool,
{
#[inline]
@ -805,6 +812,7 @@ where
impl<T, A> PartialEq for CpuBufferPoolChunk<T, A>
where
T: Send + Sync,
[T]: BufferContents,
A: MemoryPool,
{
#[inline]
@ -816,6 +824,7 @@ where
impl<T, A> Eq for CpuBufferPoolChunk<T, A>
where
T: Send + Sync,
[T]: BufferContents,
A: MemoryPool,
{
}
@ -823,6 +832,7 @@ where
impl<T, A> Hash for CpuBufferPoolChunk<T, A>
where
T: Send + Sync,
[T]: BufferContents,
A: MemoryPool,
{
#[inline]
@ -834,6 +844,7 @@ where
impl<T, A> Clone for CpuBufferPoolSubbuffer<T, A>
where
[T]: BufferContents,
A: MemoryPool,
{
fn clone(&self) -> CpuBufferPoolSubbuffer<T, A> {
@ -846,6 +857,7 @@ where
unsafe impl<T, A> BufferAccess for CpuBufferPoolSubbuffer<T, A>
where
T: Send + Sync,
[T]: BufferContents,
A: MemoryPool,
{
#[inline]
@ -881,7 +893,8 @@ where
impl<T, A> BufferAccessObject for Arc<CpuBufferPoolSubbuffer<T, A>>
where
T: Send + Sync + 'static,
T: Send + Sync,
[T]: BufferContents,
A: MemoryPool + 'static,
{
#[inline]
@ -892,7 +905,8 @@ where
unsafe impl<T, A> TypedBufferAccess for CpuBufferPoolSubbuffer<T, A>
where
T: Send + Sync,
T: BufferContents,
[T]: BufferContents,
A: MemoryPool,
{
type Content = T;
@ -900,6 +914,7 @@ where
unsafe impl<T, A> DeviceOwned for CpuBufferPoolSubbuffer<T, A>
where
[T]: BufferContents,
A: MemoryPool,
{
#[inline]
@ -911,6 +926,7 @@ where
impl<T, A> PartialEq for CpuBufferPoolSubbuffer<T, A>
where
T: Send + Sync,
[T]: BufferContents,
A: MemoryPool,
{
#[inline]
@ -922,6 +938,7 @@ where
impl<T, A> Eq for CpuBufferPoolSubbuffer<T, A>
where
T: Send + Sync,
[T]: BufferContents,
A: MemoryPool,
{
}
@ -929,6 +946,7 @@ where
impl<T, A> Hash for CpuBufferPoolSubbuffer<T, A>
where
T: Send + Sync,
[T]: BufferContents,
A: MemoryPool,
{
#[inline]

View File

@ -13,41 +13,32 @@
//! You can read the buffer multiple times simultaneously from multiple queues. Trying to read and
//! write simultaneously, or write and write simultaneously will block with a semaphore.
use crate::buffer::sys::BufferCreationError;
use crate::buffer::sys::UnsafeBuffer;
use crate::buffer::sys::UnsafeBufferCreateInfo;
use crate::buffer::traits::BufferAccess;
use crate::buffer::traits::BufferAccessObject;
use crate::buffer::traits::BufferInner;
use crate::buffer::traits::TypedBufferAccess;
use crate::buffer::BufferUsage;
use crate::device::physical::QueueFamily;
use crate::device::Device;
use crate::device::DeviceOwned;
use crate::device::Queue;
use crate::memory::pool::alloc_dedicated_with_exportable_fd;
use crate::memory::pool::AllocFromRequirementsFilter;
use crate::memory::pool::AllocLayout;
use crate::memory::pool::MappingRequirement;
use crate::memory::pool::MemoryPool;
use crate::memory::pool::MemoryPoolAlloc;
use crate::memory::pool::PotentialDedicatedAllocation;
use crate::memory::pool::StdMemoryPoolAlloc;
use crate::memory::DeviceMemoryAllocationError;
use crate::memory::DeviceMemoryExportError;
use crate::memory::ExternalMemoryHandleType;
use crate::memory::{DedicatedAllocation, MemoryRequirements};
use crate::sync::AccessError;
use crate::sync::Sharing;
use crate::DeviceSize;
use super::{
sys::{UnsafeBuffer, UnsafeBufferCreateInfo},
BufferAccess, BufferAccessObject, BufferContents, BufferCreationError, BufferInner,
BufferUsage, TypedBufferAccess,
};
use crate::{
device::{physical::QueueFamily, Device, DeviceOwned, Queue},
memory::{
pool::{
alloc_dedicated_with_exportable_fd, AllocFromRequirementsFilter, AllocLayout,
MappingRequirement, MemoryPoolAlloc, PotentialDedicatedAllocation, StdMemoryPoolAlloc,
},
DedicatedAllocation, DeviceMemoryAllocationError, DeviceMemoryExportError,
ExternalMemoryHandleType, MemoryPool, MemoryRequirements,
},
sync::{AccessError, Sharing},
DeviceSize,
};
use smallvec::SmallVec;
use std::fs::File;
use std::hash::Hash;
use std::hash::Hasher;
use std::marker::PhantomData;
use std::mem;
use std::sync::Arc;
use std::sync::Mutex;
use std::{
fs::File,
hash::{Hash, Hasher},
marker::PhantomData,
mem::size_of,
sync::{Arc, Mutex},
};
/// Buffer whose content is in device-local memory.
///
@ -58,7 +49,10 @@ use std::sync::Mutex;
/// The `DeviceLocalBuffer` will be in device-local memory, unless the device doesn't provide any
/// device-local memory.
#[derive(Debug)]
pub struct DeviceLocalBuffer<T: ?Sized, A = PotentialDedicatedAllocation<StdMemoryPoolAlloc>> {
pub struct DeviceLocalBuffer<T, A = PotentialDedicatedAllocation<StdMemoryPoolAlloc>>
where
T: BufferContents + ?Sized,
{
// Inner content.
inner: UnsafeBuffer,
@ -82,7 +76,10 @@ enum GpuAccess {
Exclusive { num: u32 },
}
impl<T> DeviceLocalBuffer<T> {
impl<T> DeviceLocalBuffer<T>
where
T: BufferContents,
{
/// Builds a new buffer. Only allowed for sized data.
///
/// # Panics
@ -98,17 +95,15 @@ impl<T> DeviceLocalBuffer<T> {
I: IntoIterator<Item = QueueFamily<'a>>,
{
unsafe {
DeviceLocalBuffer::raw(
device,
mem::size_of::<T>() as DeviceSize,
usage,
queue_families,
)
DeviceLocalBuffer::raw(device, size_of::<T>() as DeviceSize, usage, queue_families)
}
}
}
impl<T> DeviceLocalBuffer<[T]> {
impl<T> DeviceLocalBuffer<[T]>
where
[T]: BufferContents,
{
/// Builds a new buffer. Can be used for arrays.
///
/// # Panics
@ -128,7 +123,7 @@ impl<T> DeviceLocalBuffer<[T]> {
unsafe {
DeviceLocalBuffer::raw(
device,
len * mem::size_of::<T>() as DeviceSize,
len * size_of::<T>() as DeviceSize,
usage,
queue_families,
)
@ -136,7 +131,10 @@ impl<T> DeviceLocalBuffer<[T]> {
}
}
impl<T: ?Sized> DeviceLocalBuffer<T> {
impl<T> DeviceLocalBuffer<T>
where
T: BufferContents + ?Sized,
{
/// Builds a new buffer without checking the size.
///
/// # Safety
@ -279,7 +277,10 @@ impl<T: ?Sized> DeviceLocalBuffer<T> {
}
}
impl<T: ?Sized, A> DeviceLocalBuffer<T, A> {
impl<T, A> DeviceLocalBuffer<T, A>
where
T: BufferContents + ?Sized,
{
/// Returns the queue families this buffer can be used on.
// TODO: use a custom iterator
#[inline]
@ -296,16 +297,19 @@ impl<T: ?Sized, A> DeviceLocalBuffer<T, A> {
}
}
unsafe impl<T: ?Sized, A> DeviceOwned for DeviceLocalBuffer<T, A> {
unsafe impl<T, A> DeviceOwned for DeviceLocalBuffer<T, A>
where
T: BufferContents + ?Sized,
{
#[inline]
fn device(&self) -> &Arc<Device> {
self.inner.device()
}
}
unsafe impl<T: ?Sized, A> BufferAccess for DeviceLocalBuffer<T, A>
unsafe impl<T, A> BufferAccess for DeviceLocalBuffer<T, A>
where
T: Send + Sync + 'static,
T: BufferContents + ?Sized,
A: Send + Sync,
{
#[inline]
@ -393,9 +397,9 @@ where
}
}
impl<T: ?Sized, A> BufferAccessObject for Arc<DeviceLocalBuffer<T, A>>
impl<T, A> BufferAccessObject for Arc<DeviceLocalBuffer<T, A>>
where
T: Send + Sync + 'static,
T: BufferContents + ?Sized,
A: Send + Sync + 'static,
{
#[inline]
@ -404,17 +408,17 @@ where
}
}
unsafe impl<T: ?Sized, A> TypedBufferAccess for DeviceLocalBuffer<T, A>
unsafe impl<T, A> TypedBufferAccess for DeviceLocalBuffer<T, A>
where
T: Send + Sync + 'static,
T: BufferContents + ?Sized,
A: Send + Sync,
{
type Content = T;
}
impl<T: ?Sized, A> PartialEq for DeviceLocalBuffer<T, A>
impl<T, A> PartialEq for DeviceLocalBuffer<T, A>
where
T: Send + Sync + 'static,
T: BufferContents + ?Sized,
A: Send + Sync,
{
#[inline]
@ -423,16 +427,16 @@ where
}
}
impl<T: ?Sized, A> Eq for DeviceLocalBuffer<T, A>
impl<T, A> Eq for DeviceLocalBuffer<T, A>
where
T: Send + Sync + 'static,
T: BufferContents + ?Sized,
A: Send + Sync,
{
}
impl<T: ?Sized, A> Hash for DeviceLocalBuffer<T, A>
impl<T, A> Hash for DeviceLocalBuffer<T, A>
where
T: Send + Sync + 'static,
T: BufferContents + ?Sized,
A: Send + Sync,
{
#[inline]

View File

@ -18,49 +18,44 @@
//! The buffer will be stored in device-local memory if possible
//!
use crate::buffer::sys::BufferCreationError;
use crate::buffer::sys::UnsafeBuffer;
use crate::buffer::sys::UnsafeBufferCreateInfo;
use crate::buffer::traits::BufferAccess;
use crate::buffer::traits::BufferAccessObject;
use crate::buffer::traits::BufferInner;
use crate::buffer::traits::TypedBufferAccess;
use crate::buffer::BufferUsage;
use crate::buffer::CpuAccessibleBuffer;
use crate::command_buffer::AutoCommandBufferBuilder;
use crate::command_buffer::CommandBufferExecFuture;
use crate::command_buffer::CommandBufferUsage;
use crate::command_buffer::PrimaryAutoCommandBuffer;
use crate::command_buffer::PrimaryCommandBuffer;
use crate::device::physical::QueueFamily;
use crate::device::Device;
use crate::device::DeviceOwned;
use crate::device::Queue;
use crate::memory::pool::AllocFromRequirementsFilter;
use crate::memory::pool::AllocLayout;
use crate::memory::pool::MappingRequirement;
use crate::memory::pool::MemoryPool;
use crate::memory::pool::MemoryPoolAlloc;
use crate::memory::pool::PotentialDedicatedAllocation;
use crate::memory::pool::StdMemoryPoolAlloc;
use crate::memory::DedicatedAllocation;
use crate::memory::DeviceMemoryAllocationError;
use crate::sync::AccessError;
use crate::sync::NowFuture;
use crate::sync::Sharing;
use crate::DeviceSize;
use super::{
sys::UnsafeBuffer, BufferAccess, BufferAccessObject, BufferContents, BufferInner, BufferUsage,
CpuAccessibleBuffer,
};
use crate::{
buffer::{sys::UnsafeBufferCreateInfo, BufferCreationError, TypedBufferAccess},
command_buffer::{
AutoCommandBufferBuilder, CommandBufferExecFuture, CommandBufferUsage,
PrimaryAutoCommandBuffer, PrimaryCommandBuffer,
},
device::{physical::QueueFamily, Device, DeviceOwned, Queue},
memory::{
pool::{
AllocFromRequirementsFilter, AllocLayout, MappingRequirement, MemoryPoolAlloc,
PotentialDedicatedAllocation, StdMemoryPoolAlloc,
},
DedicatedAllocation, DeviceMemoryAllocationError, MemoryPool,
},
sync::{AccessError, NowFuture, Sharing},
DeviceSize,
};
use smallvec::SmallVec;
use std::hash::Hash;
use std::hash::Hasher;
use std::marker::PhantomData;
use std::mem;
use std::sync::atomic::AtomicBool;
use std::sync::atomic::Ordering;
use std::sync::Arc;
use std::{
hash::{Hash, Hasher},
marker::PhantomData,
mem::size_of,
sync::{
atomic::{AtomicBool, Ordering},
Arc,
},
};
/// Buffer that is written once then read for as long as it is alive.
// TODO: implement Debug
pub struct ImmutableBuffer<T: ?Sized, A = PotentialDedicatedAllocation<StdMemoryPoolAlloc>> {
#[derive(Debug)]
pub struct ImmutableBuffer<T, A = PotentialDedicatedAllocation<StdMemoryPoolAlloc>>
where
T: BufferContents + ?Sized,
{
// Inner content.
inner: UnsafeBuffer,
@ -81,41 +76,10 @@ pub struct ImmutableBuffer<T: ?Sized, A = PotentialDedicatedAllocation<StdMemory
// TODO: make this prettier
type ImmutableBufferFromBufferFuture = CommandBufferExecFuture<NowFuture, PrimaryAutoCommandBuffer>;
impl<T: ?Sized> ImmutableBuffer<T> {
/// Builds an `ImmutableBuffer` from some data.
///
/// This function builds a memory-mapped intermediate buffer, writes the data to it, builds a
/// command buffer that copies from this intermediate buffer to the final buffer, and finally
/// submits the command buffer as a future.
///
/// This function returns two objects: the newly-created buffer, and a future representing
/// the initial upload operation. In order to be allowed to use the `ImmutableBuffer`, you must
/// either submit your operation after this future, or execute this future and wait for it to
/// be finished before submitting your own operation.
///
/// # Panics
///
/// - Panics if `T` has zero size.
pub fn from_data(
data: T,
usage: BufferUsage,
queue: Arc<Queue>,
) -> Result<
(Arc<ImmutableBuffer<T>>, ImmutableBufferFromBufferFuture),
DeviceMemoryAllocationError,
>
where
T: Copy + Send + Sync + Sized + 'static,
{
let source = CpuAccessibleBuffer::from_data(
queue.device().clone(),
BufferUsage::transfer_source(),
false,
data,
)?;
ImmutableBuffer::from_buffer(source, usage, queue)
}
impl<T> ImmutableBuffer<T>
where
T: BufferContents + ?Sized,
{
/// Builds an `ImmutableBuffer` that copies its data from another buffer.
///
/// This function returns two objects: the newly-created buffer, and a future representing
@ -132,7 +96,6 @@ impl<T: ?Sized> ImmutableBuffer<T> {
>
where
B: TypedBufferAccess<Content = T> + 'static,
T: Send + Sync + 'static,
{
unsafe {
// We automatically set `transfer_destination` to true in order to avoid annoying errors.
@ -166,7 +129,41 @@ impl<T: ?Sized> ImmutableBuffer<T> {
}
}
impl<T> ImmutableBuffer<T> {
impl<T> ImmutableBuffer<T>
where
T: BufferContents,
{
/// Builds an `ImmutableBuffer` from some data.
///
/// This function builds a memory-mapped intermediate buffer, writes the data to it, builds a
/// command buffer that copies from this intermediate buffer to the final buffer, and finally
/// submits the command buffer as a future.
///
/// This function returns two objects: the newly-created buffer, and a future representing
/// the initial upload operation. In order to be allowed to use the `ImmutableBuffer`, you must
/// either submit your operation after this future, or execute this future and wait for it to
/// be finished before submitting your own operation.
///
/// # Panics
///
/// - Panics if `T` has zero size.
pub fn from_data(
data: T,
usage: BufferUsage,
queue: Arc<Queue>,
) -> Result<
(Arc<ImmutableBuffer<T>>, ImmutableBufferFromBufferFuture),
DeviceMemoryAllocationError,
> {
let source = CpuAccessibleBuffer::from_data(
queue.device().clone(),
BufferUsage::transfer_source(),
false,
data,
)?;
ImmutableBuffer::from_buffer(source, usage, queue)
}
/// Builds a new buffer with uninitialized data. Only allowed for sized data.
///
/// Returns two things: the buffer, and a special access that should be used for the initial
@ -199,14 +196,17 @@ impl<T> ImmutableBuffer<T> {
> {
ImmutableBuffer::raw(
device.clone(),
mem::size_of::<T>() as DeviceSize,
size_of::<T>() as DeviceSize,
usage,
device.active_queue_families(),
)
}
}
impl<T> ImmutableBuffer<[T]> {
impl<T> ImmutableBuffer<[T]>
where
[T]: BufferContents,
{
/// # Panics
///
/// - Panics if `T` has zero size.
@ -222,7 +222,6 @@ impl<T> ImmutableBuffer<[T]> {
where
D: IntoIterator<Item = T>,
D::IntoIter: ExactSizeIterator,
T: Send + Sync + Sized + 'static,
{
let source = CpuAccessibleBuffer::from_iter(
queue.device().clone(),
@ -267,14 +266,17 @@ impl<T> ImmutableBuffer<[T]> {
> {
ImmutableBuffer::raw(
device.clone(),
len * mem::size_of::<T>() as DeviceSize,
len * size_of::<T>() as DeviceSize,
usage,
device.active_queue_families(),
)
}
}
impl<T: ?Sized> ImmutableBuffer<T> {
impl<T> ImmutableBuffer<T>
where
T: BufferContents + ?Sized,
{
/// Builds a new buffer without checking the size and granting free access for the initial
/// upload.
///
@ -381,7 +383,10 @@ impl<T: ?Sized> ImmutableBuffer<T> {
}
}
impl<T: ?Sized, A> ImmutableBuffer<T, A> {
impl<T, A> ImmutableBuffer<T, A>
where
T: BufferContents + ?Sized,
{
/// Returns the device used to create this buffer.
#[inline]
pub fn device(&self) -> &Arc<Device> {
@ -406,7 +411,7 @@ impl<T: ?Sized, A> ImmutableBuffer<T, A> {
unsafe impl<T, A> BufferAccess for ImmutableBuffer<T, A>
where
T: Send + Sync + ?Sized,
T: BufferContents + ?Sized,
A: Send + Sync,
{
#[inline]
@ -449,7 +454,7 @@ where
impl<T, A> BufferAccessObject for Arc<ImmutableBuffer<T, A>>
where
T: Send + Sync + ?Sized + 'static,
T: BufferContents + ?Sized,
A: Send + Sync + 'static,
{
#[inline]
@ -460,22 +465,25 @@ where
unsafe impl<T, A> TypedBufferAccess for ImmutableBuffer<T, A>
where
T: Send + Sync + ?Sized,
T: BufferContents + ?Sized,
A: Send + Sync,
{
type Content = T;
}
unsafe impl<T: ?Sized, A> DeviceOwned for ImmutableBuffer<T, A> {
unsafe impl<T, A> DeviceOwned for ImmutableBuffer<T, A>
where
T: BufferContents + ?Sized,
{
#[inline]
fn device(&self) -> &Arc<Device> {
self.inner.device()
}
}
impl<T: ?Sized, A> PartialEq for ImmutableBuffer<T, A>
impl<T, A> PartialEq for ImmutableBuffer<T, A>
where
T: Send + Sync,
T: BufferContents + ?Sized,
A: Send + Sync,
{
#[inline]
@ -484,16 +492,16 @@ where
}
}
impl<T: ?Sized, A> Eq for ImmutableBuffer<T, A>
impl<T, A> Eq for ImmutableBuffer<T, A>
where
T: Send + Sync,
T: BufferContents + ?Sized,
A: Send + Sync,
{
}
impl<T: ?Sized, A> Hash for ImmutableBuffer<T, A>
impl<T, A> Hash for ImmutableBuffer<T, A>
where
T: Send + Sync,
T: BufferContents + ?Sized,
A: Send + Sync,
{
#[inline]
@ -504,18 +512,18 @@ where
}
/// Access to the immutable buffer that can be used for the initial upload.
//#[derive(Debug)] // TODO:
pub struct ImmutableBufferInitialization<
T: ?Sized,
A = PotentialDedicatedAllocation<StdMemoryPoolAlloc>,
> {
#[derive(Debug)]
pub struct ImmutableBufferInitialization<T, A = PotentialDedicatedAllocation<StdMemoryPoolAlloc>>
where
T: BufferContents + ?Sized,
{
buffer: Arc<ImmutableBuffer<T, A>>,
used: Arc<AtomicBool>,
}
unsafe impl<T, A> BufferAccess for ImmutableBufferInitialization<T, A>
where
T: Send + Sync + ?Sized,
T: BufferContents + ?Sized,
A: Send + Sync,
{
#[inline]
@ -563,7 +571,7 @@ where
impl<T, A> BufferAccessObject for Arc<ImmutableBufferInitialization<T, A>>
where
T: Send + Sync + ?Sized + 'static,
T: BufferContents + ?Sized,
A: Send + Sync + 'static,
{
#[inline]
@ -574,20 +582,26 @@ where
unsafe impl<T, A> TypedBufferAccess for ImmutableBufferInitialization<T, A>
where
T: Send + Sync + ?Sized,
T: BufferContents + ?Sized,
A: Send + Sync,
{
type Content = T;
}
unsafe impl<T: ?Sized, A> DeviceOwned for ImmutableBufferInitialization<T, A> {
unsafe impl<T, A> DeviceOwned for ImmutableBufferInitialization<T, A>
where
T: BufferContents + ?Sized,
{
#[inline]
fn device(&self) -> &Arc<Device> {
self.buffer.inner.device()
}
}
impl<T: ?Sized, A> Clone for ImmutableBufferInitialization<T, A> {
impl<T, A> Clone for ImmutableBufferInitialization<T, A>
where
T: BufferContents + ?Sized,
{
#[inline]
fn clone(&self) -> ImmutableBufferInitialization<T, A> {
ImmutableBufferInitialization {
@ -597,9 +611,9 @@ impl<T: ?Sized, A> Clone for ImmutableBufferInitialization<T, A> {
}
}
impl<T: ?Sized, A> PartialEq for ImmutableBufferInitialization<T, A>
impl<T, A> PartialEq for ImmutableBufferInitialization<T, A>
where
T: Send + Sync,
T: BufferContents + ?Sized,
A: Send + Sync,
{
#[inline]
@ -608,16 +622,16 @@ where
}
}
impl<T: ?Sized, A> Eq for ImmutableBufferInitialization<T, A>
impl<T, A> Eq for ImmutableBufferInitialization<T, A>
where
T: Send + Sync,
T: BufferContents + ?Sized,
A: Send + Sync,
{
}
impl<T: ?Sized, A> Hash for ImmutableBufferInitialization<T, A>
impl<T, A> Hash for ImmutableBufferInitialization<T, A>
where
T: Send + Sync,
T: BufferContents + ?Sized,
A: Send + Sync,
{
#[inline]

View File

@ -83,21 +83,27 @@
//! for how to create a buffer view.
//!
pub use self::cpu_access::CpuAccessibleBuffer;
pub use self::cpu_pool::CpuBufferPool;
pub use self::device_local::DeviceLocalBuffer;
pub use self::immutable::ImmutableBuffer;
pub use self::slice::BufferSlice;
pub use self::sys::BufferCreationError;
use self::sys::SparseLevel;
pub use self::traits::BufferAccess;
pub use self::traits::BufferAccessObject;
pub use self::traits::BufferDeviceAddressError;
pub use self::traits::BufferInner;
pub use self::traits::TypedBufferAccess;
pub use self::usage::BufferUsage;
use crate::memory::ExternalMemoryHandleType;
use crate::memory::ExternalMemoryProperties;
pub use self::{
cpu_access::CpuAccessibleBuffer,
cpu_pool::CpuBufferPool,
device_local::DeviceLocalBuffer,
immutable::ImmutableBuffer,
slice::BufferSlice,
sys::{BufferCreationError, SparseLevel},
traits::{
BufferAccess, BufferAccessObject, BufferDeviceAddressError, BufferInner, TypedBufferAccess,
},
usage::BufferUsage,
};
use crate::{
memory::{ExternalMemoryHandleType, ExternalMemoryProperties},
DeviceSize,
};
use bytemuck::{
bytes_of, cast_slice, try_cast_slice, try_cast_slice_mut, try_from_bytes, try_from_bytes_mut,
Pod, PodCastError,
};
use std::mem::size_of;
pub mod cpu_access;
pub mod cpu_pool;
@ -110,6 +116,72 @@ mod slice;
mod traits;
mod usage;
/// Trait for types of data that can be put in a buffer. These can be safely transmuted to and from
/// a slice of bytes.
pub unsafe trait BufferContents: Send + Sync + 'static {
/// Converts an immutable reference to `Self` to an immutable byte slice.
fn as_bytes(&self) -> &[u8];
/// Converts an immutable byte slice into an immutable reference to `Self`.
fn from_bytes(bytes: &[u8]) -> Result<&Self, PodCastError>;
/// Converts a mutable byte slice into a mutable reference to `Self`.
fn from_bytes_mut(bytes: &mut [u8]) -> Result<&mut Self, PodCastError>;
/// Returns the size of an element of the type.
fn size_of_element() -> DeviceSize;
}
unsafe impl<T> BufferContents for T
where
T: Pod + Send + Sync,
{
#[inline]
fn as_bytes(&self) -> &[u8] {
bytes_of(self)
}
#[inline]
fn from_bytes(bytes: &[u8]) -> Result<&T, PodCastError> {
try_from_bytes(bytes)
}
#[inline]
fn from_bytes_mut(bytes: &mut [u8]) -> Result<&mut T, PodCastError> {
try_from_bytes_mut(bytes)
}
#[inline]
fn size_of_element() -> DeviceSize {
1
}
}
unsafe impl<T> BufferContents for [T]
where
T: Pod + Send + Sync,
{
#[inline]
fn as_bytes(&self) -> &[u8] {
cast_slice(self)
}
#[inline]
fn from_bytes(bytes: &[u8]) -> Result<&[T], PodCastError> {
try_cast_slice(bytes)
}
#[inline]
fn from_bytes_mut(bytes: &mut [u8]) -> Result<&mut [T], PodCastError> {
try_cast_slice_mut(bytes)
}
#[inline]
fn size_of_element() -> DeviceSize {
size_of::<T>() as DeviceSize
}
}
/// The buffer configuration to query in
/// [`PhysicalDevice::external_buffer_properties`](crate::device::physical::PhysicalDevice::external_buffer_properties).
#[derive(Clone, Debug)]

View File

@ -7,6 +7,7 @@
// notice may not be copied, modified, or distributed except
// according to those terms.
use super::BufferContents;
use crate::buffer::traits::BufferAccess;
use crate::buffer::traits::BufferAccessObject;
use crate::buffer::traits::BufferInner;
@ -264,7 +265,7 @@ where
unsafe impl<T, B> TypedBufferAccess for BufferSlice<T, B>
where
T: Send + Sync + ?Sized,
T: BufferContents + ?Sized,
B: BufferAccess,
{
type Content = T;

View File

@ -285,7 +285,7 @@ impl UnsafeBuffer {
);
let mem_reqs = mem_reqs.assume_init();
mem_reqs.size <= (memory.size() - offset)
mem_reqs.size <= (memory.allocation_size() - offset)
&& (offset % mem_reqs.alignment) == 0
&& mem_reqs.memory_type_bits & (1 << memory.memory_type().id()) != 0
});

View File

@ -7,11 +7,11 @@
// notice may not be copied, modified, or distributed except
// according to those terms.
use super::BufferContents;
use crate::buffer::sys::UnsafeBuffer;
use crate::buffer::BufferSlice;
use crate::device::DeviceOwned;
use crate::device::Queue;
use crate::memory::Content;
use crate::sync::AccessError;
use crate::DeviceSize;
use crate::SafeDeref;
@ -207,17 +207,14 @@ where
/// Extension trait for `BufferAccess`. Indicates the type of the content of the buffer.
pub unsafe trait TypedBufferAccess: BufferAccess {
/// The type of the content.
type Content: ?Sized;
type Content: BufferContents + ?Sized;
/// Returns the length of the buffer in number of elements.
///
/// This method can only be called for buffers whose type is known to be an array.
#[inline]
fn len(&self) -> DeviceSize
where
Self::Content: Content,
{
self.size() / <Self::Content as Content>::indiv_size()
fn len(&self) -> DeviceSize {
self.size() / Self::Content::size_of_element()
}
}

View File

@ -45,10 +45,10 @@ use super::{
SubpassContents,
};
use crate::{
buffer::{BufferAccess, TypedBufferAccess},
buffer::{BufferAccess, BufferContents, TypedBufferAccess},
descriptor_set::{check_descriptor_write, DescriptorSetsCollection, WriteDescriptorSet},
device::{physical::QueueFamily, Device, DeviceOwned, Queue},
format::{ClearValue, NumericType, Pixel},
format::{ClearValue, NumericType},
image::{
attachment::{ClearAttachment, ClearRect},
ImageAccess, ImageAspect, ImageAspects, ImageLayout,
@ -85,7 +85,7 @@ use std::{
ffi::CStr,
fmt, iter,
marker::PhantomData,
mem,
mem::{size_of, size_of_val},
ops::Range,
slice,
sync::{
@ -1177,7 +1177,7 @@ impl<L, P> AutoCommandBufferBuilder<L, P> {
copy_size,
)?;
self.inner
.copy_buffer(source, destination, iter::once((0, 0, copy_size)))?;
.copy_buffer(source, destination, [(0, 0, copy_size)])?;
Ok(self)
}
}
@ -1224,15 +1224,11 @@ impl<L, P> AutoCommandBufferBuilder<L, P> {
}
/// Adds a command that copies from a buffer to an image.
pub fn copy_buffer_to_image<S, Px>(
pub fn copy_buffer_to_image(
&mut self,
source: Arc<S>,
source: Arc<dyn BufferAccess>,
destination: Arc<dyn ImageAccess>,
) -> Result<&mut Self, CopyBufferImageError>
where
S: TypedBufferAccess<Content = [Px]> + 'static,
Px: Pixel,
{
) -> Result<&mut Self, CopyBufferImageError> {
self.ensure_outside_render_pass()?;
let dims = destination.dimensions().width_height_depth();
@ -1240,20 +1236,16 @@ impl<L, P> AutoCommandBufferBuilder<L, P> {
}
/// Adds a command that copies from a buffer to an image.
pub fn copy_buffer_to_image_dimensions<S, Px>(
pub fn copy_buffer_to_image_dimensions(
&mut self,
source: Arc<S>,
source: Arc<dyn BufferAccess>,
destination: Arc<dyn ImageAccess>,
offset: [u32; 3],
size: [u32; 3],
base_array_layer: u32,
layer_count: u32,
mip_level: u32,
) -> Result<&mut Self, CopyBufferImageError>
where
S: TypedBufferAccess<Content = [Px]> + 'static,
Px: Pixel,
{
) -> Result<&mut Self, CopyBufferImageError> {
unsafe {
self.ensure_outside_render_pass()?;
@ -1399,15 +1391,11 @@ impl<L, P> AutoCommandBufferBuilder<L, P> {
/// Adds a command that copies from an image to a buffer.
// The data layout of the image on the gpu is opaque, as in, it is non of our business how the gpu stores the image.
// This does not matter since the act of copying the image into a buffer converts it to linear form.
pub fn copy_image_to_buffer<D, Px>(
pub fn copy_image_to_buffer(
&mut self,
source: Arc<dyn ImageAccess>,
destination: Arc<D>,
) -> Result<&mut Self, CopyBufferImageError>
where
D: TypedBufferAccess<Content = [Px]> + 'static,
Px: Pixel,
{
destination: Arc<dyn BufferAccess>,
) -> Result<&mut Self, CopyBufferImageError> {
self.ensure_outside_render_pass()?;
let dims = source.dimensions().width_height_depth();
@ -1415,20 +1403,16 @@ impl<L, P> AutoCommandBufferBuilder<L, P> {
}
/// Adds a command that copies from an image to a buffer.
pub fn copy_image_to_buffer_dimensions<D, Px>(
pub fn copy_image_to_buffer_dimensions(
&mut self,
source: Arc<dyn ImageAccess>,
destination: Arc<D>,
destination: Arc<dyn BufferAccess>,
offset: [u32; 3],
size: [u32; 3],
base_array_layer: u32,
layer_count: u32,
mip_level: u32,
) -> Result<&mut Self, CopyBufferImageError>
where
D: TypedBufferAccess<Content = [Px]> + 'static,
Px: Pixel,
{
) -> Result<&mut Self, CopyBufferImageError> {
unsafe {
self.ensure_outside_render_pass()?;
@ -1664,16 +1648,19 @@ impl<L, P> AutoCommandBufferBuilder<L, P> {
check_vertex_buffers(self.state(), pipeline, None, None)?;
check_indirect_buffer(self.device(), indirect_buffer.as_ref())?;
let requested = indirect_buffer.len() as u32;
let draw_count = indirect_buffer.len() as u32;
let limit = self
.device()
.physical_device()
.properties()
.max_draw_indirect_count;
if requested > limit {
if draw_count > limit {
return Err(
CheckIndirectBufferError::MaxDrawIndirectCountLimitExceeded { limit, requested }
CheckIndirectBufferError::MaxDrawIndirectCountLimitExceeded {
limit,
requested: draw_count,
}
.into(),
);
}
@ -1681,8 +1668,8 @@ impl<L, P> AutoCommandBufferBuilder<L, P> {
unsafe {
self.inner.draw_indirect(
indirect_buffer,
requested,
mem::size_of::<DrawIndirectCommand>() as u32,
draw_count,
size_of::<DrawIndirectCommand>() as u32,
)?;
}
@ -1780,16 +1767,19 @@ impl<L, P> AutoCommandBufferBuilder<L, P> {
check_index_buffer(self.state(), None)?;
check_indirect_buffer(self.device(), indirect_buffer.as_ref())?;
let requested = indirect_buffer.len() as u32;
let draw_count = indirect_buffer.len() as u32;
let limit = self
.device()
.physical_device()
.properties()
.max_draw_indirect_count;
if requested > limit {
if draw_count > limit {
return Err(
CheckIndirectBufferError::MaxDrawIndirectCountLimitExceeded { limit, requested }
CheckIndirectBufferError::MaxDrawIndirectCountLimitExceeded {
limit,
requested: draw_count,
}
.into(),
);
}
@ -1797,8 +1787,8 @@ impl<L, P> AutoCommandBufferBuilder<L, P> {
unsafe {
self.inner.draw_indexed_indirect(
indirect_buffer,
requested,
mem::size_of::<DrawIndexedIndirectCommand>() as u32,
draw_count,
size_of::<DrawIndexedIndirectCommand>() as u32,
)?;
}
@ -1843,7 +1833,7 @@ impl<L, P> AutoCommandBufferBuilder<L, P> {
offset: u32,
push_constants: Pc,
) -> &mut Self {
let size = mem::size_of::<Pc>() as u32;
let size = size_of::<Pc>() as u32;
if size == 0 {
return self;
@ -3022,14 +3012,14 @@ impl<L, P> AutoCommandBufferBuilder<L, P> {
) -> Result<&mut Self, UpdateBufferError>
where
B: TypedBufferAccess<Content = D> + 'static,
D: ?Sized,
D: BufferContents + ?Sized,
Dd: SafeDeref<Target = D> + Send + Sync + 'static,
{
unsafe {
self.ensure_outside_render_pass()?;
check_update_buffer(self.device(), buffer.as_ref(), data.deref())?;
let size_of_data = mem::size_of_val(data.deref()) as DeviceSize;
let size_of_data = size_of_val(data.deref()) as DeviceSize;
if buffer.size() >= size_of_data {
self.inner.update_buffer(buffer, data);
} else {

View File

@ -76,41 +76,26 @@
//! alternative command pool implementations and use them. See the `pool` module for more
//! information.
pub use self::auto::AutoCommandBufferBuilder;
pub use self::auto::AutoCommandBufferBuilderContextError;
pub use self::auto::BeginError;
pub use self::auto::BeginQueryError;
pub use self::auto::BeginRenderPassError;
pub use self::auto::BlitImageError;
pub use self::auto::BuildError;
pub use self::auto::ClearColorImageError;
pub use self::auto::CopyBufferError;
pub use self::auto::CopyBufferImageError;
pub use self::auto::CopyImageError;
pub use self::auto::CopyQueryPoolResultsError;
pub use self::auto::DebugMarkerError;
pub use self::auto::DispatchError;
pub use self::auto::DispatchIndirectError;
pub use self::auto::DrawError;
pub use self::auto::DrawIndexedError;
pub use self::auto::DrawIndexedIndirectError;
pub use self::auto::DrawIndirectError;
pub use self::auto::EndQueryError;
pub use self::auto::ExecuteCommandsError;
pub use self::auto::FillBufferError;
pub use self::auto::PrimaryAutoCommandBuffer;
pub use self::auto::ResetQueryPoolError;
pub use self::auto::SecondaryAutoCommandBuffer;
pub use self::auto::UpdateBufferError;
pub use self::auto::WriteTimestampError;
pub use self::traits::CommandBufferExecError;
pub use self::traits::CommandBufferExecFuture;
pub use self::traits::PrimaryCommandBuffer;
pub use self::traits::SecondaryCommandBuffer;
use crate::query::QueryControlFlags;
use crate::query::QueryPipelineStatisticFlags;
use crate::render_pass::Framebuffer;
use crate::render_pass::Subpass;
pub use self::{
auto::{
AutoCommandBufferBuilder, AutoCommandBufferBuilderContextError, BeginError,
BeginQueryError, BeginRenderPassError, BlitImageError, BuildError, ClearColorImageError,
CopyBufferError, CopyBufferImageError, CopyImageError, CopyQueryPoolResultsError,
DebugMarkerError, DispatchError, DispatchIndirectError, DrawError, DrawIndexedError,
DrawIndexedIndirectError, DrawIndirectError, EndQueryError, ExecuteCommandsError,
FillBufferError, PrimaryAutoCommandBuffer, ResetQueryPoolError, SecondaryAutoCommandBuffer,
UpdateBufferError, WriteTimestampError,
},
traits::{
CommandBufferExecError, CommandBufferExecFuture, PrimaryCommandBuffer,
SecondaryCommandBuffer,
},
};
use crate::{
query::{QueryControlFlags, QueryPipelineStatisticFlags},
render_pass::{Framebuffer, Subpass},
};
use bytemuck::{Pod, Zeroable};
use std::sync::Arc;
mod auto;
@ -137,7 +122,7 @@ impl ImageUninitializedSafe {
}
#[repr(C)]
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
#[derive(Clone, Copy, Debug, Default, Zeroable, Pod, PartialEq, Eq)]
pub struct DrawIndirectCommand {
pub vertex_count: u32,
pub instance_count: u32,
@ -146,7 +131,7 @@ pub struct DrawIndirectCommand {
}
#[repr(C)]
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
#[derive(Clone, Copy, Debug, Default, Zeroable, Pod, PartialEq, Eq)]
pub struct DrawIndexedIndirectCommand {
pub index_count: u32,
pub instance_count: u32,
@ -156,7 +141,7 @@ pub struct DrawIndexedIndirectCommand {
}
#[repr(C)]
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
#[derive(Clone, Copy, Debug, Default, Zeroable, Pod, PartialEq, Eq)]
pub struct DispatchIndirectCommand {
pub x: u32,
pub y: u32,

View File

@ -9,7 +9,7 @@
use super::{SyncCommandBufferBuilder, SyncCommandBufferBuilderError};
use crate::{
buffer::{BufferAccess, TypedBufferAccess},
buffer::{BufferAccess, BufferContents, TypedBufferAccess},
command_buffer::{
synced::{Command, KeyTy, ResourceKey, SetOrPush},
sys::{
@ -53,7 +53,7 @@ use smallvec::SmallVec;
use std::{
borrow::Cow,
ffi::CStr,
mem,
mem::size_of_val,
ops::Range,
ptr,
sync::{Arc, Mutex},
@ -1616,7 +1616,7 @@ impl SyncCommandBufferBuilder {
}
}
debug_assert!(mem::size_of_val(data) >= size as usize);
debug_assert!(size_of_val(data) >= size as usize);
let mut out = Vec::with_capacity(size as usize);
ptr::copy::<u8>(
@ -2581,7 +2581,7 @@ impl SyncCommandBufferBuilder {
#[inline]
pub unsafe fn update_buffer<D, Dd>(&mut self, buffer: Arc<dyn BufferAccess>, data: Dd)
where
D: ?Sized,
D: BufferContents + ?Sized,
Dd: SafeDeref<Target = D> + Send + Sync + 'static,
{
struct Cmd<Dd> {
@ -2591,7 +2591,7 @@ impl SyncCommandBufferBuilder {
impl<D, Dd> Command for Cmd<Dd>
where
D: ?Sized,
D: BufferContents + ?Sized,
Dd: SafeDeref<Target = D> + Send + Sync + 'static,
{
fn name(&self) -> &'static str {

View File

@ -12,7 +12,7 @@ use super::{
CommandBufferUsage, SecondaryCommandBuffer, SubpassContents,
};
use crate::{
buffer::{BufferAccess, BufferInner, TypedBufferAccess},
buffer::{BufferAccess, BufferContents, BufferInner, TypedBufferAccess},
check_errors,
descriptor_set::{sys::UnsafeDescriptorSet, DescriptorWriteInfo, WriteDescriptorSet},
device::{Device, DeviceOwned},
@ -42,7 +42,13 @@ use crate::{
DeviceSize, OomError, Version, VulkanObject,
};
use smallvec::SmallVec;
use std::{ffi::CStr, mem, ops::Range, ptr, sync::Arc};
use std::{
ffi::CStr,
mem::{size_of, size_of_val},
ops::Range,
ptr,
sync::Arc,
};
/// Command buffer being built.
///
@ -332,17 +338,14 @@ impl UnsafeCommandBufferBuilder {
/// Does nothing if the list of descriptor sets is empty, as it would be a no-op and isn't a
/// valid usage of the command anyway.
#[inline]
pub unsafe fn bind_descriptor_sets<'s, S, I>(
pub unsafe fn bind_descriptor_sets<'s>(
&mut self,
pipeline_bind_point: PipelineBindPoint,
pipeline_layout: &PipelineLayout,
first_set: u32,
sets: S,
dynamic_offsets: I,
) where
S: IntoIterator<Item = &'s UnsafeDescriptorSet>,
I: IntoIterator<Item = u32>,
{
sets: impl IntoIterator<Item = &'s UnsafeDescriptorSet>,
dynamic_offsets: impl IntoIterator<Item = u32>,
) {
let fns = self.device().fns();
let cmd = self.internal_object();
@ -369,10 +372,7 @@ impl UnsafeCommandBufferBuilder {
/// Calls `vkCmdBindIndexBuffer` on the builder.
#[inline]
pub unsafe fn bind_index_buffer<B>(&mut self, buffer: &B, index_ty: IndexType)
where
B: ?Sized + BufferAccess,
{
pub unsafe fn bind_index_buffer(&mut self, buffer: &dyn BufferAccess, index_ty: IndexType) {
let fns = self.device().fns();
let cmd = self.internal_object();
@ -457,18 +457,14 @@ impl UnsafeCommandBufferBuilder {
/// Does nothing if the list of regions is empty, as it would be a no-op and isn't a valid
/// usage of the command anyway.
#[inline]
pub unsafe fn copy_image<S, D, R>(
pub unsafe fn copy_image(
&mut self,
source: &S,
source: &dyn ImageAccess,
source_layout: ImageLayout,
destination: &D,
destination: &dyn ImageAccess,
destination_layout: ImageLayout,
regions: R,
) where
S: ?Sized + ImageAccess,
D: ?Sized + ImageAccess,
R: IntoIterator<Item = UnsafeCommandBufferBuilderImageCopy>,
{
regions: impl IntoIterator<Item = UnsafeCommandBufferBuilderImageCopy>,
) {
// TODO: The correct check here is that the uncompressed element size of the source is
// equal to the compressed element size of the destination.
debug_assert!(
@ -572,19 +568,15 @@ impl UnsafeCommandBufferBuilder {
/// Does nothing if the list of regions is empty, as it would be a no-op and isn't a valid
/// usage of the command anyway.
#[inline]
pub unsafe fn blit_image<S, D, R>(
pub unsafe fn blit_image(
&mut self,
source: &S,
source: &dyn ImageAccess,
source_layout: ImageLayout,
destination: &D,
destination: &dyn ImageAccess,
destination_layout: ImageLayout,
regions: R,
regions: impl IntoIterator<Item = UnsafeCommandBufferBuilderImageBlit>,
filter: Filter,
) where
S: ?Sized + ImageAccess,
D: ?Sized + ImageAccess,
R: IntoIterator<Item = UnsafeCommandBufferBuilderImageBlit>,
{
) {
let source_aspects = source.format().aspects();
if let (Some(source_type), Some(destination_type)) = (
@ -703,11 +695,11 @@ impl UnsafeCommandBufferBuilder {
/// Does nothing if the list of attachments or the list of rects is empty, as it would be a
/// no-op and isn't a valid usage of the command anyway.
#[inline]
pub unsafe fn clear_attachments<A, R>(&mut self, attachments: A, rects: R)
where
A: IntoIterator<Item = ClearAttachment>,
R: IntoIterator<Item = ClearRect>,
{
pub unsafe fn clear_attachments(
&mut self,
attachments: impl IntoIterator<Item = ClearAttachment>,
rects: impl IntoIterator<Item = ClearRect>,
) {
let attachments: SmallVec<[_; 3]> = attachments.into_iter().map(|v| v.into()).collect();
let rects: SmallVec<[_; 4]> = rects
.into_iter()
@ -753,16 +745,13 @@ impl UnsafeCommandBufferBuilder {
/// Does nothing if the list of regions is empty, as it would be a no-op and isn't a valid
/// usage of the command anyway.
// TODO: ClearValue could be more precise
pub unsafe fn clear_color_image<I, R>(
pub unsafe fn clear_color_image(
&mut self,
image: &I,
image: &dyn ImageAccess,
layout: ImageLayout,
color: ClearValue,
regions: R,
) where
I: ?Sized + ImageAccess,
R: IntoIterator<Item = UnsafeCommandBufferBuilderColorImageClear>,
{
regions: impl IntoIterator<Item = UnsafeCommandBufferBuilderColorImageClear>,
) {
let image_aspects = image.format().aspects();
debug_assert!(image_aspects.color && !image_aspects.plane0);
debug_assert!(image.format().compression().is_none());
@ -822,16 +811,13 @@ impl UnsafeCommandBufferBuilder {
///
/// Does nothing if the list of regions is empty, as it would be a no-op and isn't a valid
/// usage of the command anyway.
pub unsafe fn clear_depth_stencil_image<I, R>(
pub unsafe fn clear_depth_stencil_image(
&mut self,
image: &I,
image: &dyn ImageAccess,
layout: ImageLayout,
clear_value: ClearValue,
regions: R,
) where
I: ?Sized + ImageAccess,
R: IntoIterator<Item = UnsafeCommandBufferBuilderDepthStencilImageClear>,
{
regions: impl IntoIterator<Item = UnsafeCommandBufferBuilderDepthStencilImageClear>,
) {
let image_aspects = image.format().aspects();
debug_assert!((image_aspects.depth || image_aspects.stencil) && !image_aspects.plane0);
debug_assert!(image.format().compression().is_none());
@ -911,12 +897,12 @@ impl UnsafeCommandBufferBuilder {
/// Does nothing if the list of regions is empty, as it would be a no-op and isn't a valid
/// usage of the command anyway.
#[inline]
pub unsafe fn copy_buffer<S, D, R>(&mut self, source: &S, destination: &D, regions: R)
where
S: ?Sized + BufferAccess,
D: ?Sized + BufferAccess,
R: IntoIterator<Item = (DeviceSize, DeviceSize, DeviceSize)>,
{
pub unsafe fn copy_buffer(
&mut self,
source: &dyn BufferAccess,
destination: &dyn BufferAccess,
regions: impl IntoIterator<Item = (DeviceSize, DeviceSize, DeviceSize)>,
) {
// TODO: debug assert that there's no overlap in the destinations?
let source = source.inner();
@ -956,17 +942,13 @@ impl UnsafeCommandBufferBuilder {
/// Does nothing if the list of regions is empty, as it would be a no-op and isn't a valid
/// usage of the command anyway.
#[inline]
pub unsafe fn copy_buffer_to_image<S, D, R>(
pub unsafe fn copy_buffer_to_image(
&mut self,
source: &S,
destination: &D,
source: &dyn BufferAccess,
destination: &dyn ImageAccess,
destination_layout: ImageLayout,
regions: R,
) where
S: ?Sized + BufferAccess,
D: ?Sized + ImageAccess,
R: IntoIterator<Item = UnsafeCommandBufferBuilderBufferImageCopy>,
{
regions: impl IntoIterator<Item = UnsafeCommandBufferBuilderBufferImageCopy>,
) {
let source = source.inner();
debug_assert!(source.offset < source.buffer.size());
debug_assert!(source.buffer.usage().transfer_source);
@ -1031,17 +1013,13 @@ impl UnsafeCommandBufferBuilder {
/// Does nothing if the list of regions is empty, as it would be a no-op and isn't a valid
/// usage of the command anyway.
#[inline]
pub unsafe fn copy_image_to_buffer<S, D, R>(
pub unsafe fn copy_image_to_buffer(
&mut self,
source: &S,
source: &dyn ImageAccess,
source_layout: ImageLayout,
destination: &D,
regions: R,
) where
S: ?Sized + ImageAccess,
D: ?Sized + BufferAccess,
R: IntoIterator<Item = UnsafeCommandBufferBuilderBufferImageCopy>,
{
destination: &dyn BufferAccess,
regions: impl IntoIterator<Item = UnsafeCommandBufferBuilderBufferImageCopy>,
) {
debug_assert_eq!(source.samples(), SampleCount::Sample1);
let source = source.inner();
debug_assert!(source.image.usage().transfer_source);
@ -1116,8 +1094,8 @@ impl UnsafeCommandBufferBuilder {
let range = queries.range();
debug_assert!(destination.offset < destination.buffer.size());
debug_assert!(destination.buffer.usage().transfer_destination);
debug_assert!(destination.offset % std::mem::size_of::<T>() as DeviceSize == 0);
debug_assert!(stride % std::mem::size_of::<T>() as DeviceSize == 0);
debug_assert!(destination.offset % size_of::<T>() as DeviceSize == 0);
debug_assert!(stride % size_of::<T>() as DeviceSize == 0);
let fns = self.device().fns();
let cmd = self.internal_object();
@ -1155,10 +1133,7 @@ impl UnsafeCommandBufferBuilder {
/// Calls `vkCmdDispatchIndirect` on the builder.
#[inline]
pub unsafe fn dispatch_indirect<B>(&mut self, buffer: &B)
where
B: ?Sized + BufferAccess,
{
pub unsafe fn dispatch_indirect(&mut self, buffer: &dyn BufferAccess) {
let fns = self.device().fns();
let cmd = self.internal_object();
@ -1215,17 +1190,19 @@ impl UnsafeCommandBufferBuilder {
/// Calls `vkCmdDrawIndirect` on the builder.
#[inline]
pub unsafe fn draw_indirect<B>(&mut self, buffer: &B, draw_count: u32, stride: u32)
where
B: ?Sized + BufferAccess,
{
pub unsafe fn draw_indirect(
&mut self,
buffer: &dyn BufferAccess,
draw_count: u32,
stride: u32,
) {
let fns = self.device().fns();
let cmd = self.internal_object();
debug_assert!(
draw_count == 0
|| ((stride % 4) == 0)
&& stride as usize >= mem::size_of::<ash::vk::DrawIndirectCommand>()
&& stride as usize >= size_of::<ash::vk::DrawIndirectCommand>()
);
let inner = buffer.inner();
@ -1243,10 +1220,12 @@ impl UnsafeCommandBufferBuilder {
/// Calls `vkCmdDrawIndexedIndirect` on the builder.
#[inline]
pub unsafe fn draw_indexed_indirect<B>(&mut self, buffer: &B, draw_count: u32, stride: u32)
where
B: ?Sized + BufferAccess,
{
pub unsafe fn draw_indexed_indirect(
&mut self,
buffer: &dyn BufferAccess,
draw_count: u32,
stride: u32,
) {
let fns = self.device().fns();
let cmd = self.internal_object();
@ -1314,10 +1293,7 @@ impl UnsafeCommandBufferBuilder {
/// Calls `vkCmdFillBuffer` on the builder.
#[inline]
pub unsafe fn fill_buffer<B>(&mut self, buffer: &B, data: u32)
where
B: ?Sized + BufferAccess,
{
pub unsafe fn fill_buffer(&mut self, buffer: &dyn BufferAccess, data: u32) {
let fns = self.device().fns();
let cmd = self.internal_object();
@ -1413,7 +1389,7 @@ impl UnsafeCommandBufferBuilder {
size: u32,
data: &D,
) where
D: ?Sized,
D: BufferContents + ?Sized,
{
let fns = self.device().fns();
let cmd = self.internal_object();
@ -1422,7 +1398,7 @@ impl UnsafeCommandBufferBuilder {
debug_assert!(size > 0);
debug_assert_eq!(size % 4, 0);
debug_assert_eq!(offset % 4, 0);
debug_assert!(mem::size_of_val(data) >= size as usize);
debug_assert!(size_of_val(data) >= size as usize);
fns.v1_0.cmd_push_constants(
cmd,
@ -1430,7 +1406,7 @@ impl UnsafeCommandBufferBuilder {
stages.into(),
offset as u32,
size as u32,
data as *const D as *const _,
data.as_bytes().as_ptr() as *const _,
);
}
@ -1536,10 +1512,7 @@ impl UnsafeCommandBufferBuilder {
///
/// If the list is empty then the command is automatically ignored.
#[inline]
pub unsafe fn set_color_write_enable<I>(&mut self, enables: I)
where
I: IntoIterator<Item = bool>,
{
pub unsafe fn set_color_write_enable(&mut self, enables: impl IntoIterator<Item = bool>) {
debug_assert!(self.device().enabled_extensions().ext_color_write_enable);
debug_assert!(self.device().enabled_features().color_write_enable);
@ -1705,10 +1678,11 @@ impl UnsafeCommandBufferBuilder {
///
/// If the list is empty then the command is automatically ignored.
#[inline]
pub unsafe fn set_discard_rectangle<I>(&mut self, first_rectangle: u32, rectangles: I)
where
I: IntoIterator<Item = Scissor>,
{
pub unsafe fn set_discard_rectangle(
&mut self,
first_rectangle: u32,
rectangles: impl IntoIterator<Item = Scissor>,
) {
debug_assert!(self.device().enabled_extensions().ext_discard_rectangles);
let rectangles = rectangles
@ -1991,10 +1965,11 @@ impl UnsafeCommandBufferBuilder {
///
/// If the list is empty then the command is automatically ignored.
#[inline]
pub unsafe fn set_scissor<I>(&mut self, first_scissor: u32, scissors: I)
where
I: IntoIterator<Item = Scissor>,
{
pub unsafe fn set_scissor(
&mut self,
first_scissor: u32,
scissors: impl IntoIterator<Item = Scissor>,
) {
let scissors = scissors
.into_iter()
.map(|v| ash::vk::Rect2D::from(v.clone()))
@ -2029,10 +2004,7 @@ impl UnsafeCommandBufferBuilder {
///
/// If the list is empty then the command is automatically ignored.
#[inline]
pub unsafe fn set_scissor_with_count<I>(&mut self, scissors: I)
where
I: IntoIterator<Item = Scissor>,
{
pub unsafe fn set_scissor_with_count(&mut self, scissors: impl IntoIterator<Item = Scissor>) {
let scissors = scissors
.into_iter()
.map(|v| ash::vk::Rect2D::from(v.clone()))
@ -2075,10 +2047,11 @@ impl UnsafeCommandBufferBuilder {
///
/// If the list is empty then the command is automatically ignored.
#[inline]
pub unsafe fn set_viewport<I>(&mut self, first_viewport: u32, viewports: I)
where
I: IntoIterator<Item = Viewport>,
{
pub unsafe fn set_viewport(
&mut self,
first_viewport: u32,
viewports: impl IntoIterator<Item = Viewport>,
) {
let viewports = viewports
.into_iter()
.map(|v| v.clone().into())
@ -2110,10 +2083,10 @@ impl UnsafeCommandBufferBuilder {
///
/// If the list is empty then the command is automatically ignored.
#[inline]
pub unsafe fn set_viewport_with_count<I>(&mut self, viewports: I)
where
I: IntoIterator<Item = Viewport>,
{
pub unsafe fn set_viewport_with_count(
&mut self,
viewports: impl IntoIterator<Item = Viewport>,
) {
let viewports = viewports
.into_iter()
.map(|v| v.clone().into())
@ -2147,10 +2120,9 @@ impl UnsafeCommandBufferBuilder {
/// Calls `vkCmdUpdateBuffer` on the builder.
#[inline]
pub unsafe fn update_buffer<B, D>(&mut self, buffer: &B, data: &D)
pub unsafe fn update_buffer<D>(&mut self, buffer: &dyn BufferAccess, data: &D)
where
B: ?Sized + BufferAccess,
D: ?Sized,
D: BufferContents + ?Sized,
{
let fns = self.device().fns();
let cmd = self.internal_object();
@ -2158,7 +2130,7 @@ impl UnsafeCommandBufferBuilder {
let size = buffer.size();
debug_assert_eq!(size % 4, 0);
debug_assert!(size <= 65536);
debug_assert!(size <= mem::size_of_val(data) as DeviceSize);
debug_assert!(size <= size_of_val(data) as DeviceSize);
let (buffer_handle, offset) = {
let BufferInner {
@ -2175,7 +2147,7 @@ impl UnsafeCommandBufferBuilder {
buffer_handle,
offset,
size,
data as *const D as *const _,
data.as_bytes().as_ptr() as *const _,
);
}
@ -2353,10 +2325,7 @@ impl UnsafeCommandBufferBuilderBindVertexBuffer {
/// Adds a buffer to the list.
#[inline]
pub fn add<B>(&mut self, buffer: &B)
where
B: ?Sized + BufferAccess,
{
pub fn add(&mut self, buffer: &dyn BufferAccess) {
let inner = buffer.inner();
debug_assert!(inner.buffer.usage().vertex_buffer);
self.raw_buffers.push(inner.buffer.internal_object());
@ -2587,9 +2556,9 @@ impl UnsafeCommandBufferBuilderPipelineBarrier {
/// is added.
/// - Queue ownership transfers must be correct.
///
pub unsafe fn add_buffer_memory_barrier<B>(
pub unsafe fn add_buffer_memory_barrier(
&mut self,
buffer: &B,
buffer: &dyn BufferAccess,
source_stage: PipelineStages,
source_access: AccessFlags,
destination_stage: PipelineStages,
@ -2598,9 +2567,7 @@ impl UnsafeCommandBufferBuilderPipelineBarrier {
queue_transfer: Option<(u32, u32)>,
offset: DeviceSize,
size: DeviceSize,
) where
B: ?Sized + BufferAccess,
{
) {
debug_assert!(source_stage.supported_access().contains(&source_access));
debug_assert!(destination_stage
.supported_access()
@ -2650,9 +2617,9 @@ impl UnsafeCommandBufferBuilderPipelineBarrier {
/// - Image layouts transfers must be correct.
/// - Access flags must be compatible with the image usage flags passed at image creation.
///
pub unsafe fn add_image_memory_barrier<I>(
pub unsafe fn add_image_memory_barrier(
&mut self,
image: &I,
image: &dyn ImageAccess,
mip_levels: Range<u32>,
array_layers: Range<u32>,
source_stage: PipelineStages,
@ -2663,9 +2630,7 @@ impl UnsafeCommandBufferBuilderPipelineBarrier {
queue_transfer: Option<(u32, u32)>,
current_layout: ImageLayout,
new_layout: ImageLayout,
) where
I: ?Sized + ImageAccess,
{
) {
debug_assert!(source_stage.supported_access().contains(&source_access));
debug_assert!(destination_stage
.supported_access()

View File

@ -8,13 +8,12 @@
// according to those terms.
use super::ranges::is_overlapping_ranges;
use crate::buffer::TypedBufferAccess;
use crate::device::Device;
use crate::device::DeviceOwned;
use crate::DeviceSize;
use crate::VulkanObject;
use std::error;
use std::fmt;
use crate::{
buffer::BufferAccess,
device::{Device, DeviceOwned},
DeviceSize, VulkanObject,
};
use std::{error, fmt};
/// Checks whether a copy buffer command is valid.
///
@ -22,19 +21,14 @@ use std::fmt;
///
/// - Panics if the source and destination were not created with `device`.
///
pub fn check_copy_buffer<S, D, T>(
pub fn check_copy_buffer(
device: &Device,
source: &S,
destination: &D,
source: &dyn BufferAccess,
destination: &dyn BufferAccess,
source_offset: DeviceSize,
destination_offset: DeviceSize,
size: DeviceSize,
) -> Result<(), CheckCopyBufferError>
where
S: ?Sized + TypedBufferAccess<Content = T>,
D: ?Sized + TypedBufferAccess<Content = T>,
T: ?Sized,
{
) -> Result<(), CheckCopyBufferError> {
assert_eq!(
source.inner().buffer.device().internal_object(),
device.internal_object()

View File

@ -7,19 +7,14 @@
// notice may not be copied, modified, or distributed except
// according to those terms.
use crate::buffer::TypedBufferAccess;
use crate::device::Device;
use crate::device::DeviceOwned;
use crate::format::Format;
use crate::format::IncompatiblePixelsType;
use crate::format::Pixel;
use crate::image::ImageAccess;
use crate::image::ImageDimensions;
use crate::image::SampleCount;
use crate::DeviceSize;
use crate::VulkanObject;
use std::error;
use std::fmt;
use crate::{
buffer::BufferAccess,
device::{Device, DeviceOwned},
format::Format,
image::{ImageAccess, ImageDimensions, SampleCount},
DeviceSize, VulkanObject,
};
use std::{error, fmt};
/// Type of operation to check.
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
@ -35,22 +30,17 @@ pub enum CheckCopyBufferImageTy {
///
/// - Panics if the buffer and image were not created with `device`.
///
pub fn check_copy_buffer_image<B, I, Px>(
pub fn check_copy_buffer_image(
device: &Device,
buffer: &B,
image: &I,
buffer: &dyn BufferAccess,
image: &dyn ImageAccess,
ty: CheckCopyBufferImageTy,
image_offset: [u32; 3],
image_size: [u32; 3],
image_first_layer: u32,
image_num_layers: u32,
image_mipmap: u32,
) -> Result<(), CheckCopyBufferImageError>
where
I: ?Sized + ImageAccess,
B: ?Sized + TypedBufferAccess<Content = [Px]>,
Px: Pixel, // TODO: use a trait on the image itself instead
{
) -> Result<(), CheckCopyBufferImageError> {
let buffer_inner = buffer.inner();
let image_inner = image.inner();
@ -133,18 +123,13 @@ where
}
}
Px::ensure_accepts(image.format())?;
{
let required_len =
required_len_for_format::<Px>(image.format(), image_size, image_num_layers);
if required_len > buffer.len() {
let required_size = required_size_for_format(image.format(), image_size, image_num_layers);
if required_size > buffer.size() {
return Err(CheckCopyBufferImageError::BufferTooSmall {
required_len,
actual_len: buffer.len(),
required_size,
actual_size: buffer.size(),
});
}
}
// TODO: check memory overlap?
@ -153,67 +138,62 @@ where
/// Computes the minimum required len in elements for buffer with image data in specified
/// format of specified size.
fn required_len_for_format<Px>(
format: Format,
image_size: [u32; 3],
image_num_layers: u32,
) -> DeviceSize
where
Px: Pixel,
{
let [block_width, block_height, _block_depth] = format.block_extent();
let num_blocks = (image_size[0] + block_width - 1) / block_width
* ((image_size[1] + block_height - 1) / block_height)
* image_size[2]
* image_num_layers;
let required_len = num_blocks as DeviceSize * Px::rate(format) as DeviceSize;
return required_len;
fn required_size_for_format(format: Format, extent: [u32; 3], layer_count: u32) -> DeviceSize {
let num_blocks = extent
.into_iter()
.zip(format.block_extent())
.map(|(extent, block_extent)| {
let extent = extent as DeviceSize;
let block_extent = block_extent as DeviceSize;
(extent + block_extent - 1) / block_extent
})
.product::<DeviceSize>()
* layer_count as DeviceSize;
let block_size = format
.block_size()
.expect("this format cannot accept pixels");
num_blocks * block_size
}
#[cfg(test)]
mod tests {
use crate::command_buffer::validity::copy_image_buffer::required_len_for_format;
use crate::command_buffer::validity::copy_image_buffer::required_size_for_format;
use crate::format::Format;
#[test]
fn test_required_len_for_format() {
// issue #1292
assert_eq!(
required_len_for_format::<u8>(Format::BC1_RGB_UNORM_BLOCK, [2048, 2048, 1], 1),
required_size_for_format(Format::BC1_RGB_UNORM_BLOCK, [2048, 2048, 1], 1),
2097152
);
// other test cases
assert_eq!(
required_len_for_format::<u8>(Format::R8G8B8A8_UNORM, [2048, 2048, 1], 1),
required_size_for_format(Format::R8G8B8A8_UNORM, [2048, 2048, 1], 1),
16777216
);
assert_eq!(
required_len_for_format::<u8>(Format::R4G4_UNORM_PACK8, [512, 512, 1], 1),
required_size_for_format(Format::R4G4_UNORM_PACK8, [512, 512, 1], 1),
262144
);
assert_eq!(
required_len_for_format::<u8>(Format::R8G8B8_USCALED, [512, 512, 1], 1),
required_size_for_format(Format::R8G8B8_USCALED, [512, 512, 1], 1),
786432
);
assert_eq!(
required_len_for_format::<u8>(Format::R32G32_UINT, [512, 512, 1], 1),
required_size_for_format(Format::R32G32_UINT, [512, 512, 1], 1),
2097152
);
assert_eq!(
required_len_for_format::<u32>(Format::R32G32_UINT, [512, 512, 1], 1),
524288
required_size_for_format(Format::R32G32_UINT, [512, 512, 1], 1),
2097152
);
assert_eq!(
required_len_for_format::<[u32; 2]>(Format::R32G32_UINT, [512, 512, 1], 1),
262144
);
assert_eq!(
required_len_for_format::<u8>(Format::ASTC_8x8_UNORM_BLOCK, [512, 512, 1], 1),
required_size_for_format(Format::ASTC_8x8_UNORM_BLOCK, [512, 512, 1], 1),
65536
);
assert_eq!(
required_len_for_format::<u8>(Format::ASTC_12x12_SRGB_BLOCK, [512, 512, 1], 1),
required_size_for_format(Format::ASTC_12x12_SRGB_BLOCK, [512, 512, 1], 1),
29584
);
}
@ -232,25 +212,16 @@ pub enum CheckCopyBufferImageError {
UnexpectedMultisampled,
/// The image coordinates are out of range.
ImageCoordinatesOutOfRange,
/// The type of pixels in the buffer isn't compatible with the image format.
WrongPixelType(IncompatiblePixelsType),
/// The buffer is too small for the copy operation.
BufferTooSmall {
/// Required number of elements in the buffer.
required_len: DeviceSize,
/// Actual number of elements in the buffer.
actual_len: DeviceSize,
/// Required size of the buffer.
required_size: DeviceSize,
/// Actual size of the buffer.
actual_size: DeviceSize,
},
}
impl error::Error for CheckCopyBufferImageError {
fn source(&self) -> Option<&(dyn error::Error + 'static)> {
match *self {
CheckCopyBufferImageError::WrongPixelType(ref err) => Some(err),
_ => None,
}
}
}
impl error::Error for CheckCopyBufferImageError {}
impl fmt::Display for CheckCopyBufferImageError {
#[inline]
@ -274,9 +245,6 @@ impl fmt::Display for CheckCopyBufferImageError {
CheckCopyBufferImageError::ImageCoordinatesOutOfRange => {
"the image coordinates are out of range"
}
CheckCopyBufferImageError::WrongPixelType(_) => {
"the type of pixels in the buffer isn't compatible with the image format"
}
CheckCopyBufferImageError::BufferTooSmall { .. } => {
"the buffer is too small for the copy operation"
}
@ -284,10 +252,3 @@ impl fmt::Display for CheckCopyBufferImageError {
)
}
}
impl From<IncompatiblePixelsType> for CheckCopyBufferImageError {
#[inline]
fn from(err: IncompatiblePixelsType) -> CheckCopyBufferImageError {
CheckCopyBufferImageError::WrongPixelType(err)
}
}

View File

@ -15,13 +15,10 @@ use std::error;
use std::fmt;
/// Checks whether an indirect buffer can be bound.
pub fn check_indirect_buffer<Inb>(
pub fn check_indirect_buffer(
device: &Device,
buffer: &Inb,
) -> Result<(), CheckIndirectBufferError>
where
Inb: BufferAccess + 'static,
{
buffer: &dyn BufferAccess,
) -> Result<(), CheckIndirectBufferError> {
assert_eq!(
buffer.inner().buffer.device().internal_object(),
device.internal_object()

View File

@ -7,15 +7,12 @@
// notice may not be copied, modified, or distributed except
// according to those terms.
use crate::buffer::TypedBufferAccess;
use crate::device::Device;
use crate::device::DeviceOwned;
use crate::DeviceSize;
use crate::VulkanObject;
use std::cmp;
use std::error;
use std::fmt;
use std::mem;
use crate::{
buffer::BufferAccess,
device::{Device, DeviceOwned},
DeviceSize, VulkanObject,
};
use std::{error, fmt, mem::size_of_val};
/// Checks whether an update buffer command is valid.
///
@ -23,13 +20,12 @@ use std::mem;
///
/// - Panics if the buffer not created with `device`.
///
pub fn check_update_buffer<B, D>(
pub fn check_update_buffer<D>(
device: &Device,
buffer: &B,
buffer: &dyn BufferAccess,
data: &D,
) -> Result<(), CheckUpdateBufferError>
where
B: ?Sized + TypedBufferAccess<Content = D>,
D: ?Sized,
{
assert_eq!(
@ -45,7 +41,7 @@ where
return Err(CheckUpdateBufferError::WrongAlignment);
}
let size = cmp::min(buffer.size(), mem::size_of_val(data) as DeviceSize);
let size = buffer.size().min(size_of_val(data) as DeviceSize);
if size % 4 != 0 {
return Err(CheckUpdateBufferError::WrongAlignment);

View File

@ -92,13 +92,10 @@
//! behaves as a regular image, and even has its own format, which can be queried with the `plane`
//! method on a format.
use crate::device::physical::PhysicalDevice;
use crate::image::ImageAspects;
use crate::shader::spirv::ImageFormat;
use crate::DeviceSize;
use half::f16;
use std::vec::IntoIter as VecIntoIter;
use std::{error, fmt, mem, ops::BitOr};
use crate::{
device::physical::PhysicalDevice, image::ImageAspects, shader::spirv::ImageFormat, DeviceSize,
};
use std::{ops::BitOr, vec::IntoIter as VecIntoIter};
// Generated by build.rs
include!(concat!(env!("OUT_DIR"), "/formats.rs"));
@ -404,69 +401,6 @@ pub(crate) enum FormatCompatibilityInner {
Class_16bit_2plane_444,
}
/// Trait for Rust types that can represent a pixel in an image.
pub unsafe trait Pixel {
/// Returns an error if `Self` cannot be used as a source of pixels for `format`.
fn ensure_accepts(format: Format) -> Result<(), IncompatiblePixelsType>;
/// The number of `Self`s which make up a single pixel.
///
/// # Panics
///
/// May panic if `ensure_accepts` would not return `Ok(())`.
fn rate(format: Format) -> u32;
}
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub struct IncompatiblePixelsType;
impl error::Error for IncompatiblePixelsType {}
impl fmt::Display for IncompatiblePixelsType {
#[inline]
fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
write!(
fmt,
"{}",
"supplied pixels' type is incompatible with this format"
)
}
}
macro_rules! impl_pixel {
{$($ty:ty;)+} => {
$(impl_pixel!(inner $ty);)*
$(impl_pixel!(inner [$ty; 1]);)*
$(impl_pixel!(inner [$ty; 2]);)*
$(impl_pixel!(inner [$ty; 3]);)*
$(impl_pixel!(inner [$ty; 4]);)*
$(impl_pixel!(inner ($ty,));)*
$(impl_pixel!(inner ($ty, $ty));)*
$(impl_pixel!(inner ($ty, $ty, $ty));)*
$(impl_pixel!(inner ($ty, $ty, $ty, $ty));)*
};
(inner $ty:ty) => {
unsafe impl Pixel for $ty {
fn ensure_accepts(format: Format) -> Result<(), IncompatiblePixelsType> {
// TODO: Be more strict: accept only if the format has a matching AcceptsPixels impl.
if format.block_size().map_or(false, |x| x % mem::size_of::<$ty>() as DeviceSize == 0) {
Ok(())
} else {
Err(IncompatiblePixelsType)
}
}
fn rate(format: Format) -> u32 {
(format.block_size().expect("this format cannot accept pixels") / mem::size_of::<$ty>() as DeviceSize) as u32
}
}
}
}
impl_pixel! {
u8; i8; u16; i16; u32; i32; u64; i64; f16; f32; f64;
}
/// Describes a uniform value that will be used to fill an image.
// TODO: should have the same layout as `vk::ClearValue` for performance
#[derive(Debug, Copy, Clone, PartialEq)]

View File

@ -554,7 +554,7 @@ impl AttachmentImage {
/// Return the size of the allocated memory (used for e.g. with cuda)
pub fn mem_size(&self) -> DeviceSize {
self.memory.memory().size()
self.memory.memory().allocation_size()
}
}

View File

@ -7,49 +7,38 @@
// notice may not be copied, modified, or distributed except
// according to those terms.
use crate::buffer::BufferUsage;
use crate::buffer::CpuAccessibleBuffer;
use crate::buffer::TypedBufferAccess;
use crate::command_buffer::AutoCommandBufferBuilder;
use crate::command_buffer::CommandBufferExecFuture;
use crate::command_buffer::CommandBufferUsage;
use crate::command_buffer::PrimaryAutoCommandBuffer;
use crate::command_buffer::PrimaryCommandBuffer;
use crate::device::physical::QueueFamily;
use crate::device::Device;
use crate::device::Queue;
use crate::format::Format;
use crate::format::Pixel;
use crate::image::sys::ImageCreationError;
use crate::image::sys::UnsafeImage;
use crate::image::sys::UnsafeImageCreateInfo;
use crate::image::traits::ImageAccess;
use crate::image::traits::ImageContent;
use crate::image::ImageCreateFlags;
use crate::image::ImageDescriptorLayouts;
use crate::image::ImageDimensions;
use crate::image::ImageInner;
use crate::image::ImageLayout;
use crate::image::ImageUsage;
use crate::image::MipmapsCount;
use crate::memory::pool::AllocFromRequirementsFilter;
use crate::memory::pool::AllocLayout;
use crate::memory::pool::MappingRequirement;
use crate::memory::pool::MemoryPool;
use crate::memory::pool::MemoryPoolAlloc;
use crate::memory::pool::PotentialDedicatedAllocation;
use crate::memory::pool::StdMemoryPoolAlloc;
use crate::memory::DedicatedAllocation;
use crate::sampler::Filter;
use crate::sync::AccessError;
use crate::sync::NowFuture;
use crate::sync::Sharing;
use super::{
sys::UnsafeImage, traits::ImageContent, ImageAccess, ImageCreateFlags, ImageCreationError,
ImageDescriptorLayouts, ImageDimensions, ImageInner, ImageLayout, ImageUsage, MipmapsCount,
};
use crate::{
buffer::{BufferAccess, BufferContents, BufferUsage, CpuAccessibleBuffer},
command_buffer::{
AutoCommandBufferBuilder, CommandBufferExecFuture, CommandBufferUsage,
PrimaryAutoCommandBuffer, PrimaryCommandBuffer,
},
device::{physical::QueueFamily, Device, Queue},
format::Format,
image::sys::UnsafeImageCreateInfo,
memory::{
pool::{
AllocFromRequirementsFilter, AllocLayout, MappingRequirement, MemoryPoolAlloc,
PotentialDedicatedAllocation, StdMemoryPoolAlloc,
},
DedicatedAllocation, MemoryPool,
},
sampler::Filter,
sync::{AccessError, NowFuture, Sharing},
};
use smallvec::SmallVec;
use std::hash::Hash;
use std::hash::Hasher;
use std::sync::atomic::AtomicBool;
use std::sync::atomic::Ordering;
use std::sync::Arc;
use std::{
hash::{Hash, Hasher},
ops::Range,
sync::{
atomic::{AtomicBool, Ordering},
Arc,
},
};
/// Image whose purpose is to be used for read-only purposes. You can write to the image once,
/// but then you must only ever read from it.
@ -72,8 +61,8 @@ pub struct ImmutableImage<A = PotentialDedicatedAllocation<StdMemoryPoolAlloc>>
/// The layout must be the layout of the image at the beginning and at the end of the command buffer
pub struct SubImage {
image: Arc<dyn ImageAccess>,
mip_levels_access: std::ops::Range<u32>,
array_layers_access: std::ops::Range<u32>,
mip_levels_access: Range<u32>,
array_layers_access: Range<u32>,
layout: ImageLayout,
}
@ -319,7 +308,7 @@ impl ImmutableImage {
ImageCreationError,
>
where
Px: Pixel + Send + Sync + Clone + 'static,
[Px]: BufferContents,
I: IntoIterator<Item = Px>,
I::IntoIter: ExactSizeIterator,
{
@ -333,8 +322,8 @@ impl ImmutableImage {
}
/// Construct an ImmutableImage containing a copy of the data in `source`.
pub fn from_buffer<B, Px>(
source: Arc<B>,
pub fn from_buffer(
source: Arc<dyn BufferAccess>,
dimensions: ImageDimensions,
mip_levels: MipmapsCount,
format: Format,
@ -345,11 +334,7 @@ impl ImmutableImage {
CommandBufferExecFuture<NowFuture, PrimaryAutoCommandBuffer>,
),
ImageCreationError,
>
where
B: TypedBufferAccess<Content = [Px]> + 'static,
Px: Pixel + Send + Sync + Clone + 'static,
{
> {
let need_to_generate_mipmaps = has_mipmaps(mip_levels);
let usage = ImageUsage {
transfer_destination: true,

View File

@ -250,7 +250,7 @@ impl StorageImage {
/// Return the size of the allocated memory (used for e.g. with cuda)
pub fn mem_size(&self) -> DeviceSize {
self.memory.memory().size()
self.memory.memory().allocation_size()
}
}

View File

@ -941,7 +941,7 @@ impl UnsafeImage {
);
let mem_reqs = mem_reqs.assume_init();
mem_reqs.size <= memory.size() - offset
mem_reqs.size <= memory.allocation_size() - offset
&& offset % mem_reqs.alignment == 0
&& mem_reqs.memory_type_bits & (1 << memory.memory_type().id()) != 0
});

View File

@ -64,11 +64,11 @@
pub use ash::vk::Handle;
pub use half;
use std::error;
use std::fmt;
use std::ops::Deref;
use std::sync::Arc;
use std::sync::MutexGuard;
use std::{
error, fmt,
ops::Deref,
sync::{Arc, MutexGuard},
};
pub use version::Version;
#[macro_use]

View File

@ -7,7 +7,7 @@
// notice may not be copied, modified, or distributed except
// according to those terms.
use super::{Content, DedicatedAllocation};
use super::DedicatedAllocation;
use crate::{
check_errors,
device::{physical::MemoryType, Device, DeviceOwned},
@ -20,8 +20,8 @@ use std::{
fs::File,
hash::{Hash, Hasher},
mem::MaybeUninit,
ops::{BitOr, Deref, DerefMut, Range},
ptr,
ops::{BitOr, Range},
ptr, slice,
sync::{Arc, Mutex},
};
@ -97,22 +97,6 @@ impl DeviceMemory {
})
}
/// Allocates a block of memory from the device, and maps it to host memory.
///
/// # Panics
///
/// - Panics if `allocate_info.allocation_size` is 0.
/// - Panics if `allocate_info.dedicated_allocation` is `Some` and the contained buffer or
/// image does not belong to `device`.
/// - Panics if the memory type is not host-visible.
pub fn allocate_and_map(
device: Arc<Device>,
allocate_info: MemoryAllocateInfo,
) -> Result<MappedDeviceMemory, DeviceMemoryAllocationError> {
let device_memory = Self::allocate(device, allocate_info)?;
Self::map_allocation(device_memory.device().clone(), device_memory)
}
/// Imports a block of memory from an external source.
///
/// # Safety
@ -152,27 +136,6 @@ impl DeviceMemory {
})
}
/// Imports a block of memory from an external source, and maps it to host memory.
///
/// # Safety
///
/// - See the documentation of the variants of [`MemoryImportInfo`].
///
/// # Panics
///
/// - Panics if `allocate_info.allocation_size` is 0.
/// - Panics if `allocate_info.dedicated_allocation` is `Some` and the contained buffer or
/// image does not belong to `device`.
/// - Panics if the memory type is not host-visible.
pub unsafe fn import_and_map(
device: Arc<Device>,
allocate_info: MemoryAllocateInfo,
import_info: MemoryImportInfo,
) -> Result<MappedDeviceMemory, DeviceMemoryAllocationError> {
let device_memory = Self::import(device, allocate_info, import_info)?;
Self::map_allocation(device_memory.device().clone(), device_memory)
}
fn validate(
device: &Device,
allocate_info: &mut MemoryAllocateInfo,
@ -437,32 +400,6 @@ impl DeviceMemory {
Ok(handle)
}
fn map_allocation(
device: Arc<Device>,
mem: DeviceMemory,
) -> Result<MappedDeviceMemory, DeviceMemoryAllocationError> {
let fns = device.fns();
let coherent = mem.memory_type().is_host_coherent();
let ptr = unsafe {
let mut output = MaybeUninit::uninit();
check_errors(fns.v1_0.map_memory(
device.internal_object(),
mem.handle,
0,
mem.allocation_size,
ash::vk::MemoryMapFlags::empty(),
output.as_mut_ptr(),
))?;
output.assume_init()
};
Ok(MappedDeviceMemory {
memory: mem,
pointer: ptr,
coherent,
})
}
/// Returns the memory type that this memory was allocated from.
#[inline]
pub fn memory_type(&self) -> MemoryType {
@ -474,7 +411,7 @@ impl DeviceMemory {
/// Returns the size in bytes of the memory allocation.
#[inline]
pub fn size(&self) -> DeviceSize {
pub fn allocation_size(&self) -> DeviceSize {
self.allocation_size
}
@ -586,7 +523,7 @@ impl Hash for DeviceMemory {
}
/// Error type returned by functions related to `DeviceMemory`.
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum DeviceMemoryAllocationError {
/// Not enough memory available.
OomError(OomError),
@ -594,8 +531,8 @@ pub enum DeviceMemoryAllocationError {
/// The maximum number of allocations has been exceeded.
TooManyObjects,
/// Memory map failed.
MemoryMapFailed,
/// An error occurred when mapping the memory.
MemoryMapError(MemoryMapError),
ExtensionNotEnabled {
extension: &'static str,
@ -645,6 +582,7 @@ impl error::Error for DeviceMemoryAllocationError {
fn source(&self) -> Option<&(dyn error::Error + 'static)> {
match *self {
Self::OomError(ref err) => Some(err),
Self::MemoryMapError(ref err) => Some(err),
_ => None,
}
}
@ -658,7 +596,7 @@ impl fmt::Display for DeviceMemoryAllocationError {
Self::TooManyObjects => {
write!(fmt, "the maximum number of allocations has been exceeded")
}
Self::MemoryMapFailed => write!(fmt, "memory map failed"),
Self::MemoryMapError(_) => write!(fmt, "error occurred when mapping the memory"),
Self::ExtensionNotEnabled { extension, reason } => write!(
fmt,
"the extension {} must be enabled: {}",
@ -704,7 +642,6 @@ impl From<Error> for DeviceMemoryAllocationError {
match err {
e @ Error::OutOfHostMemory | e @ Error::OutOfDeviceMemory => Self::OomError(e.into()),
Error::TooManyObjects => Self::TooManyObjects,
Error::MemoryMapFailed => Self::MemoryMapFailed,
_ => panic!("unexpected error: {:?}", err),
}
}
@ -717,6 +654,13 @@ impl From<OomError> for DeviceMemoryAllocationError {
}
}
impl From<MemoryMapError> for DeviceMemoryAllocationError {
#[inline]
fn from(err: MemoryMapError) -> Self {
Self::MemoryMapError(err)
}
}
/// Parameters to allocate a new `DeviceMemory`.
#[derive(Clone, Debug)]
pub struct MemoryAllocateInfo<'d> {
@ -1111,18 +1055,15 @@ impl From<OomError> for DeviceMemoryExportError {
}
}
/// Represents memory that has been allocated and mapped in CPU accessible space.
/// Represents device memory that has been mapped in a CPU-accessible space.
///
/// Can be obtained with `DeviceMemory::alloc_and_map`. The function will panic if the memory type
/// is not host-accessible.
///
/// In order to access the content of the allocated memory, you can use the `read_write` method.
/// This method returns a guard object that derefs to the content.
/// In order to access the contents of the allocated memory, you can use the `read` and `write`
/// methods.
///
/// # Example
///
/// ```
/// use vulkano::memory::{DeviceMemory, MemoryAllocateInfo};
/// use vulkano::memory::{DeviceMemory, MappedDeviceMemory, MemoryAllocateInfo};
///
/// # let device: std::sync::Arc<vulkano::device::Device> = return;
/// // The memory type must be mappable.
@ -1131,7 +1072,7 @@ impl From<OomError> for DeviceMemoryExportError {
/// .next().unwrap(); // Vk specs guarantee that this can't fail
///
/// // Allocates 1KB of memory.
/// let memory = DeviceMemory::allocate_and_map(
/// let memory = DeviceMemory::allocate(
/// device.clone(),
/// MemoryAllocateInfo {
/// allocation_size: 1024,
@ -1139,17 +1080,22 @@ impl From<OomError> for DeviceMemoryExportError {
/// ..Default::default()
/// },
/// ).unwrap();
/// let mapped_memory = MappedDeviceMemory::new(memory, 0..1024).unwrap();
///
/// // Get access to the content. Note that this is very unsafe for two reasons: 1) the content is
/// // uninitialized, and 2) the access is unsynchronized.
/// // Get access to the content.
/// // Note that this is very unsafe because the access is unsynchronized.
/// unsafe {
/// let mut content = memory.read_write::<[u8]>(0 .. 1024);
/// content[12] = 54; // `content` derefs to a `&[u8]` or a `&mut [u8]`
/// let content = mapped_memory.write(0..1024).unwrap();
/// content[12] = 54;
/// }
/// ```
#[derive(Debug)]
pub struct MappedDeviceMemory {
memory: DeviceMemory,
pointer: *mut c_void,
pointer: *mut c_void, // points to `range.start`
range: Range<DeviceSize>,
atom_size: DeviceSize,
coherent: bool,
}
@ -1161,6 +1107,78 @@ pub struct MappedDeviceMemory {
//
impl MappedDeviceMemory {
/// Maps a range of memory to be accessed by the CPU.
///
/// `memory` must be allocated from host-visible memory.
///
/// `range` is specified in bytes relative to the start of the memory allocation, and must fall
/// within the range of the allocation (`0..allocation_size`). If `memory` was not allocated
/// from host-coherent memory, then the start and end of `range` must be a multiple of the
/// [`non_coherent_atom_size`](crate::device::Properties::non_coherent_atom_size) device
/// property, but `range.end` can also the memory's `allocation_size`.
///
/// # Panics
///
/// - Panics if `range` is empty.
pub fn new(memory: DeviceMemory, range: Range<DeviceSize>) -> Result<Self, MemoryMapError> {
// VUID-vkMapMemory-size-00680
assert!(!range.is_empty());
// VUID-vkMapMemory-memory-00678
// Guaranteed because we take ownership of `memory`, no other mapping can exist.
// VUID-vkMapMemory-offset-00679
// VUID-vkMapMemory-size-00681
if range.end > memory.allocation_size {
return Err(MemoryMapError::OutOfRange {
provided_range: range,
allowed_range: 0..memory.allocation_size,
});
}
// VUID-vkMapMemory-memory-00682
if !memory.memory_type().is_host_visible() {
return Err(MemoryMapError::NotHostVisible);
}
let device = memory.device();
let coherent = memory.memory_type().is_host_coherent();
let atom_size = device.physical_device().properties().non_coherent_atom_size;
// Not required for merely mapping, but without this check the user can end up with
// parts of the mapped memory at the start and end that they're not able to
// invalidate/flush, which is probably unintended.
if !coherent
&& (range.start % atom_size != 0
|| (range.end % atom_size != 0 && range.end != memory.allocation_size))
{
return Err(MemoryMapError::RangeNotAlignedToAtomSize { range, atom_size });
}
let pointer = unsafe {
let fns = device.fns();
let mut output = MaybeUninit::uninit();
check_errors(fns.v1_0.map_memory(
device.internal_object(),
memory.handle,
range.start,
range.end - range.start,
ash::vk::MemoryMapFlags::empty(),
output.as_mut_ptr(),
))?;
output.assume_init()
};
Ok(MappedDeviceMemory {
memory,
pointer,
range,
atom_size,
coherent,
})
}
/// Unmaps the memory. It will no longer be accessible from the CPU.
pub fn unmap(self) -> DeviceMemory {
unsafe {
@ -1173,33 +1191,36 @@ impl MappedDeviceMemory {
self.memory
}
/// Gives access to the content of the memory.
/// Invalidates the host (CPU) cache for a range of mapped memory.
///
/// This function takes care of calling `vkInvalidateMappedMemoryRanges` and
/// `vkFlushMappedMemoryRanges` on the given range. You are therefore encouraged to use the
/// smallest range as possible, and to not call this function multiple times in a row for
/// several small changes.
/// If the mapped memory is not host-coherent, you must call this function before the memory is
/// read by the host, if the device previously wrote to the memory. It has no effect if the
/// mapped memory is host-coherent.
///
/// `range` is specified in bytes relative to the start of the memory allocation, and must fall
/// within the range of the memory mapping given to `new`. If the memory was not allocated
/// from host-coherent memory, then the start and end of `range` must be a multiple of the
/// [`non_coherent_atom_size`](crate::device::Properties::non_coherent_atom_size) device
/// property, but `range.end` can also equal the memory's `allocation_size`.
///
/// # Safety
///
/// - Type safety is not checked. You must ensure that `T` corresponds to the content of the
/// buffer.
/// - Accesses are not synchronized. Synchronization must be handled outside of
/// the `MappedDeviceMemory`.
/// - If there are memory writes by the GPU that have not been propagated into the CPU cache,
/// then there must not be any references in Rust code to the specified `range` of the memory.
///
#[inline]
pub unsafe fn read_write<T: ?Sized>(&self, range: Range<DeviceSize>) -> CpuAccess<T>
where
T: Content,
{
let fns = self.memory.device().fns();
let pointer = T::ref_from_ptr(
(self.pointer as usize + range.start as usize) as *mut _,
(range.end - range.start) as usize,
)
.unwrap(); // TODO: error
/// # Panics
///
/// - Panics if `range` is empty.
pub unsafe fn invalidate_range(&self, range: Range<DeviceSize>) -> Result<(), MemoryMapError> {
if self.coherent {
return Ok(());
}
self.check_range(range.clone())?;
// VUID-VkMappedMemoryRange-memory-00684
// Guaranteed because `self` owns the memory and it's mapped during our lifetime.
if !self.coherent {
let range = ash::vk::MappedMemoryRange {
memory: self.memory.internal_object(),
offset: range.start,
@ -1207,21 +1228,147 @@ impl MappedDeviceMemory {
..Default::default()
};
// TODO: return result instead?
let fns = self.memory.device().fns();
check_errors(fns.v1_0.invalidate_mapped_memory_ranges(
self.memory.device().internal_object(),
1,
&range,
))
.unwrap();
))?;
Ok(())
}
CpuAccess {
pointer: pointer,
mem: self,
coherent: self.coherent,
range,
/// Flushes the host (CPU) cache for a range of mapped memory.
///
/// If the mapped memory is not host-coherent, you must call this function after writing to the
/// memory, if the device is going to read the memory. It has no effect if the
/// mapped memory is host-coherent.
///
/// `range` is specified in bytes relative to the start of the memory allocation, and must fall
/// within the range of the memory mapping given to `map`. If the memory was not allocated
/// from host-coherent memory, then the start and end of `range` must be a multiple of the
/// [`non_coherent_atom_size`](crate::device::Properties::non_coherent_atom_size) device
/// property, but `range.end` can also equal the memory's `allocation_size`.
///
/// # Safety
///
/// - There must be no operations pending or executing in a GPU queue, that access the specified
/// `range` of the memory.
///
/// # Panics
///
/// - Panics if `range` is empty.
pub unsafe fn flush_range(&self, range: Range<DeviceSize>) -> Result<(), MemoryMapError> {
self.check_range(range.clone())?;
if self.coherent {
return Ok(());
}
// VUID-VkMappedMemoryRange-memory-00684
// Guaranteed because `self` owns the memory and it's mapped during our lifetime.
let range = ash::vk::MappedMemoryRange {
memory: self.memory.internal_object(),
offset: range.start,
size: range.end - range.start,
..Default::default()
};
let fns = self.device().fns();
check_errors(fns.v1_0.flush_mapped_memory_ranges(
self.memory.device().internal_object(),
1,
&range,
))?;
Ok(())
}
/// Returns a reference to bytes in the mapped memory.
///
/// `range` is specified in bytes relative to the start of the memory allocation, and must fall
/// within the range of the memory mapping given to `map`. If the memory was not allocated
/// from host-coherent memory, then the start and end of `range` must be a multiple of the
/// [`non_coherent_atom_size`](crate::device::Properties::non_coherent_atom_size) device
/// property, but `range.end` can also equal the memory's `allocation_size`.
///
/// # Safety
///
/// - While the returned reference exists, there must not be any mutable references in Rust code
/// to the same memory.
/// - While the returned reference exists, there must be no operations pending or executing in
/// a GPU queue, that write to the same memory.
///
/// # Panics
///
/// - Panics if `range` is empty.
pub unsafe fn read(&self, range: Range<DeviceSize>) -> Result<&[u8], MemoryMapError> {
self.check_range(range.clone())?;
let bytes = slice::from_raw_parts(
self.pointer.add((range.start - self.range.start) as usize) as *const u8,
(range.end - range.start) as usize,
);
Ok(bytes)
}
/// Returns a mutable reference to bytes in the mapped memory.
///
/// `range` is specified in bytes relative to the start of the memory allocation, and must fall
/// within the range of the memory mapping given to `map`. If the memory was not allocated
/// from host-coherent memory, then the start and end of `range` must be a multiple of the
/// [`non_coherent_atom_size`](crate::device::Properties::non_coherent_atom_size) device
/// property, but `range.end` can also equal the memory's `allocation_size`.
///
/// # Safety
///
/// - While the returned reference exists, there must not be any other references in Rust code
/// to the same memory.
/// - While the returned reference exists, there must be no operations pending or executing in
/// a GPU queue, that access the same memory.
///
/// # Panics
///
/// - Panics if `range` is empty.
pub unsafe fn write(&self, range: Range<DeviceSize>) -> Result<&mut [u8], MemoryMapError> {
self.check_range(range.clone())?;
let bytes = slice::from_raw_parts_mut(
self.pointer.add((range.start - self.range.start) as usize) as *mut u8,
(range.end - range.start) as usize,
);
Ok(bytes)
}
#[inline]
fn check_range(&self, range: Range<DeviceSize>) -> Result<(), MemoryMapError> {
assert!(!range.is_empty());
// VUID-VkMappedMemoryRange-size-00685
if range.start < self.range.start || range.end > self.range.end {
return Err(MemoryMapError::OutOfRange {
provided_range: range,
allowed_range: self.range.clone(),
});
}
if !self.coherent {
// VUID-VkMappedMemoryRange-offset-00687
// VUID-VkMappedMemoryRange-size-01390
if range.start % self.atom_size != 0
|| (range.end % self.atom_size != 0 && range.end != self.memory.allocation_size)
{
return Err(MemoryMapError::RangeNotAlignedToAtomSize {
range,
atom_size: self.atom_size,
});
}
}
Ok(())
}
}
@ -1249,229 +1396,85 @@ unsafe impl DeviceOwned for MappedDeviceMemory {
unsafe impl Send for MappedDeviceMemory {}
unsafe impl Sync for MappedDeviceMemory {}
impl fmt::Debug for MappedDeviceMemory {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
fmt.debug_tuple("MappedDeviceMemory")
.field(&self.memory)
.finish()
}
}
/// Error type returned by functions related to `DeviceMemory`.
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum MemoryMapError {
/// Not enough memory available.
OomError(OomError),
unsafe impl Send for DeviceMemoryMapping {}
unsafe impl Sync for DeviceMemoryMapping {}
/// Memory map failed.
MemoryMapFailed,
/// Represents memory mapped in CPU accessible space.
///
/// Takes an additional reference on the underlying device memory and device.
pub struct DeviceMemoryMapping {
memory: Arc<DeviceMemory>,
pointer: *mut c_void,
coherent: bool,
}
/// Tried to map memory whose type is not host-visible.
NotHostVisible,
impl DeviceMemoryMapping {
/// Creates a new `DeviceMemoryMapping` object given the previously allocated `device` and `memory`.
pub fn new(
memory: Arc<DeviceMemory>,
offset: DeviceSize,
size: DeviceSize,
flags: u32,
) -> Result<DeviceMemoryMapping, DeviceMemoryAllocationError> {
// VUID-vkMapMemory-memory-00678: "memory must not be currently host mapped".
let mut mapped = memory.mapped.lock().expect("Poisoned mutex");
/// The specified `range` is not contained within the allocated or mapped memory range.
OutOfRange {
provided_range: Range<DeviceSize>,
allowed_range: Range<DeviceSize>,
},
if *mapped {
return Err(DeviceMemoryAllocationError::SpecViolation(678));
}
// VUID-vkMapMemory-offset-00679: "offset must be less than the size of memory"
if size != ash::vk::WHOLE_SIZE && offset >= memory.size() {
return Err(DeviceMemoryAllocationError::SpecViolation(679));
}
// VUID-vkMapMemory-size-00680: "If size is not equal to VK_WHOLE_SIZE, size must be
// greater than 0".
if size != ash::vk::WHOLE_SIZE && size == 0 {
return Err(DeviceMemoryAllocationError::SpecViolation(680));
}
// VUID-vkMapMemory-size-00681: "If size is not equal to VK_WHOLE_SIZE, size must be less
// than or equal to the size of the memory minus offset".
if size != ash::vk::WHOLE_SIZE && size > memory.size() - offset {
return Err(DeviceMemoryAllocationError::SpecViolation(681));
}
// VUID-vkMapMemory-memory-00682: "memory must have been created with a memory type
// that reports VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT"
let coherent = memory.memory_type().is_host_coherent();
if !coherent {
return Err(DeviceMemoryAllocationError::SpecViolation(682));
}
// VUID-vkMapMemory-memory-00683: "memory must not have been allocated with multiple instances".
// Confused about this one, so not implemented.
// VUID-vkMapMemory-flags-zerobitmask: "flags must be 0".
if flags != 0 {
return Err(DeviceMemoryAllocationError::ImplicitSpecViolation(
"VUID-vkMapMemory-flags-zerobitmask",
));
}
// VUID-vkMapMemory-device-parameter, VUID-vkMapMemory-memory-parameter and
// VUID-vkMapMemory-ppData-parameter satisfied via Vulkano internally.
let fns = memory.device().fns();
let ptr = unsafe {
let mut output = MaybeUninit::uninit();
check_errors(fns.v1_0.map_memory(
memory.device().internal_object(),
memory.handle,
0,
memory.allocation_size,
ash::vk::MemoryMapFlags::empty(),
output.as_mut_ptr(),
))?;
output.assume_init()
};
*mapped = true;
std::mem::drop(mapped);
Ok(DeviceMemoryMapping {
memory,
pointer: ptr,
coherent,
})
}
/// Returns the raw pointer associated with the `DeviceMemoryMapping`.
///
/// # Safety
///
/// The caller of this function must ensure that the use of the raw pointer does not outlive
/// the associated `DeviceMemoryMapping`.
pub unsafe fn as_ptr(&self) -> *mut u8 {
self.pointer as *mut u8
}
}
impl Drop for DeviceMemoryMapping {
#[inline]
fn drop(&mut self) {
let mut mapped = self.memory.mapped.lock().expect("Poisoned mutex");
unsafe {
let device = self.memory.device();
let fns = device.fns();
fns.v1_0
.unmap_memory(device.internal_object(), self.memory.handle);
}
*mapped = false;
}
}
/// Object that can be used to read or write the content of a `MappedDeviceMemory`.
///
/// This object derefs to the content, just like a `MutexGuard` for example.
pub struct CpuAccess<'a, T: ?Sized + 'a> {
pointer: *mut T,
mem: &'a MappedDeviceMemory,
coherent: bool,
/// The memory is not host-coherent, and the specified `range` bounds are not a multiple of the
/// [`non_coherent_atom_size`](crate::device::Properties::non_coherent_atom_size) device
/// property.
RangeNotAlignedToAtomSize {
range: Range<DeviceSize>,
atom_size: DeviceSize,
},
}
impl<'a, T: ?Sized + 'a> CpuAccess<'a, T> {
/// Builds a new `CpuAccess` to access a sub-part of the current `CpuAccess`.
///
/// This function is unstable. Don't use it directly.
// TODO: unsafe?
// TODO: decide what to do with this
#[doc(hidden)]
impl error::Error for MemoryMapError {
#[inline]
pub fn map<U: ?Sized + 'a, F>(self, f: F) -> CpuAccess<'a, U>
where
F: FnOnce(*mut T) -> *mut U,
{
CpuAccess {
pointer: f(self.pointer),
mem: self.mem,
coherent: self.coherent,
range: self.range.clone(), // TODO: ?
fn source(&self) -> Option<&(dyn error::Error + 'static)> {
match *self {
Self::OomError(ref err) => Some(err),
_ => None,
}
}
}
unsafe impl<'a, T: ?Sized + 'a> Send for CpuAccess<'a, T> {}
unsafe impl<'a, T: ?Sized + 'a> Sync for CpuAccess<'a, T> {}
impl<'a, T: ?Sized + 'a> Deref for CpuAccess<'a, T> {
type Target = T;
impl fmt::Display for MemoryMapError {
#[inline]
fn deref(&self) -> &T {
unsafe { &*self.pointer }
fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
match *self {
Self::OomError(_) => write!(fmt, "not enough memory available"),
Self::MemoryMapFailed => write!(fmt, "memory map failed"),
Self::NotHostVisible => write!(
fmt,
"tried to map memory whose type is not host-visible",
),
Self::OutOfRange { ref provided_range, ref allowed_range } => write!(
fmt,
"the specified `range` ({:?}) was not contained within the allocated or mapped memory range ({:?})",
provided_range, allowed_range,
),
Self::RangeNotAlignedToAtomSize { ref range, atom_size } => write!(
fmt,
"the memory is not host-coherent, and the specified `range` bounds ({:?}) are not a multiple of the `non_coherent_atom_size` device property ({})",
range, atom_size,
)
}
}
}
impl<'a, T: ?Sized + 'a> DerefMut for CpuAccess<'a, T> {
impl From<Error> for MemoryMapError {
#[inline]
fn deref_mut(&mut self) -> &mut T {
unsafe { &mut *self.pointer }
fn from(err: Error) -> Self {
match err {
e @ Error::OutOfHostMemory | e @ Error::OutOfDeviceMemory => Self::OomError(e.into()),
Error::MemoryMapFailed => Self::MemoryMapFailed,
_ => panic!("unexpected error: {:?}", err),
}
}
}
impl<'a, T: ?Sized + 'a> Drop for CpuAccess<'a, T> {
impl From<OomError> for MemoryMapError {
#[inline]
fn drop(&mut self) {
// If the memory doesn't have the `coherent` flag, we need to flush the data.
if !self.coherent {
let fns = self.mem.as_ref().device().fns();
let range = ash::vk::MappedMemoryRange {
memory: self.mem.as_ref().internal_object(),
offset: self.range.start,
size: self.range.end - self.range.start,
..Default::default()
};
unsafe {
check_errors(fns.v1_0.flush_mapped_memory_ranges(
self.mem.as_ref().device().internal_object(),
1,
&range,
))
.unwrap();
}
}
fn from(err: OomError) -> Self {
Self::OomError(err)
}
}
#[repr(C)]
pub struct BaseOutStructure {
pub s_type: i32,
pub p_next: *mut BaseOutStructure,
}
pub(crate) unsafe fn ptr_chain_iter<T>(ptr: &mut T) -> impl Iterator<Item = *mut BaseOutStructure> {
let ptr: *mut BaseOutStructure = ptr as *mut T as _;
(0..).scan(ptr, |p_ptr, _| {
if p_ptr.is_null() {
return None;
}
let n_ptr = (**p_ptr).p_next as *mut BaseOutStructure;
let old = *p_ptr;
*p_ptr = n_ptr;
Some(old)
})
}
pub unsafe trait ExtendsMemoryAllocateInfo {}
unsafe impl ExtendsMemoryAllocateInfo for ash::vk::MemoryDedicatedAllocateInfoKHR {}
unsafe impl ExtendsMemoryAllocateInfo for ash::vk::ExportMemoryAllocateInfo {}
unsafe impl ExtendsMemoryAllocateInfo for ash::vk::ImportMemoryFdInfoKHR {}
#[cfg(test)]
mod tests {
use super::MemoryAllocateInfo;

View File

@ -94,14 +94,13 @@
pub use self::{
device_memory::{
CpuAccess, DeviceMemory, DeviceMemoryAllocationError, DeviceMemoryExportError,
DeviceMemoryMapping, ExternalMemoryHandleType, ExternalMemoryHandleTypes,
MappedDeviceMemory, MemoryAllocateInfo, MemoryImportInfo,
DeviceMemory, DeviceMemoryAllocationError, DeviceMemoryExportError,
ExternalMemoryHandleType, ExternalMemoryHandleTypes, MappedDeviceMemory,
MemoryAllocateInfo, MemoryImportInfo,
},
pool::MemoryPool,
};
use crate::{buffer::sys::UnsafeBuffer, image::sys::UnsafeImage, DeviceSize};
use std::{mem, os::raw::c_void, slice};
mod device_memory;
pub mod pool;
@ -202,68 +201,3 @@ impl From<ash::vk::ExternalMemoryProperties> for ExternalMemoryProperties {
}
}
}
/// Trait for types of data that can be mapped.
// TODO: move to `buffer` module
pub unsafe trait Content {
/// Builds a pointer to this type from a raw pointer.
fn ref_from_ptr<'a>(ptr: *mut c_void, size: usize) -> Option<*mut Self>;
/// Returns true if the size is suitable to store a type like this.
fn is_size_suitable(size: DeviceSize) -> bool;
/// Returns the size of an individual element.
fn indiv_size() -> DeviceSize;
}
unsafe impl<T> Content for T {
#[inline]
fn ref_from_ptr<'a>(ptr: *mut c_void, size: usize) -> Option<*mut T> {
if size < mem::size_of::<T>() {
return None;
}
Some(ptr as *mut T)
}
#[inline]
fn is_size_suitable(size: DeviceSize) -> bool {
size == mem::size_of::<T>() as DeviceSize
}
#[inline]
fn indiv_size() -> DeviceSize {
mem::size_of::<T>() as DeviceSize
}
}
unsafe impl<T> Content for [T] {
#[inline]
fn ref_from_ptr<'a>(ptr: *mut c_void, size: usize) -> Option<*mut [T]> {
let ptr = ptr as *mut T;
let size = size / mem::size_of::<T>();
Some(unsafe { slice::from_raw_parts_mut(&mut *ptr, size) as *mut [T] })
}
#[inline]
fn is_size_suitable(size: DeviceSize) -> bool {
size % mem::size_of::<T>() as DeviceSize == 0
}
#[inline]
fn indiv_size() -> DeviceSize {
mem::size_of::<T>() as DeviceSize
}
}
/*
TODO: do this when it's possible
unsafe impl Content for .. {}
impl<'a, T> !Content for &'a T {}
impl<'a, T> !Content for &'a mut T {}
impl<T> !Content for *const T {}
impl<T> !Content for *mut T {}
impl<T> !Content for Box<T> {}
impl<T> !Content for UnsafeCell<T> {}
*/

View File

@ -99,7 +99,7 @@ impl StdHostVisibleMemoryTypePool {
// Try append at the end.
let last_end = entries.last().map(|e| align(e.end, alignment)).unwrap_or(0);
if last_end + size <= (**dev_mem).as_ref().size() {
if last_end + size <= (**dev_mem).as_ref().allocation_size() {
entries.push(last_end..last_end + size);
return Ok(StdHostVisibleMemoryTypePoolAlloc {
pool: me.clone(),
@ -114,7 +114,7 @@ impl StdHostVisibleMemoryTypePool {
let new_block = {
const MIN_BLOCK_SIZE: DeviceSize = 8 * 1024 * 1024; // 8 MB
let allocation_size = cmp::max(MIN_BLOCK_SIZE, size.next_power_of_two());
let new_block = DeviceMemory::allocate_and_map(
let memory = DeviceMemory::allocate(
me.device.clone(),
MemoryAllocateInfo {
allocation_size,
@ -122,6 +122,7 @@ impl StdHostVisibleMemoryTypePool {
..Default::default()
},
)?;
let new_block = MappedDeviceMemory::new(memory, 0..allocation_size)?;
Arc::new(new_block)
};

View File

@ -85,38 +85,25 @@ where
assert!(device.enabled_extensions().khr_external_memory);
let memory_type = choose_allocation_memory_type(&device, requirements, filter, map);
let memory = DeviceMemory::allocate(
device.clone(),
MemoryAllocateInfo {
allocation_size: requirements.size,
memory_type_index: memory_type.id(),
export_handle_types: ExternalMemoryHandleTypes {
opaque_fd: true,
..ExternalMemoryHandleTypes::none()
},
..MemoryAllocateInfo::dedicated_allocation(dedicated_allocation)
},
)?;
match map {
MappingRequirement::Map => {
let mem = DeviceMemory::allocate_and_map(
device.clone(),
MemoryAllocateInfo {
allocation_size: requirements.size,
memory_type_index: memory_type.id(),
export_handle_types: ExternalMemoryHandleTypes {
opaque_fd: true,
..ExternalMemoryHandleTypes::none()
},
..MemoryAllocateInfo::dedicated_allocation(dedicated_allocation)
},
)?;
Ok(PotentialDedicatedAllocation::DedicatedMapped(mem))
}
MappingRequirement::DoNotMap => {
let mem = DeviceMemory::allocate(
device.clone(),
MemoryAllocateInfo {
allocation_size: requirements.size,
memory_type_index: memory_type.id(),
export_handle_types: ExternalMemoryHandleTypes {
opaque_fd: true,
..ExternalMemoryHandleTypes::none()
},
..MemoryAllocateInfo::dedicated_allocation(dedicated_allocation)
},
)?;
Ok(PotentialDedicatedAllocation::Dedicated(mem))
let mapped_memory = MappedDeviceMemory::new(memory, 0..requirements.size)?;
Ok(PotentialDedicatedAllocation::DedicatedMapped(mapped_memory))
}
MappingRequirement::DoNotMap => Ok(PotentialDedicatedAllocation::Dedicated(memory)),
}
}
@ -221,31 +208,22 @@ pub unsafe trait MemoryPool: DeviceOwned {
}
// If we reach here, then we perform a dedicated alloc.
let memory = DeviceMemory::allocate(
self.device().clone(),
MemoryAllocateInfo {
allocation_size: requirements.size,
memory_type_index: memory_type.id(),
dedicated_allocation,
..Default::default()
},
)?;
match map {
MappingRequirement::Map => {
let mem = DeviceMemory::allocate_and_map(
self.device().clone(),
MemoryAllocateInfo {
allocation_size: requirements.size,
memory_type_index: memory_type.id(),
dedicated_allocation,
..Default::default()
},
)?;
Ok(PotentialDedicatedAllocation::DedicatedMapped(mem))
}
MappingRequirement::DoNotMap => {
let mem = DeviceMemory::allocate(
self.device().clone(),
MemoryAllocateInfo {
allocation_size: requirements.size,
memory_type_index: memory_type.id(),
dedicated_allocation,
..Default::default()
},
)?;
Ok(PotentialDedicatedAllocation::Dedicated(mem))
let mapped_memory = MappedDeviceMemory::new(memory, 0..requirements.size)?;
Ok(PotentialDedicatedAllocation::DedicatedMapped(mapped_memory))
}
MappingRequirement::DoNotMap => Ok(PotentialDedicatedAllocation::Dedicated(memory)),
}
}
}

View File

@ -99,7 +99,7 @@ impl StdNonHostVisibleMemoryTypePool {
// Try append at the end.
let last_end = entries.last().map(|e| align(e.end, alignment)).unwrap_or(0);
if last_end + size <= dev_mem.size() {
if last_end + size <= dev_mem.allocation_size() {
entries.push(last_end..last_end + size);
return Ok(StdNonHostVisibleMemoryTypePoolAlloc {
pool: me.clone(),

View File

@ -13,7 +13,10 @@ use crate::pipeline::graphics::vertex_input::VertexMemberTy;
///# Example
///
///```
///#[derive(Default, Copy, Clone)]
/// # use bytemuck::{Zeroable, Pod};
///
///#[repr(C)]
///#[derive(Clone, Copy, Debug, Default, Zeroable, Pod)]
///struct Vertex{
/// position: [f32; 3],
/// color: [f32; 4]

View File

@ -8,13 +8,14 @@
// according to those terms.
use crate::format::Format;
use bytemuck::Pod;
/// Describes an individual `Vertex`. In other words a collection of attributes that can be read
/// from a vertex shader.
///
/// At this stage, the vertex is in a "raw" format. For example a `[f32; 4]` can match both a
/// `vec4` or a `float[4]`. The way the things are bound depends on the shader.
pub unsafe trait Vertex: Send + Sync + 'static {
pub unsafe trait Vertex: Pod + Send + Sync + 'static {
/// Returns the characteristics of a vertex member by its name.
fn member(name: &str) -> Option<VertexMemberInfo>;
}

View File

@ -23,7 +23,7 @@ use std::{
ffi::c_void,
fmt,
hash::{Hash, Hasher},
mem::MaybeUninit,
mem::{size_of_val, MaybeUninit},
ops::Range,
ptr,
sync::Arc,
@ -344,7 +344,7 @@ impl<'a> QueriesRange<'a> {
self.pool.internal_object(),
self.range.start,
self.range.end - self.range.start,
std::mem::size_of_val(destination),
size_of_val(destination),
destination.as_mut_ptr() as *mut c_void,
stride,
ash::vk::QueryResultFlags::from(flags) | T::FLAG,
@ -372,7 +372,7 @@ impl<'a> QueriesRange<'a> {
let count = self.range.end - self.range.start;
let per_query_len =
self.pool.query_type.result_size() + flags.with_availability as DeviceSize;
self.pool.query_type.result_len() + flags.with_availability as DeviceSize;
let required_len = per_query_len * count as DeviceSize;
if buffer_len < required_len {
@ -502,7 +502,7 @@ impl QueryType {
/// If the results are retrieved with [`QueryResultFlags::with_availability`] enabled, then
/// an additional element is required per query.
#[inline]
pub const fn result_size(&self) -> DeviceSize {
pub const fn result_len(&self) -> DeviceSize {
match self {
Self::Occlusion | Self::Timestamp => 1,
Self::PipelineStatistics(flags) => flags.count(),