mirror of
https://github.com/vulkano-rs/vulkano.git
synced 2024-11-25 16:25:31 +00:00
Rework mapped memory, add BufferContents
trait with bytemuck (#1853)
* Rework mapped memory, add `BufferContents` trait with bytemuck * Platform fix
This commit is contained in:
parent
6061fb738a
commit
c70fcc575f
@ -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"
|
||||
|
@ -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.
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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,
|
||||
|
@ -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,24 +40,23 @@ 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 vertices = [
|
||||
Vertex {
|
||||
position: [-1.0, -1.0],
|
||||
},
|
||||
Vertex {
|
||||
position: [-1.0, 3.0],
|
||||
},
|
||||
Vertex {
|
||||
position: [3.0, -1.0],
|
||||
},
|
||||
];
|
||||
let vertex_buffer = {
|
||||
CpuAccessibleBuffer::from_iter(
|
||||
gfx_queue.device().clone(),
|
||||
BufferUsage::all(),
|
||||
false,
|
||||
[
|
||||
Vertex {
|
||||
position: [-1.0, -1.0],
|
||||
},
|
||||
Vertex {
|
||||
position: [-1.0, 3.0],
|
||||
},
|
||||
Vertex {
|
||||
position: [3.0, -1.0],
|
||||
},
|
||||
]
|
||||
.iter()
|
||||
.cloned(),
|
||||
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! {
|
||||
|
@ -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,24 +41,23 @@ 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 vertices = [
|
||||
Vertex {
|
||||
position: [-1.0, -1.0],
|
||||
},
|
||||
Vertex {
|
||||
position: [-1.0, 3.0],
|
||||
},
|
||||
Vertex {
|
||||
position: [3.0, -1.0],
|
||||
},
|
||||
];
|
||||
let vertex_buffer = {
|
||||
CpuAccessibleBuffer::from_iter(
|
||||
gfx_queue.device().clone(),
|
||||
BufferUsage::all(),
|
||||
false,
|
||||
[
|
||||
Vertex {
|
||||
position: [-1.0, -1.0],
|
||||
},
|
||||
Vertex {
|
||||
position: [-1.0, 3.0],
|
||||
},
|
||||
Vertex {
|
||||
position: [3.0, -1.0],
|
||||
},
|
||||
]
|
||||
.iter()
|
||||
.cloned(),
|
||||
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! {
|
||||
|
@ -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;
|
||||
|
@ -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,24 +40,23 @@ 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 vertices = [
|
||||
Vertex {
|
||||
position: [-1.0, -1.0],
|
||||
},
|
||||
Vertex {
|
||||
position: [-1.0, 3.0],
|
||||
},
|
||||
Vertex {
|
||||
position: [3.0, -1.0],
|
||||
},
|
||||
];
|
||||
let vertex_buffer = {
|
||||
CpuAccessibleBuffer::from_iter(
|
||||
gfx_queue.device().clone(),
|
||||
BufferUsage::all(),
|
||||
false,
|
||||
[
|
||||
Vertex {
|
||||
position: [-1.0, -1.0],
|
||||
},
|
||||
Vertex {
|
||||
position: [-1.0, 3.0],
|
||||
},
|
||||
Vertex {
|
||||
position: [3.0, -1.0],
|
||||
},
|
||||
]
|
||||
.iter()
|
||||
.cloned(),
|
||||
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! {
|
||||
|
@ -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 {
|
||||
|
@ -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;
|
||||
|
@ -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,24 +35,23 @@ pub struct TriangleDrawSystem {
|
||||
impl TriangleDrawSystem {
|
||||
/// Initializes a triangle drawing system.
|
||||
pub fn new(gfx_queue: Arc<Queue>, subpass: Subpass) -> TriangleDrawSystem {
|
||||
let vertices = [
|
||||
Vertex {
|
||||
position: [-0.5, -0.25],
|
||||
},
|
||||
Vertex {
|
||||
position: [0.0, 0.5],
|
||||
},
|
||||
Vertex {
|
||||
position: [0.25, -0.1],
|
||||
},
|
||||
];
|
||||
let vertex_buffer = {
|
||||
CpuAccessibleBuffer::from_iter(
|
||||
gfx_queue.device().clone(),
|
||||
BufferUsage::all(),
|
||||
false,
|
||||
[
|
||||
Vertex {
|
||||
position: [-0.5, -0.25],
|
||||
},
|
||||
Vertex {
|
||||
position: [0.0, 0.5],
|
||||
},
|
||||
Vertex {
|
||||
position: [0.25, -0.1],
|
||||
},
|
||||
]
|
||||
.iter()
|
||||
.cloned(),
|
||||
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! {
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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 {
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -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::{
|
||||
AutoCommandBufferBuilder, CommandBufferUsage, PrimaryCommandBuffer, SubpassContents,
|
||||
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,32 +134,31 @@ 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 vertices = [
|
||||
Vertex {
|
||||
position: [-0.5, -0.5],
|
||||
},
|
||||
Vertex {
|
||||
position: [-0.5, 0.5],
|
||||
},
|
||||
Vertex {
|
||||
position: [0.5, -0.5],
|
||||
},
|
||||
Vertex {
|
||||
position: [0.5, 0.5],
|
||||
},
|
||||
];
|
||||
let vertex_buffer = CpuAccessibleBuffer::<[Vertex]>::from_iter(
|
||||
device.clone(),
|
||||
BufferUsage::all(),
|
||||
false,
|
||||
[
|
||||
Vertex {
|
||||
position: [-0.5, -0.5],
|
||||
},
|
||||
Vertex {
|
||||
position: [-0.5, 0.5],
|
||||
},
|
||||
Vertex {
|
||||
position: [0.5, -0.5],
|
||||
},
|
||||
Vertex {
|
||||
position: [0.5, 0.5],
|
||||
},
|
||||
]
|
||||
.iter()
|
||||
.cloned(),
|
||||
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;
|
||||
|
@ -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,32 +133,31 @@ 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 vertices = [
|
||||
Vertex {
|
||||
position: [-0.5, -0.5],
|
||||
},
|
||||
Vertex {
|
||||
position: [-0.5, 0.5],
|
||||
},
|
||||
Vertex {
|
||||
position: [0.5, -0.5],
|
||||
},
|
||||
Vertex {
|
||||
position: [0.5, 0.5],
|
||||
},
|
||||
];
|
||||
let vertex_buffer = CpuAccessibleBuffer::<[Vertex]>::from_iter(
|
||||
device.clone(),
|
||||
BufferUsage::all(),
|
||||
false,
|
||||
[
|
||||
Vertex {
|
||||
position: [-0.5, -0.5],
|
||||
},
|
||||
Vertex {
|
||||
position: [-0.5, 0.5],
|
||||
},
|
||||
Vertex {
|
||||
position: [0.5, -0.5],
|
||||
},
|
||||
Vertex {
|
||||
position: [0.5, 0.5],
|
||||
},
|
||||
]
|
||||
.iter()
|
||||
.cloned(),
|
||||
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;
|
||||
|
@ -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();
|
||||
|
@ -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,32 +139,31 @@ 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 vertices = [
|
||||
Vertex {
|
||||
position: [-0.5, -0.5],
|
||||
},
|
||||
Vertex {
|
||||
position: [-0.5, 0.5],
|
||||
},
|
||||
Vertex {
|
||||
position: [0.5, -0.5],
|
||||
},
|
||||
Vertex {
|
||||
position: [0.5, 0.5],
|
||||
},
|
||||
];
|
||||
let vertex_buffer = CpuAccessibleBuffer::<[Vertex]>::from_iter(
|
||||
device.clone(),
|
||||
BufferUsage::all(),
|
||||
false,
|
||||
[
|
||||
Vertex {
|
||||
position: [-0.5, -0.5],
|
||||
},
|
||||
Vertex {
|
||||
position: [-0.5, 0.5],
|
||||
},
|
||||
Vertex {
|
||||
position: [0.5, -0.5],
|
||||
},
|
||||
Vertex {
|
||||
position: [0.5, 0.5],
|
||||
},
|
||||
]
|
||||
.iter()
|
||||
.cloned(),
|
||||
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;
|
||||
|
@ -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::{
|
||||
AutoCommandBufferBuilder, CommandBufferUsage, DrawIndirectCommand, SubpassContents,
|
||||
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 {
|
||||
vertex_count: 0,
|
||||
instance_count: 1,
|
||||
first_vertex: 0,
|
||||
first_instance: 0,
|
||||
}))
|
||||
.unwrap();
|
||||
let indirect_commands = [DrawIndirectCommand {
|
||||
vertex_count: 0,
|
||||
instance_count: 1,
|
||||
first_vertex: 0,
|
||||
first_instance: 0,
|
||||
}];
|
||||
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();
|
||||
|
@ -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,31 +153,24 @@ 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,
|
||||
[
|
||||
Vertex {
|
||||
position: [-0.5, -0.25],
|
||||
},
|
||||
Vertex {
|
||||
position: [0.0, 0.5],
|
||||
},
|
||||
Vertex {
|
||||
position: [0.25, -0.1],
|
||||
},
|
||||
]
|
||||
.iter()
|
||||
.cloned(),
|
||||
)
|
||||
.unwrap()
|
||||
let vertices = [
|
||||
Vertex {
|
||||
position: [-0.5, -0.25],
|
||||
},
|
||||
Vertex {
|
||||
position: [0.0, 0.5],
|
||||
},
|
||||
Vertex {
|
||||
position: [0.25, -0.1],
|
||||
},
|
||||
];
|
||||
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,
|
||||
)
|
||||
|
@ -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();
|
||||
|
@ -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
|
||||
|
@ -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},
|
||||
|
@ -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();
|
||||
|
||||
|
@ -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>,
|
||||
|
@ -8,29 +8,29 @@
|
||||
// according to those terms.
|
||||
|
||||
use crate::place_over_frame::RenderPassPlaceOverFrame;
|
||||
|
||||
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_win::VkSurfaceBuild;
|
||||
|
||||
use std::collections::HashMap;
|
||||
use std::sync::Arc;
|
||||
use vulkano::device::physical::{PhysicalDevice, PhysicalDeviceType};
|
||||
use vulkano::device::{
|
||||
Device, DeviceCreateInfo, DeviceExtensions, Features, Queue, QueueCreateInfo,
|
||||
use winit::{
|
||||
event_loop::EventLoop,
|
||||
window::{Fullscreen, Window, WindowBuilder},
|
||||
};
|
||||
use vulkano::format::Format;
|
||||
use vulkano::image::view::ImageView;
|
||||
use vulkano::image::{
|
||||
AttachmentImage, ImageAccess, ImageUsage, ImageViewAbstract, SampleCount, SwapchainImage,
|
||||
};
|
||||
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;
|
||||
|
@ -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::{
|
||||
AutoCommandBufferBuilder, CommandBufferUsage, PrimaryCommandBuffer, SubpassContents,
|
||||
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,28 +253,26 @@ 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 {
|
||||
position: [-0.5, -0.5],
|
||||
};
|
||||
let vertex2 = Vertex {
|
||||
position: [0.0, 0.5],
|
||||
};
|
||||
let vertex3 = Vertex {
|
||||
position: [0.5, -0.25],
|
||||
};
|
||||
let vertex_buffer = CpuAccessibleBuffer::from_iter(
|
||||
device.clone(),
|
||||
BufferUsage::all(),
|
||||
false,
|
||||
vec![vertex1, vertex2, vertex3].into_iter(),
|
||||
)
|
||||
.unwrap();
|
||||
let vertices = [
|
||||
Vertex {
|
||||
position: [-0.5, -0.5],
|
||||
},
|
||||
Vertex {
|
||||
position: [0.0, 0.5],
|
||||
},
|
||||
Vertex {
|
||||
position: [0.5, -0.25],
|
||||
},
|
||||
];
|
||||
let vertex_buffer =
|
||||
CpuAccessibleBuffer::from_iter(device.clone(), BufferUsage::all(), false, vertices)
|
||||
.unwrap();
|
||||
|
||||
let pipeline = GraphicsPipeline::start()
|
||||
.vertex_input_state(BuffersDefinition::new().vertex::<Vertex>())
|
||||
|
@ -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,31 +161,26 @@ 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,
|
||||
[
|
||||
Vertex {
|
||||
position: [-0.5, -0.25],
|
||||
},
|
||||
Vertex {
|
||||
position: [0.0, 0.5],
|
||||
},
|
||||
Vertex {
|
||||
position: [0.25, -0.1],
|
||||
},
|
||||
]
|
||||
.iter()
|
||||
.cloned(),
|
||||
)
|
||||
.unwrap();
|
||||
let vertices = [
|
||||
Vertex {
|
||||
position: [-0.5, -0.25],
|
||||
},
|
||||
Vertex {
|
||||
position: [0.0, 0.5],
|
||||
},
|
||||
Vertex {
|
||||
position: [0.25, -0.1],
|
||||
},
|
||||
];
|
||||
let vertex_buffer =
|
||||
CpuAccessibleBuffer::from_iter(device.clone(), BufferUsage::all(), false, vertices)
|
||||
.unwrap();
|
||||
|
||||
mod vs {
|
||||
vulkano_shaders::shader! {
|
||||
@ -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;
|
||||
|
@ -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,
|
||||
|
@ -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.
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -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>) {
|
||||
(
|
||||
|
@ -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>,
|
||||
|
@ -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,18 +253,22 @@ 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 {
|
||||
Err(e) => match e {
|
||||
InstanceCreationError::LoadingError(le) => {
|
||||
println!(
|
||||
"{:?}, Did you install vulkanSDK from https://vulkan.lunarg.com/sdk/home ?",
|
||||
le
|
||||
);
|
||||
Err(le).expect("")
|
||||
}
|
||||
_ => Err(e).expect("Failed to create instance"),
|
||||
},
|
||||
Ok(i) => i,
|
||||
let instance = {
|
||||
use vulkano::instance::InstanceCreationError;
|
||||
|
||||
match result {
|
||||
Err(e) => match e {
|
||||
InstanceCreationError::LoadingError(le) => {
|
||||
println!(
|
||||
"{:?}, Did you install vulkanSDK from https://vulkan.lunarg.com/sdk/home ?",
|
||||
le
|
||||
);
|
||||
Err(le).expect("")
|
||||
}
|
||||
_ => Err(e).expect("Failed to create instance"),
|
||||
},
|
||||
Ok(i) => i,
|
||||
}
|
||||
};
|
||||
#[cfg(not(target_os = "macos"))]
|
||||
let instance = result.expect("Failed to create instance");
|
||||
|
@ -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>,
|
||||
|
@ -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 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::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::{
|
||||
AttachmentDescription, AttachmentReference, Framebuffer, FramebufferCreateInfo, LoadOp,
|
||||
RenderPass, RenderPassCreateInfo, StoreOp, Subpass, SubpassDescription,
|
||||
};
|
||||
use vulkano::sync::{self, GpuFuture};
|
||||
|
||||
fn main() {
|
||||
let instance = Instance::new(InstanceCreateInfo {
|
||||
@ -131,31 +137,26 @@ 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,
|
||||
[
|
||||
Vertex {
|
||||
position: [-0.5, -0.25],
|
||||
},
|
||||
Vertex {
|
||||
position: [0.0, 0.5],
|
||||
},
|
||||
Vertex {
|
||||
position: [0.25, -0.1],
|
||||
},
|
||||
]
|
||||
.iter()
|
||||
.cloned(),
|
||||
)
|
||||
.unwrap();
|
||||
let vertices = [
|
||||
Vertex {
|
||||
position: [-0.5, -0.25],
|
||||
},
|
||||
Vertex {
|
||||
position: [0.0, 0.5],
|
||||
},
|
||||
Vertex {
|
||||
position: [0.25, -0.1],
|
||||
},
|
||||
];
|
||||
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
|
||||
// for the shader and the use of `gl_ViewIndex` which contains a value based on which
|
||||
|
@ -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,72 +130,67 @@ 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,
|
||||
[
|
||||
// The first triangle (red) is the same one as in the triangle example.
|
||||
Vertex {
|
||||
position: [-0.5, -0.25, 0.5],
|
||||
color: [1.0, 0.0, 0.0],
|
||||
},
|
||||
Vertex {
|
||||
position: [0.0, 0.5, 0.5],
|
||||
color: [1.0, 0.0, 0.0],
|
||||
},
|
||||
Vertex {
|
||||
position: [0.25, -0.1, 0.5],
|
||||
color: [1.0, 0.0, 0.0],
|
||||
},
|
||||
// The second triangle (cyan) is the same shape and position as the first,
|
||||
// but smaller, and moved behind a bit.
|
||||
// It should be completely occluded by the first triangle.
|
||||
// (You can lower its z value to put it in front)
|
||||
Vertex {
|
||||
position: [-0.25, -0.125, 0.6],
|
||||
color: [0.0, 1.0, 1.0],
|
||||
},
|
||||
Vertex {
|
||||
position: [0.0, 0.25, 0.6],
|
||||
color: [0.0, 1.0, 1.0],
|
||||
},
|
||||
Vertex {
|
||||
position: [0.125, -0.05, 0.6],
|
||||
color: [0.0, 1.0, 1.0],
|
||||
},
|
||||
// The third triangle (green) is the same shape and size as the first,
|
||||
// but moved to the left and behind the second.
|
||||
// It is partially occluded by the first two.
|
||||
Vertex {
|
||||
position: [-0.25, -0.25, 0.7],
|
||||
color: [0.0, 1.0, 0.0],
|
||||
},
|
||||
Vertex {
|
||||
position: [0.25, 0.5, 0.7],
|
||||
color: [0.0, 1.0, 0.0],
|
||||
},
|
||||
Vertex {
|
||||
position: [0.5, -0.1, 0.7],
|
||||
color: [0.0, 1.0, 0.0],
|
||||
},
|
||||
]
|
||||
.iter()
|
||||
.cloned(),
|
||||
)
|
||||
.unwrap();
|
||||
let vertices = [
|
||||
// The first triangle (red) is the same one as in the triangle example.
|
||||
Vertex {
|
||||
position: [-0.5, -0.25, 0.5],
|
||||
color: [1.0, 0.0, 0.0],
|
||||
},
|
||||
Vertex {
|
||||
position: [0.0, 0.5, 0.5],
|
||||
color: [1.0, 0.0, 0.0],
|
||||
},
|
||||
Vertex {
|
||||
position: [0.25, -0.1, 0.5],
|
||||
color: [1.0, 0.0, 0.0],
|
||||
},
|
||||
// The second triangle (cyan) is the same shape and position as the first,
|
||||
// but smaller, and moved behind a bit.
|
||||
// It should be completely occluded by the first triangle.
|
||||
// (You can lower its z value to put it in front)
|
||||
Vertex {
|
||||
position: [-0.25, -0.125, 0.6],
|
||||
color: [0.0, 1.0, 1.0],
|
||||
},
|
||||
Vertex {
|
||||
position: [0.0, 0.25, 0.6],
|
||||
color: [0.0, 1.0, 1.0],
|
||||
},
|
||||
Vertex {
|
||||
position: [0.125, -0.05, 0.6],
|
||||
color: [0.0, 1.0, 1.0],
|
||||
},
|
||||
// The third triangle (green) is the same shape and size as the first,
|
||||
// but moved to the left and behind the second.
|
||||
// It is partially occluded by the first two.
|
||||
Vertex {
|
||||
position: [-0.25, -0.25, 0.7],
|
||||
color: [0.0, 1.0, 0.0],
|
||||
},
|
||||
Vertex {
|
||||
position: [0.25, 0.5, 0.7],
|
||||
color: [0.0, 1.0, 0.0],
|
||||
},
|
||||
Vertex {
|
||||
position: [0.5, -0.1, 0.7],
|
||||
color: [0.0, 1.0, 0.0],
|
||||
},
|
||||
];
|
||||
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.
|
||||
//
|
||||
|
@ -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");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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();
|
||||
|
@ -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,32 +131,31 @@ 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 vertices = [
|
||||
Vertex {
|
||||
position: [-0.5, -0.5],
|
||||
},
|
||||
Vertex {
|
||||
position: [-0.5, 0.5],
|
||||
},
|
||||
Vertex {
|
||||
position: [0.5, -0.5],
|
||||
},
|
||||
Vertex {
|
||||
position: [0.5, 0.5],
|
||||
},
|
||||
];
|
||||
let vertex_buffer = CpuAccessibleBuffer::<[Vertex]>::from_iter(
|
||||
device.clone(),
|
||||
BufferUsage::all(),
|
||||
false,
|
||||
[
|
||||
Vertex {
|
||||
position: [-0.5, -0.5],
|
||||
},
|
||||
Vertex {
|
||||
position: [-0.5, 0.5],
|
||||
},
|
||||
Vertex {
|
||||
position: [0.5, -0.5],
|
||||
},
|
||||
Vertex {
|
||||
position: [0.5, 0.5],
|
||||
},
|
||||
]
|
||||
.iter()
|
||||
.cloned(),
|
||||
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;
|
||||
|
@ -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,28 +197,23 @@ fn main() {
|
||||
|
||||
let mut recreate_swapchain = false;
|
||||
|
||||
let vertex_buffer = CpuAccessibleBuffer::from_iter(
|
||||
device.clone(),
|
||||
BufferUsage::all(),
|
||||
false,
|
||||
[
|
||||
Vertex {
|
||||
position: [-1.0, 1.0],
|
||||
color: [1.0, 0.0, 0.0],
|
||||
},
|
||||
Vertex {
|
||||
position: [0.0, -1.0],
|
||||
color: [0.0, 1.0, 0.0],
|
||||
},
|
||||
Vertex {
|
||||
position: [1.0, 1.0],
|
||||
color: [0.0, 0.0, 1.0],
|
||||
},
|
||||
]
|
||||
.iter()
|
||||
.cloned(),
|
||||
)
|
||||
.unwrap();
|
||||
let vertices = [
|
||||
Vertex {
|
||||
position: [-1.0, 1.0],
|
||||
color: [1.0, 0.0, 0.0],
|
||||
},
|
||||
Vertex {
|
||||
position: [0.0, -1.0],
|
||||
color: [0.0, 1.0, 0.0],
|
||||
},
|
||||
Vertex {
|
||||
position: [1.0, 1.0],
|
||||
color: [0.0, 0.0, 1.0],
|
||||
},
|
||||
];
|
||||
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
|
||||
// note that passing wrong types, providing sets at wrong indexes will cause
|
||||
@ -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;
|
||||
|
@ -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::{
|
||||
DescriptorSetLayout, DescriptorSetLayoutCreateInfo, DescriptorSetLayoutCreationError,
|
||||
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,82 +145,81 @@ 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 vertices = [
|
||||
Vertex {
|
||||
position: [-0.1, -0.9],
|
||||
tex_i: 0,
|
||||
coords: [1.0, 0.0],
|
||||
},
|
||||
Vertex {
|
||||
position: [-0.9, -0.9],
|
||||
tex_i: 0,
|
||||
coords: [0.0, 0.0],
|
||||
},
|
||||
Vertex {
|
||||
position: [-0.9, -0.1],
|
||||
tex_i: 0,
|
||||
coords: [0.0, 1.0],
|
||||
},
|
||||
Vertex {
|
||||
position: [-0.1, -0.9],
|
||||
tex_i: 0,
|
||||
coords: [1.0, 0.0],
|
||||
},
|
||||
Vertex {
|
||||
position: [-0.9, -0.1],
|
||||
tex_i: 0,
|
||||
coords: [0.0, 1.0],
|
||||
},
|
||||
Vertex {
|
||||
position: [-0.1, -0.1],
|
||||
tex_i: 0,
|
||||
coords: [1.0, 1.0],
|
||||
},
|
||||
Vertex {
|
||||
position: [0.9, -0.9],
|
||||
tex_i: 1,
|
||||
coords: [1.0, 0.0],
|
||||
},
|
||||
Vertex {
|
||||
position: [0.1, -0.9],
|
||||
tex_i: 1,
|
||||
coords: [0.0, 0.0],
|
||||
},
|
||||
Vertex {
|
||||
position: [0.1, -0.1],
|
||||
tex_i: 1,
|
||||
coords: [0.0, 1.0],
|
||||
},
|
||||
Vertex {
|
||||
position: [0.9, -0.9],
|
||||
tex_i: 1,
|
||||
coords: [1.0, 0.0],
|
||||
},
|
||||
Vertex {
|
||||
position: [0.1, -0.1],
|
||||
tex_i: 1,
|
||||
coords: [0.0, 1.0],
|
||||
},
|
||||
Vertex {
|
||||
position: [0.9, -0.1],
|
||||
tex_i: 1,
|
||||
coords: [1.0, 1.0],
|
||||
},
|
||||
];
|
||||
let vertex_buffer = CpuAccessibleBuffer::<[Vertex]>::from_iter(
|
||||
device.clone(),
|
||||
BufferUsage::all(),
|
||||
false,
|
||||
[
|
||||
Vertex {
|
||||
position: [-0.1, -0.9],
|
||||
tex_i: 0,
|
||||
coords: [1.0, 0.0],
|
||||
},
|
||||
Vertex {
|
||||
position: [-0.9, -0.9],
|
||||
tex_i: 0,
|
||||
coords: [0.0, 0.0],
|
||||
},
|
||||
Vertex {
|
||||
position: [-0.9, -0.1],
|
||||
tex_i: 0,
|
||||
coords: [0.0, 1.0],
|
||||
},
|
||||
Vertex {
|
||||
position: [-0.1, -0.9],
|
||||
tex_i: 0,
|
||||
coords: [1.0, 0.0],
|
||||
},
|
||||
Vertex {
|
||||
position: [-0.9, -0.1],
|
||||
tex_i: 0,
|
||||
coords: [0.0, 1.0],
|
||||
},
|
||||
Vertex {
|
||||
position: [-0.1, -0.1],
|
||||
tex_i: 0,
|
||||
coords: [1.0, 1.0],
|
||||
},
|
||||
Vertex {
|
||||
position: [0.9, -0.9],
|
||||
tex_i: 1,
|
||||
coords: [1.0, 0.0],
|
||||
},
|
||||
Vertex {
|
||||
position: [0.1, -0.9],
|
||||
tex_i: 1,
|
||||
coords: [0.0, 0.0],
|
||||
},
|
||||
Vertex {
|
||||
position: [0.1, -0.1],
|
||||
tex_i: 1,
|
||||
coords: [0.0, 1.0],
|
||||
},
|
||||
Vertex {
|
||||
position: [0.9, -0.9],
|
||||
tex_i: 1,
|
||||
coords: [1.0, 0.0],
|
||||
},
|
||||
Vertex {
|
||||
position: [0.1, -0.1],
|
||||
tex_i: 1,
|
||||
coords: [0.0, 1.0],
|
||||
},
|
||||
Vertex {
|
||||
position: [0.9, -0.1],
|
||||
tex_i: 1,
|
||||
coords: [1.0, 1.0],
|
||||
},
|
||||
]
|
||||
.iter()
|
||||
.cloned(),
|
||||
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;
|
||||
|
@ -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();
|
||||
|
@ -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();
|
||||
|
@ -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! {
|
||||
|
@ -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();
|
||||
|
@ -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();
|
||||
|
@ -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)]
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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,50 +237,45 @@ 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,
|
||||
[
|
||||
Vertex {
|
||||
position: [-0.5, -0.25],
|
||||
},
|
||||
Vertex {
|
||||
position: [0.0, 0.5],
|
||||
},
|
||||
Vertex {
|
||||
position: [0.25, -0.1],
|
||||
},
|
||||
Vertex {
|
||||
position: [0.9, 0.9],
|
||||
},
|
||||
Vertex {
|
||||
position: [0.9, 0.8],
|
||||
},
|
||||
Vertex {
|
||||
position: [0.8, 0.8],
|
||||
},
|
||||
Vertex {
|
||||
position: [-0.9, 0.9],
|
||||
},
|
||||
Vertex {
|
||||
position: [-0.7, 0.6],
|
||||
},
|
||||
Vertex {
|
||||
position: [-0.5, 0.9],
|
||||
},
|
||||
]
|
||||
.iter()
|
||||
.cloned(),
|
||||
)
|
||||
.unwrap();
|
||||
let vertices = [
|
||||
Vertex {
|
||||
position: [-0.5, -0.25],
|
||||
},
|
||||
Vertex {
|
||||
position: [0.0, 0.5],
|
||||
},
|
||||
Vertex {
|
||||
position: [0.25, -0.1],
|
||||
},
|
||||
Vertex {
|
||||
position: [0.9, 0.9],
|
||||
},
|
||||
Vertex {
|
||||
position: [0.9, 0.8],
|
||||
},
|
||||
Vertex {
|
||||
position: [0.8, 0.8],
|
||||
},
|
||||
Vertex {
|
||||
position: [-0.9, 0.9],
|
||||
},
|
||||
Vertex {
|
||||
position: [-0.7, 0.6],
|
||||
},
|
||||
Vertex {
|
||||
position: [-0.5, 0.9],
|
||||
},
|
||||
];
|
||||
let vertex_buffer =
|
||||
CpuAccessibleBuffer::from_iter(device.clone(), BufferUsage::all(), false, vertices)
|
||||
.unwrap();
|
||||
|
||||
let vs = vs::load(device.clone()).unwrap();
|
||||
let tcs = tcs::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;
|
||||
|
@ -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,32 +135,31 @@ 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 vertices = [
|
||||
Vertex {
|
||||
position: [-0.2, -0.5],
|
||||
},
|
||||
Vertex {
|
||||
position: [-0.5, 0.8],
|
||||
},
|
||||
Vertex {
|
||||
position: [0.4, -0.5],
|
||||
},
|
||||
Vertex {
|
||||
position: [0.5, 0.2],
|
||||
},
|
||||
];
|
||||
let vertex_buffer = CpuAccessibleBuffer::<[Vertex]>::from_iter(
|
||||
device.clone(),
|
||||
BufferUsage::all(),
|
||||
false,
|
||||
[
|
||||
Vertex {
|
||||
position: [-0.2, -0.5],
|
||||
},
|
||||
Vertex {
|
||||
position: [-0.5, 0.8],
|
||||
},
|
||||
Vertex {
|
||||
position: [0.4, -0.5],
|
||||
},
|
||||
Vertex {
|
||||
position: [0.5, 0.2],
|
||||
},
|
||||
]
|
||||
.iter()
|
||||
.cloned(),
|
||||
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;
|
||||
|
@ -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,37 +244,32 @@ 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,
|
||||
[
|
||||
Vertex {
|
||||
position: [-0.5, -0.25],
|
||||
},
|
||||
Vertex {
|
||||
position: [0.0, 0.5],
|
||||
},
|
||||
Vertex {
|
||||
position: [0.25, -0.1],
|
||||
},
|
||||
]
|
||||
.iter()
|
||||
.cloned(),
|
||||
)
|
||||
.unwrap();
|
||||
let vertices = [
|
||||
Vertex {
|
||||
position: [-0.5, -0.25],
|
||||
},
|
||||
Vertex {
|
||||
position: [0.0, 0.5],
|
||||
},
|
||||
Vertex {
|
||||
position: [0.25, -0.1],
|
||||
},
|
||||
];
|
||||
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;
|
||||
|
2141
examples/src/lib.rs
2141
examples/src/lib.rs
File diff suppressed because it is too large
Load Diff
@ -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"
|
||||
|
@ -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();
|
||||
});
|
||||
}
|
||||
|
@ -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 {
|
||||
self.device()
|
||||
.physical_device()
|
||||
.properties()
|
||||
.min_uniform_buffer_offset_alignment
|
||||
} else {
|
||||
1
|
||||
},
|
||||
if self.usage.storage_buffer {
|
||||
self.device()
|
||||
.physical_device()
|
||||
.properties()
|
||||
.min_storage_buffer_offset_alignment
|
||||
} else {
|
||||
1
|
||||
},
|
||||
);
|
||||
let align_uniform = if self.usage.uniform_buffer {
|
||||
self.device()
|
||||
.physical_device()
|
||||
.properties()
|
||||
.min_uniform_buffer_offset_alignment
|
||||
} else {
|
||||
1
|
||||
};
|
||||
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]
|
||||
|
@ -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]
|
||||
|
@ -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]
|
||||
|
@ -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)]
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
});
|
||||
|
@ -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()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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,25 +1648,28 @@ 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 }
|
||||
.into(),
|
||||
CheckIndirectBufferError::MaxDrawIndirectCountLimitExceeded {
|
||||
limit,
|
||||
requested: draw_count,
|
||||
}
|
||||
.into(),
|
||||
);
|
||||
}
|
||||
|
||||
unsafe {
|
||||
self.inner.draw_indirect(
|
||||
indirect_buffer,
|
||||
requested,
|
||||
mem::size_of::<DrawIndirectCommand>() as u32,
|
||||
draw_count,
|
||||
size_of::<DrawIndirectCommand>() as u32,
|
||||
)?;
|
||||
}
|
||||
|
||||
@ -1780,25 +1767,28 @@ 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 }
|
||||
.into(),
|
||||
CheckIndirectBufferError::MaxDrawIndirectCountLimitExceeded {
|
||||
limit,
|
||||
requested: draw_count,
|
||||
}
|
||||
.into(),
|
||||
);
|
||||
}
|
||||
|
||||
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 {
|
||||
|
@ -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,
|
||||
|
@ -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 {
|
||||
|
@ -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()
|
||||
|
@ -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()
|
||||
|
@ -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,17 +123,12 @@ 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() {
|
||||
return Err(CheckCopyBufferImageError::BufferTooSmall {
|
||||
required_len,
|
||||
actual_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_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)
|
||||
}
|
||||
}
|
||||
|
@ -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()
|
||||
|
@ -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);
|
||||
|
@ -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)]
|
||||
|
@ -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()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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,
|
||||
|
@ -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()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
});
|
||||
|
@ -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]
|
||||
|
@ -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,55 +1191,184 @@ 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,
|
||||
{
|
||||
/// # 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.
|
||||
|
||||
let range = ash::vk::MappedMemoryRange {
|
||||
memory: self.memory.internal_object(),
|
||||
offset: range.start,
|
||||
size: range.end - range.start,
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
let fns = self.memory.device().fns();
|
||||
let pointer = T::ref_from_ptr(
|
||||
(self.pointer as usize + range.start as usize) as *mut _,
|
||||
check_errors(fns.v1_0.invalidate_mapped_memory_ranges(
|
||||
self.memory.device().internal_object(),
|
||||
1,
|
||||
&range,
|
||||
))?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// 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,
|
||||
)
|
||||
.unwrap(); // TODO: error
|
||||
);
|
||||
|
||||
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 {
|
||||
let range = ash::vk::MappedMemoryRange {
|
||||
memory: self.memory.internal_object(),
|
||||
offset: range.start,
|
||||
size: range.end - range.start,
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
// TODO: return result instead?
|
||||
check_errors(fns.v1_0.invalidate_mapped_memory_ranges(
|
||||
self.memory.device().internal_object(),
|
||||
1,
|
||||
&range,
|
||||
))
|
||||
.unwrap();
|
||||
// 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,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
CpuAccess {
|
||||
pointer: pointer,
|
||||
mem: self,
|
||||
coherent: self.coherent,
|
||||
range,
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
@ -1249,228 +1396,84 @@ 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),
|
||||
|
||||
/// Memory map failed.
|
||||
MemoryMapFailed,
|
||||
|
||||
/// Tried to map memory whose type is not host-visible.
|
||||
NotHostVisible,
|
||||
|
||||
/// The specified `range` is not contained within the allocated or mapped memory range.
|
||||
OutOfRange {
|
||||
provided_range: Range<DeviceSize>,
|
||||
allowed_range: Range<DeviceSize>,
|
||||
},
|
||||
|
||||
/// 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,
|
||||
},
|
||||
}
|
||||
|
||||
unsafe impl Send for DeviceMemoryMapping {}
|
||||
unsafe impl Sync for DeviceMemoryMapping {}
|
||||
|
||||
/// 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,
|
||||
}
|
||||
|
||||
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");
|
||||
|
||||
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 {
|
||||
impl error::Error for MemoryMapError {
|
||||
#[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,
|
||||
range: Range<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)]
|
||||
#[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 }
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T: ?Sized + 'a> DerefMut for CpuAccess<'a, T> {
|
||||
#[inline]
|
||||
fn deref_mut(&mut self) -> &mut T {
|
||||
unsafe { &mut *self.pointer }
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T: ?Sized + 'a> Drop for CpuAccess<'a, T> {
|
||||
#[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 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,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[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;
|
||||
impl From<Error> for MemoryMapError {
|
||||
#[inline]
|
||||
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),
|
||||
}
|
||||
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 {}
|
||||
impl From<OomError> for MemoryMapError {
|
||||
#[inline]
|
||||
fn from(err: OomError) -> Self {
|
||||
Self::OomError(err)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
|
@ -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> {}
|
||||
|
||||
*/
|
||||
|
@ -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)
|
||||
};
|
||||
|
||||
|
@ -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)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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(),
|
||||
|
@ -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]
|
||||
|
@ -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>;
|
||||
}
|
||||
|
@ -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(),
|
||||
|
Loading…
Reference in New Issue
Block a user