Merge branch 'master' into moltenvk

This commit is contained in:
Pierre Krieger 2017-06-03 13:04:17 +02:00
commit 41eb21c291
74 changed files with 3456 additions and 2827 deletions

View File

@ -100,7 +100,7 @@ fn main() {
// Create an image in order to generate some additional logging:
let pixel_format = Format::R8G8B8A8Uint;
let dimensions = Dimensions::Dim2d { width: 4096, height: 4096 };
ImmutableImage::new(&device, dimensions, pixel_format, Some(queue.family())).unwrap();
ImmutableImage::new(device.clone(), dimensions, pixel_format, Some(queue.family())).unwrap();
// (At this point you should see a bunch of messages printed to the terminal window - have fun debugging!)
}

View File

@ -34,9 +34,9 @@ fn main() {
println!("Using device: {} (type: {:?})", physical.name(), physical.ty());
let events_loop = winit::EventsLoop::new();
let window = winit::WindowBuilder::new().build_vk_surface(&events_loop, &instance).unwrap();
let window = winit::WindowBuilder::new().build_vk_surface(&events_loop, instance.clone()).unwrap();
let queue = physical.queue_families().find(|q| q.supports_graphics() &&
let queue = physical.queue_families().find(|&q| q.supports_graphics() &&
window.surface().is_supported(q).unwrap_or(false))
.expect("couldn't find a graphical queue family");
@ -50,15 +50,15 @@ fn main() {
let queue = queues.next().unwrap();
let (swapchain, images) = {
let caps = window.surface().get_capabilities(&physical).expect("failed to get surface capabilities");
let caps = window.surface().capabilities(physical).expect("failed to get surface capabilities");
let dimensions = caps.current_extent.unwrap_or([1280, 1024]);
let present = caps.present_modes.iter().next().unwrap();
let usage = caps.supported_usage_flags;
vulkano::swapchain::Swapchain::new(&device, &window.surface(), caps.min_image_count,
vulkano::swapchain::Swapchain::new(device.clone(), window.surface().clone(), caps.min_image_count,
vulkano::format::B8G8R8A8Srgb, dimensions, 1,
&usage, &queue, vulkano::swapchain::SurfaceTransform::Identity,
usage, &queue, vulkano::swapchain::SurfaceTransform::Identity,
vulkano::swapchain::CompositeAlpha::Opaque,
present, true, None).expect("failed to create swapchain")
};
@ -69,7 +69,7 @@ fn main() {
impl_vertex!(Vertex, position);
let vertex_buffer = vulkano::buffer::cpu_access::CpuAccessibleBuffer::<[Vertex]>
::from_iter(&device, &vulkano::buffer::BufferUsage::all(),
::from_iter(device.clone(), vulkano::buffer::BufferUsage::all(),
Some(queue.family()), [
Vertex { position: [-0.5, -0.5 ] },
Vertex { position: [-0.5, 0.5 ] },
@ -88,7 +88,7 @@ fn main() {
color: {
load: Clear,
store: Store,
format: images[0].format(),
format: swapchain.format(),
samples: 1,
}
},
@ -99,7 +99,7 @@ fn main() {
).unwrap()
);
let texture = vulkano::image::immutable::ImmutableImage::new(&device, vulkano::image::Dimensions::Dim2d { width: 93, height: 93 },
let texture = vulkano::image::immutable::ImmutableImage::new(device.clone(), vulkano::image::Dimensions::Dim2d { width: 93, height: 93 },
vulkano::format::R8G8B8A8Unorm, Some(queue.family())).unwrap();
@ -112,20 +112,20 @@ fn main() {
// TODO: staging buffer instead
vulkano::buffer::cpu_access::CpuAccessibleBuffer::<[[u8; 4]]>
::from_iter(&device, &vulkano::buffer::BufferUsage::all(),
::from_iter(device.clone(), vulkano::buffer::BufferUsage::all(),
Some(queue.family()), image_data_chunks)
.expect("failed to create buffer")
};
let sampler = vulkano::sampler::Sampler::new(&device, vulkano::sampler::Filter::Linear,
let sampler = vulkano::sampler::Sampler::new(device.clone(), vulkano::sampler::Filter::Linear,
vulkano::sampler::Filter::Linear, vulkano::sampler::MipmapMode::Nearest,
vulkano::sampler::SamplerAddressMode::Repeat,
vulkano::sampler::SamplerAddressMode::Repeat,
vulkano::sampler::SamplerAddressMode::Repeat,
0.0, 1.0, 0.0, 0.0).unwrap();
let pipeline = Arc::new(vulkano::pipeline::GraphicsPipeline::new(&device, vulkano::pipeline::GraphicsPipelineParams {
let pipeline = Arc::new(vulkano::pipeline::GraphicsPipeline::new(device.clone(), vulkano::pipeline::GraphicsPipelineParams {
vertex_input: vulkano::pipeline::vertex::SingleBufferDefinition::new(),
vertex_shader: vs.main_entry_point(),
input_assembly: vulkano::pipeline::input_assembly::InputAssembly {
@ -157,21 +157,16 @@ fn main() {
}));
let framebuffers = images.iter().map(|image| {
let attachments = renderpass.desc().start_attachments()
.color(image.clone());
let dimensions = [image.dimensions()[0], image.dimensions()[1], 1];
vulkano::framebuffer::Framebuffer::new(renderpass.clone(), dimensions, attachments).unwrap()
Arc::new(vulkano::framebuffer::Framebuffer::start(renderpass.clone())
.add(image.clone()).unwrap().build().unwrap())
}).collect::<Vec<_>>();
let mut submissions: Vec<Box<GpuFuture>> = Vec::new();
let mut previous_frame_end = Box::new(vulkano::sync::now(device.clone())) as Box<GpuFuture>;
loop {
while submissions.len() >= 4 {
submissions.remove(0);
}
previous_frame_end.cleanup_finished();
let (image_num, future) = swapchain.acquire_next_image(Duration::new(10, 0)).unwrap();
let (image_num, future) = vulkano::swapchain::acquire_next_image(swapchain.clone(), Duration::new(10, 0)).unwrap();
let cb = vulkano::command_buffer::AutoCommandBufferBuilder::new(device.clone(), queue.family())
.unwrap()
@ -180,18 +175,17 @@ fn main() {
//.clear_color_image(&texture, [0.0, 1.0, 0.0, 1.0])
.begin_render_pass(
framebuffers[image_num].clone(), false,
renderpass.desc().start_clear_values()
.color([0.0, 0.0, 1.0, 1.0])).unwrap()
vec![[0.0, 0.0, 1.0, 1.0].into()]).unwrap()
.draw(pipeline.clone(), vulkano::command_buffer::DynamicState::none(), vertex_buffer.clone(),
set.clone(), ()).unwrap()
.end_render_pass().unwrap()
.build().unwrap();
let future = future
let future = previous_frame_end.join(future)
.then_execute(queue.clone(), cb).unwrap()
.then_swapchain_present(queue.clone(), swapchain.clone(), image_num)
.then_signal_fence_and_flush().unwrap();
submissions.push(Box::new(future) as Box<_>);
previous_frame_end = Box::new(future) as Box<_>;
let mut done = false;
events_loop.poll_events(|ev| {

View File

@ -38,9 +38,9 @@ fn main() {
println!("Using device: {} (type: {:?})", physical.name(), physical.ty());
let events_loop = winit::EventsLoop::new();
let window = winit::WindowBuilder::new().build_vk_surface(&events_loop, &instance).unwrap();
let window = winit::WindowBuilder::new().build_vk_surface(&events_loop, instance.clone()).unwrap();
let queue = physical.queue_families().find(|q| q.supports_graphics() &&
let queue = physical.queue_families().find(|&q| q.supports_graphics() &&
window.surface().is_supported(q).unwrap_or(false))
.expect("couldn't find a graphical queue family");
@ -55,32 +55,32 @@ fn main() {
let queue = queues.next().unwrap();
let (swapchain, images) = {
let caps = window.surface().get_capabilities(&physical).expect("failed to get surface capabilities");
let caps = window.surface().capabilities(physical).expect("failed to get surface capabilities");
let dimensions = caps.current_extent.unwrap_or([1280, 1024]);
let present = caps.present_modes.iter().next().unwrap();
let usage = caps.supported_usage_flags;
let format = caps.supported_formats[0].0;
vulkano::swapchain::Swapchain::new(&device, &window.surface(), caps.min_image_count, format, dimensions, 1,
&usage, &queue, vulkano::swapchain::SurfaceTransform::Identity,
vulkano::swapchain::Swapchain::new(device.clone(), window.surface().clone(), caps.min_image_count, format, dimensions, 1,
usage, &queue, vulkano::swapchain::SurfaceTransform::Identity,
vulkano::swapchain::CompositeAlpha::Opaque,
present, true, None).expect("failed to create swapchain")
};
let depth_buffer = vulkano::image::attachment::AttachmentImage::transient(&device, images[0].dimensions(), vulkano::format::D16Unorm).unwrap().access();
let depth_buffer = vulkano::image::attachment::AttachmentImage::transient(device.clone(), images[0].dimensions(), vulkano::format::D16Unorm).unwrap();
let vertex_buffer = vulkano::buffer::cpu_access::CpuAccessibleBuffer
::from_iter(&device, &vulkano::buffer::BufferUsage::all(), Some(queue.family()), examples::VERTICES.iter().cloned())
::from_iter(device.clone(), vulkano::buffer::BufferUsage::all(), Some(queue.family()), examples::VERTICES.iter().cloned())
.expect("failed to create buffer");
let normals_buffer = vulkano::buffer::cpu_access::CpuAccessibleBuffer
::from_iter(&device, &vulkano::buffer::BufferUsage::all(), Some(queue.family()), examples::NORMALS.iter().cloned())
::from_iter(device.clone(), vulkano::buffer::BufferUsage::all(), Some(queue.family()), examples::NORMALS.iter().cloned())
.expect("failed to create buffer");
let index_buffer = vulkano::buffer::cpu_access::CpuAccessibleBuffer
::from_iter(&device, &vulkano::buffer::BufferUsage::all(), Some(queue.family()), examples::INDICES.iter().cloned())
::from_iter(device.clone(), vulkano::buffer::BufferUsage::all(), Some(queue.family()), examples::INDICES.iter().cloned())
.expect("failed to create buffer");
// note: this teapot was meant for OpenGL where the origin is at the lower left
@ -90,7 +90,7 @@ fn main() {
let scale = cgmath::Matrix4::from_scale(0.01);
let uniform_buffer = vulkano::buffer::cpu_access::CpuAccessibleBuffer::<vs::ty::Data>
::from_data(&device, &vulkano::buffer::BufferUsage::all(), Some(queue.family()),
::from_data(device.clone(), vulkano::buffer::BufferUsage::all(), Some(queue.family()),
vs::ty::Data {
world : <cgmath::Matrix4<f32> as cgmath::SquareMatrix>::identity().into(),
view : (view * scale).into(),
@ -107,13 +107,13 @@ fn main() {
color: {
load: Clear,
store: Store,
format: images[0].format(),
format: swapchain.format(),
samples: 1,
},
depth: {
load: Clear,
store: DontCare,
format: vulkano::image::ImageAccess::format(&depth_buffer),
format: vulkano::format::Format::D16Unorm,
samples: 1,
}
},
@ -124,7 +124,7 @@ fn main() {
).unwrap()
);
let pipeline = Arc::new(vulkano::pipeline::GraphicsPipeline::new(&device, vulkano::pipeline::GraphicsPipelineParams {
let pipeline = Arc::new(vulkano::pipeline::GraphicsPipeline::new(device.clone(), vulkano::pipeline::GraphicsPipelineParams {
vertex_input: vulkano::pipeline::vertex::TwoBuffersDefinition::new(),
vertex_shader: vs.main_entry_point(),
input_assembly: vulkano::pipeline::input_assembly::InputAssembly::triangle_list(),
@ -153,20 +153,17 @@ fn main() {
}));
let framebuffers = images.iter().map(|image| {
let attachments = renderpass.desc().start_attachments()
.color(image.clone()).depth(depth_buffer.clone());
let dimensions = [image.dimensions()[0], image.dimensions()[1], 1];
vulkano::framebuffer::Framebuffer::new(renderpass.clone(), dimensions, attachments).unwrap()
Arc::new(vulkano::framebuffer::Framebuffer::start(renderpass.clone())
.add(image.clone()).unwrap()
.add(depth_buffer.clone()).unwrap()
.build().unwrap())
}).collect::<Vec<_>>();
let mut submissions: Vec<Box<GpuFuture>> = Vec::new();
let mut previous_frame = Box::new(vulkano::sync::now(device.clone())) as Box<GpuFuture>;
loop {
while submissions.len() >= 4 {
submissions.remove(0);
}
previous_frame.cleanup_finished();
{
// aquiring write lock for the uniform buffer
@ -179,13 +176,15 @@ fn main() {
buffer_content.world = cgmath::Matrix4::from(rotation).into();
}
let (image_num, future) = swapchain.acquire_next_image(std::time::Duration::new(1, 0)).unwrap();
let (image_num, acquire_future) = vulkano::swapchain::acquire_next_image(swapchain.clone(), std::time::Duration::new(1, 0)).unwrap();
let command_buffer = vulkano::command_buffer::AutoCommandBufferBuilder::new(device.clone(), queue.family()).unwrap()
.begin_render_pass(
framebuffers[image_num].clone(), false,
renderpass.desc().start_clear_values()
.color([0.0, 0.0, 1.0, 1.0]).depth((1f32))).unwrap()
vec![
[0.0, 0.0, 1.0, 1.0].into(),
1f32.into()
]).unwrap()
.draw_indexed(
pipeline.clone(), vulkano::command_buffer::DynamicState::none(),
(vertex_buffer.clone(), normals_buffer.clone()),
@ -193,11 +192,11 @@ fn main() {
.end_render_pass().unwrap()
.build().unwrap();
let future = future
let future = previous_frame.join(acquire_future)
.then_execute(queue.clone(), command_buffer).unwrap()
.then_swapchain_present(queue.clone(), swapchain.clone(), image_num)
.then_signal_fence_and_flush().unwrap();
submissions.push(Box::new(future) as Box<_>);
previous_frame = Box::new(future) as Box<_>;
let mut done = false;
events_loop.poll_events(|ev| {

View File

@ -53,8 +53,10 @@ use vulkano::pipeline::vertex::SingleBufferDefinition;
use vulkano::pipeline::viewport::ViewportsState;
use vulkano::pipeline::viewport::Viewport;
use vulkano::pipeline::viewport::Scissor;
use vulkano::swapchain;
use vulkano::swapchain::SurfaceTransform;
use vulkano::swapchain::Swapchain;
use vulkano::sync::now;
use vulkano::sync::GpuFuture;
use std::sync::Arc;
@ -105,7 +107,7 @@ fn main() {
// This returns a `vulkano_win::Window` object that contains both a cross-platform winit
// window and a cross-platform Vulkan surface that represents the surface of the window.
let events_loop = winit::EventsLoop::new();
let window = winit::WindowBuilder::new().build_vk_surface(&events_loop, &instance).unwrap();
let window = winit::WindowBuilder::new().build_vk_surface(&events_loop, instance.clone()).unwrap();
// The next step is to choose which GPU queue will execute our draw commands.
//
@ -117,7 +119,7 @@ fn main() {
// queue to handle data transfers in parallel. In this example we only use one queue.
//
// We have to choose which queues to use early on, because we will need this info very soon.
let queue = physical.queue_families().find(|q| {
let queue = physical.queue_families().find(|&q| {
// We take the first queue that supports drawing to our window.
q.supports_graphics() && window.surface().is_supported(q).unwrap_or(false)
}).expect("couldn't find a graphical queue family");
@ -162,7 +164,7 @@ fn main() {
let (swapchain, images) = {
// Querying the capabilities of the surface. When we create the swapchain we can only
// pass values that are allowed by the capabilities.
let caps = window.surface().get_capabilities(&physical)
let caps = window.surface().capabilities(physical)
.expect("failed to get surface capabilities");
// We choose the dimensions of the swapchain to match the current dimensions of the window.
@ -183,8 +185,8 @@ fn main() {
let format = caps.supported_formats[0].0;
// Please take a look at the docs for the meaning of the parameters we didn't mention.
Swapchain::new(&device, &window.surface(), caps.min_image_count, format, dimensions, 1,
&caps.supported_usage_flags, &queue, SurfaceTransform::Identity, alpha,
Swapchain::new(device.clone(), window.surface().clone(), caps.min_image_count, format, dimensions, 1,
caps.supported_usage_flags, &queue, SurfaceTransform::Identity, alpha,
present, true, None).expect("failed to create swapchain")
};
@ -194,7 +196,7 @@ fn main() {
struct Vertex { position: [f32; 2] }
impl_vertex!(Vertex, position);
CpuAccessibleBuffer::from_iter(&device, &BufferUsage::all(), Some(queue.family()), [
CpuAccessibleBuffer::from_iter(device.clone(), BufferUsage::all(), Some(queue.family()), [
Vertex { position: [-0.5, -0.25] },
Vertex { position: [0.0, 0.5] },
Vertex { position: [0.25, -0.1] }
@ -244,7 +246,7 @@ fn main() {
// of your structs that implements the `FormatDesc` trait). Here we use the
// generic `vulkano::format::Format` enum because we don't know the format in
// advance.
format: images[0].format(),
format: swapchain.format(),
// TODO:
samples: 1,
}
@ -259,7 +261,7 @@ fn main() {
// Before we draw we have to create what is called a pipeline. This is similar to an OpenGL
// program, but much more specific.
let pipeline = Arc::new(GraphicsPipeline::new(&device, GraphicsPipelineParams {
let pipeline = Arc::new(GraphicsPipeline::new(device.clone(), GraphicsPipelineParams {
// We need to indicate the layout of the vertices.
// The type `SingleBufferDefinition` actually contains a template parameter corresponding
// to the type of each vertex. But in this code it is automatically inferred.
@ -323,22 +325,9 @@ fn main() {
// Since we need to draw to multiple images, we are going to create a different framebuffer for
// each image.
let framebuffers = images.iter().map(|image| {
// When we create the framebuffer we need to pass the actual list of images for the
// framebuffer's attachments.
//
// The type of data that corresponds to this list depends on the way you created the
// render pass. With the `single_pass_renderpass!` macro you need to call
// `.desc().start_attachments()`. The returned object will have a method whose name is the
// name of the first attachment. When called, it returns an object that will have a method
// whose name is the name of the second attachment. And so on. Only the object returned
// by the method of the last attachment can be passed to `Framebuffer::new`.
let attachments = render_pass.desc().start_attachments().color(image.clone());
// Actually creating the framebuffer. Note that we have to pass the dimensions of the
// framebuffer. These dimensions must be inferior or equal to the intersection of the
// dimensions of all the attachments.
let dimensions = [image.dimensions()[0], image.dimensions()[1], 1];
Framebuffer::new(render_pass.clone(), dimensions, attachments).unwrap()
Arc::new(Framebuffer::start(render_pass.clone())
.add(image.clone()).unwrap()
.build().unwrap())
}).collect::<Vec<_>>();
// Initialization is finally finished!
@ -348,15 +337,15 @@ fn main() {
// they are in use by the GPU.
//
// Destroying the `GpuFuture` blocks until the GPU is finished executing it. In order to avoid
// that, we store them in a `Vec` and clean them from time to time.
let mut submissions: Vec<Box<GpuFuture>> = Vec::new();
// that, we store the submission of the previous frame here.
let mut previous_frame_end = Box::new(now(device.clone())) as Box<GpuFuture>;
loop {
// Clearing the old submissions by keeping alive only the ones which probably aren't
// finished.
while submissions.len() >= 4 {
submissions.remove(0);
}
// It is important to call this function from time to time, otherwise resources will keep
// accumulating and you will eventually reach an out of memory error.
// Calling this function polls various fences in order to determine what the GPU has
// already processed, and frees the resources that are no longer needed.
previous_frame_end.cleanup_finished();
// Before we can draw on the output, we have to *acquire* an image from the swapchain. If
// no image is available (which happens if you submit draw commands too quickly), then the
@ -365,7 +354,8 @@ fn main() {
//
// This function can block if no image is available. The parameter is a timeout after
// which the function call will return an error.
let (image_num, future) = swapchain.acquire_next_image(Duration::new(1, 0)).unwrap();
let (image_num, acquire_future) = swapchain::acquire_next_image(swapchain.clone(),
Duration::new(1, 0)).unwrap();
// In order to draw, we have to build a *command buffer*. The command buffer object holds
// the list of commands that are going to be executed.
@ -385,7 +375,7 @@ fn main() {
// is similar to the list of attachments when building the framebuffers, except that
// only the attachments that use `load: Clear` appear in the list.
.begin_render_pass(framebuffers[image_num].clone(), false,
render_pass.desc().start_clear_values().color([0.0, 0.0, 1.0, 1.0]))
vec![[0.0, 0.0, 1.0, 1.0].into()])
.unwrap()
// We are now inside the first subpass of the render pass. We add a draw command.
@ -404,7 +394,7 @@ fn main() {
// Finish building the command buffer by calling `build`.
.build().unwrap();
let future = future
let future = previous_frame_end.join(acquire_future)
.then_execute(queue.clone(), command_buffer).unwrap()
// The color output is now expected to contain our triangle. But in order to show it on
@ -415,7 +405,7 @@ fn main() {
// the GPU has finished executing the command buffer that draws the triangle.
.then_swapchain_present(queue.clone(), swapchain.clone(), image_num)
.then_signal_fence_and_flush().unwrap();
submissions.push(Box::new(future) as Box<_>);
previous_frame_end = Box::new(future) as Box<_>;
// Note that in more complex programs it is likely that one of `acquire_next_image`,
// `command_buffer::submit`, or `present` will block for some time. This happens when the

View File

@ -52,11 +52,11 @@ pub fn required_extensions() -> InstanceExtensions {
}
pub trait VkSurfaceBuild {
fn build_vk_surface(self, events_loop: &EventsLoop, instance: &Arc<Instance>) -> Result<Window, CreationError>;
fn build_vk_surface(self, events_loop: &EventsLoop, instance: Arc<Instance>) -> Result<Window, CreationError>;
}
impl VkSurfaceBuild for WindowBuilder {
fn build_vk_surface(self, events_loop: &EventsLoop, instance: &Arc<Instance>) -> Result<Window, CreationError> {
fn build_vk_surface(self, events_loop: &EventsLoop, instance: Arc<Instance>) -> Result<Window, CreationError> {
let window = try!(self.build(events_loop));
let surface = try!(unsafe { winit_to_surface(instance, &window) });
@ -133,7 +133,7 @@ impl From<WindowCreationError> for CreationError {
}
#[cfg(target_os = "android")]
unsafe fn winit_to_surface(instance: &Arc<Instance>,
unsafe fn winit_to_surface(instance: Arc<Instance>,
win: &winit::Window)
-> Result<Arc<Surface>, SurfaceCreationError> {
use winit::os::android::WindowExt;
@ -141,7 +141,7 @@ unsafe fn winit_to_surface(instance: &Arc<Instance>,
}
#[cfg(all(unix, not(target_os = "android"), not(target_os = "macos")))]
unsafe fn winit_to_surface(instance: &Arc<Instance>,
unsafe fn winit_to_surface(instance: Arc<Instance>,
win: &winit::Window)
-> Result<Arc<Surface>, SurfaceCreationError> {
use winit::os::unix::WindowExt;
@ -164,7 +164,7 @@ unsafe fn winit_to_surface(instance: &Arc<Instance>,
}
#[cfg(target_os = "windows")]
unsafe fn winit_to_surface(instance: &Arc<Instance>,
unsafe fn winit_to_surface(instance: Arc<Instance>,
win: &winit::Window)
-> Result<Arc<Surface>, SurfaceCreationError> {
use winit::os::windows::WindowExt;
@ -174,7 +174,7 @@ unsafe fn winit_to_surface(instance: &Arc<Instance>,
}
#[cfg(target_os = "macos")]
unsafe fn winit_to_surface(instance: &Arc<Instance>, win: &winit::Window)
unsafe fn winit_to_surface(instance: Arc<Instance>, win: &winit::Window)
-> Result<Arc<Surface>, SurfaceCreationError>
{
use winit::os::macos::WindowExt;

View File

@ -31,7 +31,7 @@ use smallvec::SmallVec;
use buffer::sys::BufferCreationError;
use buffer::sys::SparseLevel;
use buffer::sys::UnsafeBuffer;
use buffer::sys::Usage;
use buffer::BufferUsage;
use buffer::traits::BufferAccess;
use buffer::traits::BufferInner;
use buffer::traits::Buffer;
@ -47,6 +47,7 @@ use memory::pool::AllocLayout;
use memory::pool::MemoryPool;
use memory::pool::MemoryPoolAlloc;
use memory::pool::StdMemoryPool;
use sync::AccessError;
use sync::Sharing;
use sync::AccessFlagBits;
use sync::PipelineStages;
@ -77,7 +78,7 @@ impl<T> CpuAccessibleBuffer<T> {
/// Deprecated. Use `from_data` instead.
#[deprecated]
#[inline]
pub fn new<'a, I>(device: &Arc<Device>, usage: &Usage, queue_families: I)
pub fn new<'a, I>(device: Arc<Device>, usage: BufferUsage, queue_families: I)
-> Result<Arc<CpuAccessibleBuffer<T>>, OomError>
where I: IntoIterator<Item = QueueFamily<'a>>
{
@ -87,7 +88,7 @@ impl<T> CpuAccessibleBuffer<T> {
}
/// Builds a new buffer with some data in it. Only allowed for sized data.
pub fn from_data<'a, I>(device: &Arc<Device>, usage: &Usage, queue_families: I, data: T)
pub fn from_data<'a, I>(device: Arc<Device>, usage: BufferUsage, queue_families: I, data: T)
-> Result<Arc<CpuAccessibleBuffer<T>>, OomError>
where I: IntoIterator<Item = QueueFamily<'a>>,
T: Content + 'static,
@ -112,7 +113,7 @@ impl<T> CpuAccessibleBuffer<T> {
/// Builds a new uninitialized buffer. Only allowed for sized data.
#[inline]
pub unsafe fn uninitialized<'a, I>(device: &Arc<Device>, usage: &Usage, queue_families: I)
pub unsafe fn uninitialized<'a, I>(device: Arc<Device>, usage: BufferUsage, queue_families: I)
-> Result<Arc<CpuAccessibleBuffer<T>>, OomError>
where I: IntoIterator<Item = QueueFamily<'a>>
{
@ -123,7 +124,7 @@ impl<T> CpuAccessibleBuffer<T> {
impl<T> CpuAccessibleBuffer<[T]> {
/// Builds a new buffer that contains an array `T`. The initial data comes from an iterator
/// that produces that list of Ts.
pub fn from_iter<'a, I, Q>(device: &Arc<Device>, usage: &Usage, queue_families: Q, data: I)
pub fn from_iter<'a, I, Q>(device: Arc<Device>, usage: BufferUsage, queue_families: Q, data: I)
-> Result<Arc<CpuAccessibleBuffer<[T]>>, OomError>
where I: ExactSizeIterator<Item = T>,
T: Content + 'static,
@ -154,7 +155,7 @@ impl<T> CpuAccessibleBuffer<[T]> {
// TODO: remove
#[inline]
#[deprecated]
pub fn array<'a, I>(device: &Arc<Device>, len: usize, usage: &Usage, queue_families: I)
pub fn array<'a, I>(device: Arc<Device>, len: usize, usage: BufferUsage, queue_families: I)
-> Result<Arc<CpuAccessibleBuffer<[T]>>, OomError>
where I: IntoIterator<Item = QueueFamily<'a>>
{
@ -165,7 +166,7 @@ impl<T> CpuAccessibleBuffer<[T]> {
/// Builds a new buffer. Can be used for arrays.
#[inline]
pub unsafe fn uninitialized_array<'a, I>(device: &Arc<Device>, len: usize, usage: &Usage,
pub unsafe fn uninitialized_array<'a, I>(device: Arc<Device>, len: usize, usage: BufferUsage,
queue_families: I)
-> Result<Arc<CpuAccessibleBuffer<[T]>>, OomError>
where I: IntoIterator<Item = QueueFamily<'a>>
@ -181,7 +182,7 @@ impl<T: ?Sized> CpuAccessibleBuffer<T> {
///
/// You must ensure that the size that you pass is correct for `T`.
///
pub unsafe fn raw<'a, I>(device: &Arc<Device>, size: usize, usage: &Usage, queue_families: I)
pub unsafe fn raw<'a, I>(device: Arc<Device>, size: usize, usage: BufferUsage, queue_families: I)
-> Result<Arc<CpuAccessibleBuffer<T>>, OomError>
where I: IntoIterator<Item = QueueFamily<'a>>
{
@ -195,7 +196,7 @@ impl<T: ?Sized> CpuAccessibleBuffer<T> {
Sharing::Exclusive
};
match UnsafeBuffer::new(device, size, &usage, sharing, SparseLevel::none()) {
match UnsafeBuffer::new(device.clone(), size, usage, sharing, SparseLevel::none()) {
Ok(b) => b,
Err(BufferCreationError::OomError(err)) => return Err(err),
Err(_) => unreachable!() // We don't use sparse binding, therefore the other
@ -208,7 +209,7 @@ impl<T: ?Sized> CpuAccessibleBuffer<T> {
.filter(|t| t.is_host_visible())
.next().unwrap(); // Vk specs guarantee that this can't fail
let mem = try!(MemoryPool::alloc(&Device::standard_pool(device), mem_ty,
let mem = try!(MemoryPool::alloc(&Device::standard_pool(&device), mem_ty,
mem_reqs.size, mem_reqs.alignment, AllocLayout::Linear));
debug_assert!((mem.offset() % mem_reqs.alignment) == 0);
debug_assert!(mem.mapped_memory().is_some());
@ -325,8 +326,8 @@ unsafe impl<T: ?Sized, A> BufferAccess for CpuAccessibleBuffer<T, A>
}
#[inline]
fn try_gpu_lock(&self, exclusive_access: bool, queue: &Queue) -> bool {
true // FIXME:
fn try_gpu_lock(&self, exclusive_access: bool, queue: &Queue) -> Result<(), AccessError> {
Ok(()) // FIXME:
}
#[inline]

View File

@ -21,7 +21,7 @@ use smallvec::SmallVec;
use buffer::sys::BufferCreationError;
use buffer::sys::SparseLevel;
use buffer::sys::UnsafeBuffer;
use buffer::sys::Usage;
use buffer::BufferUsage;
use buffer::traits::BufferAccess;
use buffer::traits::BufferInner;
use buffer::traits::Buffer;
@ -35,6 +35,7 @@ use memory::pool::AllocLayout;
use memory::pool::MemoryPool;
use memory::pool::MemoryPoolAlloc;
use memory::pool::StdMemoryPool;
use sync::AccessError;
use sync::Sharing;
use OomError;
@ -43,7 +44,7 @@ use OomError;
///
/// This buffer is especially suitable when you want to upload or download some data at each frame.
///
/// # Usage
/// # BufferUsage
///
/// A `CpuBufferPool` is a bit similar to a `Vec`. You start by creating an empty pool, then you
/// grab elements from the pool and use them, and if the pool is full it will automatically grow
@ -71,7 +72,7 @@ pub struct CpuBufferPool<T: ?Sized, A = Arc<StdMemoryPool>> where A: MemoryPool
one_size: usize,
// Buffer usage.
usage: Usage,
usage: BufferUsage,
// Queue families allowed to access this buffer.
queue_families: SmallVec<[u32; 4]>,
@ -131,7 +132,7 @@ pub struct CpuBufferPoolSubbuffer<T: ?Sized, A> where A: MemoryPool {
impl<T> CpuBufferPool<T> {
#[inline]
pub fn new<'a, I>(device: Arc<Device>, usage: &Usage, queue_families: I)
pub fn new<'a, I>(device: Arc<Device>, usage: BufferUsage, queue_families: I)
-> CpuBufferPool<T>
where I: IntoIterator<Item = QueueFamily<'a>>
{
@ -146,13 +147,13 @@ impl<T> CpuBufferPool<T> {
/// family accesses.
#[inline]
pub fn upload(device: Arc<Device>) -> CpuBufferPool<T> {
CpuBufferPool::new(device, &Usage::transfer_source(), iter::empty())
CpuBufferPool::new(device, BufferUsage::transfer_source(), iter::empty())
}
}
impl<T> CpuBufferPool<[T]> {
#[inline]
pub fn array<'a, I>(device: Arc<Device>, len: usize, usage: &Usage, queue_families: I)
pub fn array<'a, I>(device: Arc<Device>, len: usize, usage: BufferUsage, queue_families: I)
-> CpuBufferPool<[T]>
where I: IntoIterator<Item = QueueFamily<'a>>
{
@ -164,7 +165,7 @@ impl<T> CpuBufferPool<[T]> {
impl<T: ?Sized> CpuBufferPool<T> {
pub unsafe fn raw<'a, I>(device: Arc<Device>, one_size: usize,
usage: &Usage, queue_families: I) -> CpuBufferPool<T>
usage: BufferUsage, queue_families: I) -> CpuBufferPool<T>
where I: IntoIterator<Item = QueueFamily<'a>>
{
let queue_families = queue_families.into_iter().map(|f| f.id())
@ -265,7 +266,7 @@ impl<T, A> CpuBufferPool<T, A> where A: MemoryPool {
None => return Err(OomError::OutOfDeviceMemory),
};
match UnsafeBuffer::new(&self.device, total_size, &self.usage, sharing, SparseLevel::none()) {
match UnsafeBuffer::new(self.device.clone(), total_size, self.usage, sharing, SparseLevel::none()) {
Ok(b) => b,
Err(BufferCreationError::OomError(err)) => return Err(err),
Err(_) => unreachable!() // We don't use sparse binding, therefore the other
@ -436,15 +437,15 @@ unsafe impl<T: ?Sized, A> BufferAccess for CpuBufferPoolSubbuffer<T, A>
}
#[inline]
fn try_gpu_lock(&self, _: bool, _: &Queue) -> bool {
fn try_gpu_lock(&self, _: bool, _: &Queue) -> Result<(), AccessError> {
let in_use = &self.buffer.subbuffers[self.subbuffer_index].num_gpu_accesses;
if in_use.compare_and_swap(0, 1, Ordering::SeqCst) != 0 {
return false;
return Err(AccessError::AlreadyInUse);
}
let was_locked = self.gpu_locked.swap(true, Ordering::SeqCst);
debug_assert!(!was_locked);
true
Ok(())
}
#[inline]

View File

@ -22,7 +22,7 @@ use smallvec::SmallVec;
use buffer::sys::BufferCreationError;
use buffer::sys::SparseLevel;
use buffer::sys::UnsafeBuffer;
use buffer::sys::Usage;
use buffer::BufferUsage;
use buffer::traits::BufferAccess;
use buffer::traits::BufferInner;
use buffer::traits::Buffer;
@ -36,6 +36,7 @@ use memory::pool::AllocLayout;
use memory::pool::MemoryPool;
use memory::pool::MemoryPoolAlloc;
use memory::pool::StdMemoryPool;
use sync::AccessError;
use sync::Sharing;
use OomError;
@ -63,7 +64,7 @@ pub struct DeviceLocalBuffer<T: ?Sized, A = Arc<StdMemoryPool>> where A: MemoryP
impl<T> DeviceLocalBuffer<T> {
/// Builds a new buffer. Only allowed for sized data.
#[inline]
pub fn new<'a, I>(device: &Arc<Device>, usage: &Usage, queue_families: I)
pub fn new<'a, I>(device: Arc<Device>, usage: BufferUsage, queue_families: I)
-> Result<Arc<DeviceLocalBuffer<T>>, OomError>
where I: IntoIterator<Item = QueueFamily<'a>>
{
@ -76,7 +77,7 @@ impl<T> DeviceLocalBuffer<T> {
impl<T> DeviceLocalBuffer<[T]> {
/// Builds a new buffer. Can be used for arrays.
#[inline]
pub fn array<'a, I>(device: &Arc<Device>, len: usize, usage: &Usage, queue_families: I)
pub fn array<'a, I>(device: Arc<Device>, len: usize, usage: BufferUsage, queue_families: I)
-> Result<Arc<DeviceLocalBuffer<[T]>>, OomError>
where I: IntoIterator<Item = QueueFamily<'a>>
{
@ -93,7 +94,7 @@ impl<T: ?Sized> DeviceLocalBuffer<T> {
///
/// You must ensure that the size that you pass is correct for `T`.
///
pub unsafe fn raw<'a, I>(device: &Arc<Device>, size: usize, usage: &Usage, queue_families: I)
pub unsafe fn raw<'a, I>(device: Arc<Device>, size: usize, usage: BufferUsage, queue_families: I)
-> Result<Arc<DeviceLocalBuffer<T>>, OomError>
where I: IntoIterator<Item = QueueFamily<'a>>
{
@ -107,7 +108,7 @@ impl<T: ?Sized> DeviceLocalBuffer<T> {
Sharing::Exclusive
};
match UnsafeBuffer::new(device, size, &usage, sharing, SparseLevel::none()) {
match UnsafeBuffer::new(device.clone(), size, usage, sharing, SparseLevel::none()) {
Ok(b) => b,
Err(BufferCreationError::OomError(err)) => return Err(err),
Err(_) => unreachable!() // We don't use sparse binding, therefore the other
@ -124,7 +125,7 @@ impl<T: ?Sized> DeviceLocalBuffer<T> {
device_local.chain(any).next().unwrap()
};
let mem = try!(MemoryPool::alloc(&Device::standard_pool(device), mem_ty,
let mem = try!(MemoryPool::alloc(&Device::standard_pool(&device), mem_ty,
mem_reqs.size, mem_reqs.alignment, AllocLayout::Linear));
debug_assert!((mem.offset() % mem_reqs.alignment) == 0);
try!(buffer.bind_memory(mem.memory(), mem.offset()));
@ -204,7 +205,7 @@ unsafe impl<P, T: ?Sized, A> BufferAccess for DeviceLocalBufferAccess<P>
}
#[inline]
fn try_gpu_lock(&self, _: bool, _: &Queue) -> bool {
fn try_gpu_lock(&self, _: bool, _: &Queue) -> Result<(), AccessError> {
// FIXME: not implemented correctly
/*let val = self.0.gpu_lock.fetch_add(1, Ordering::SeqCst);
if val == 1 {
@ -213,7 +214,7 @@ unsafe impl<P, T: ?Sized, A> BufferAccess for DeviceLocalBufferAccess<P>
self.0.gpu_lock.fetch_sub(1, Ordering::SeqCst);
false
}*/
true
Ok(())
}
#[inline]

View File

@ -32,7 +32,7 @@ use buffer::CpuAccessibleBuffer;
use buffer::sys::BufferCreationError;
use buffer::sys::SparseLevel;
use buffer::sys::UnsafeBuffer;
use buffer::sys::Usage;
use buffer::BufferUsage;
use buffer::traits::BufferAccess;
use buffer::traits::BufferInner;
use buffer::traits::Buffer;
@ -54,6 +54,7 @@ use memory::pool::AllocLayout;
use memory::pool::MemoryPool;
use memory::pool::MemoryPoolAlloc;
use memory::pool::StdMemoryPoolAlloc;
use sync::AccessError;
use sync::NowFuture;
use sync::Sharing;
@ -93,12 +94,12 @@ impl<T: ?Sized> ImmutableBuffer<T> {
/// 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.
pub fn from_data<'a, I>(data: T, usage: &Usage, queue_families: I, queue: Arc<Queue>)
pub fn from_data<'a, I>(data: T, usage: BufferUsage, queue_families: I, queue: Arc<Queue>)
-> Result<(Arc<ImmutableBuffer<T>>, ImmutableBufferFromBufferFuture), OomError>
where I: IntoIterator<Item = QueueFamily<'a>>,
T: 'static + Send + Sync + Sized,
{
let source = CpuAccessibleBuffer::from_data(queue.device(), &Usage::transfer_source(),
let source = CpuAccessibleBuffer::from_data(queue.device().clone(), BufferUsage::transfer_source(),
iter::once(queue.family()), data)?;
ImmutableBuffer::from_buffer(source, usage, queue_families, queue)
}
@ -109,7 +110,7 @@ impl<T: ?Sized> ImmutableBuffer<T> {
/// 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.
pub fn from_buffer<'a, B, I>(source: B, usage: &Usage, queue_families: I, queue: Arc<Queue>)
pub fn from_buffer<'a, B, I>(source: B, usage: BufferUsage, queue_families: I, queue: Arc<Queue>)
-> Result<(Arc<ImmutableBuffer<T>>, ImmutableBufferFromBufferFuture), OomError>
where B: Buffer + TypedBuffer<Content = T> + DeviceOwned, // TODO: remove + DeviceOwned once Buffer requires it
B::Access: 'static + Clone + Send + Sync,
@ -140,7 +141,7 @@ impl<T: ?Sized> ImmutableBuffer<T> {
}
/// Builds an `ImmutableBuffer` that copies its data from another buffer.
pub fn from_buffer_with_builder<'a, B, I, Cb, O>(source: B, usage: &Usage, queue_families: I,
pub fn from_buffer_with_builder<'a, B, I, Cb, O>(source: B, usage: BufferUsage, queue_families: I,
builder: Cb)
-> Result<(Arc<ImmutableBuffer<T>>, O), ImmutableBufferFromBufferWithBuilderError>
where B: Buffer + TypedBuffer<Content = T> + DeviceOwned, // TODO: remove + DeviceOwned once Buffer requires it
@ -150,13 +151,13 @@ impl<T: ?Sized> ImmutableBuffer<T> {
{
unsafe {
// We automatically set `transfer_dest` to true in order to avoid annoying errors.
let actual_usage = Usage {
let actual_usage = BufferUsage {
transfer_dest: true,
.. *usage
.. usage
};
let (buffer, init) = ImmutableBuffer::raw(source.device().clone(), source.size(),
&actual_usage, queue_families)?;
actual_usage, queue_families)?;
let builder = builder.copy_buffer(source, init)?;
Ok((buffer, builder))
@ -182,7 +183,7 @@ impl<T> ImmutableBuffer<T> {
/// data, otherwise the content is undefined.
///
#[inline]
pub unsafe fn uninitialized<'a, I>(device: Arc<Device>, usage: &Usage, queue_families: I)
pub unsafe fn uninitialized<'a, I>(device: Arc<Device>, usage: BufferUsage, queue_families: I)
-> Result<(Arc<ImmutableBuffer<T>>, ImmutableBufferInitialization<T>), OomError>
where I: IntoIterator<Item = QueueFamily<'a>>
{
@ -191,13 +192,13 @@ impl<T> ImmutableBuffer<T> {
}
impl<T> ImmutableBuffer<[T]> {
pub fn from_iter<'a, D, I>(data: D, usage: &Usage, queue_families: I, queue: Arc<Queue>)
pub fn from_iter<'a, D, I>(data: D, usage: BufferUsage, queue_families: I, queue: Arc<Queue>)
-> Result<(Arc<ImmutableBuffer<[T]>>, ImmutableBufferFromBufferFuture), OomError>
where I: IntoIterator<Item = QueueFamily<'a>>,
D: ExactSizeIterator<Item = T>,
T: 'static + Send + Sync + Sized,
{
let source = CpuAccessibleBuffer::from_iter(queue.device(), &Usage::transfer_source(),
let source = CpuAccessibleBuffer::from_iter(queue.device().clone(), BufferUsage::transfer_source(),
iter::once(queue.family()), data)?;
ImmutableBuffer::from_buffer(source, usage, queue_families, queue)
}
@ -219,7 +220,7 @@ impl<T> ImmutableBuffer<[T]> {
/// data, otherwise the content is undefined.
///
#[inline]
pub unsafe fn uninitialized_array<'a, I>(device: Arc<Device>, len: usize, usage: &Usage,
pub unsafe fn uninitialized_array<'a, I>(device: Arc<Device>, len: usize, usage: BufferUsage,
queue_families: I)
-> Result<(Arc<ImmutableBuffer<[T]>>, ImmutableBufferInitialization<[T]>), OomError>
where I: IntoIterator<Item = QueueFamily<'a>>
@ -245,7 +246,7 @@ impl<T: ?Sized> ImmutableBuffer<T> {
/// data.
///
#[inline]
pub unsafe fn raw<'a, I>(device: Arc<Device>, size: usize, usage: &Usage, queue_families: I)
pub unsafe fn raw<'a, I>(device: Arc<Device>, size: usize, usage: BufferUsage, queue_families: I)
-> Result<(Arc<ImmutableBuffer<T>>, ImmutableBufferInitialization<T>), OomError>
where I: IntoIterator<Item = QueueFamily<'a>>
{
@ -255,7 +256,7 @@ impl<T: ?Sized> ImmutableBuffer<T> {
// Internal implementation of `raw`. This is separated from `raw` so that it doesn't need to be
// inlined.
unsafe fn raw_impl(device: Arc<Device>, size: usize, usage: &Usage,
unsafe fn raw_impl(device: Arc<Device>, size: usize, usage: BufferUsage,
queue_families: SmallVec<[u32; 4]>)
-> Result<(Arc<ImmutableBuffer<T>>, ImmutableBufferInitialization<T>), OomError>
{
@ -266,7 +267,7 @@ impl<T: ?Sized> ImmutableBuffer<T> {
Sharing::Exclusive
};
match UnsafeBuffer::new(&device, size, &usage, sharing, SparseLevel::none()) {
match UnsafeBuffer::new(device.clone(), size, usage, sharing, SparseLevel::none()) {
Ok(b) => b,
Err(BufferCreationError::OomError(err)) => return Err(err),
Err(_) => unreachable!() // We don't use sparse binding, therefore the other
@ -355,16 +356,16 @@ unsafe impl<T: ?Sized, A> BufferAccess for ImmutableBuffer<T, A> {
}
#[inline]
fn try_gpu_lock(&self, exclusive_access: bool, queue: &Queue) -> bool {
fn try_gpu_lock(&self, exclusive_access: bool, queue: &Queue) -> Result<(), AccessError> {
if exclusive_access {
return false;
return Err(AccessError::ExclusiveDenied);
}
if !self.initialized.load(Ordering::Relaxed) {
return false;
return Err(AccessError::BufferNotInitialized);
}
true
Ok(())
}
#[inline]
@ -402,8 +403,12 @@ unsafe impl<T: ?Sized, A> BufferAccess for ImmutableBufferInitialization<T, A> {
}
#[inline]
fn try_gpu_lock(&self, exclusive_access: bool, queue: &Queue) -> bool {
!self.used.compare_and_swap(false, true, Ordering::Relaxed)
fn try_gpu_lock(&self, exclusive_access: bool, queue: &Queue) -> Result<(), AccessError> {
if !self.used.compare_and_swap(false, true, Ordering::Relaxed) {
Ok(())
} else {
Err(AccessError::AlreadyInUse)
}
}
#[inline]
@ -517,7 +522,7 @@ mod tests {
use std::iter;
use buffer::cpu_access::CpuAccessibleBuffer;
use buffer::immutable::ImmutableBuffer;
use buffer::sys::Usage;
use buffer::BufferUsage;
use command_buffer::AutoCommandBufferBuilder;
use command_buffer::CommandBuffer;
use command_buffer::CommandBufferBuilder;
@ -527,11 +532,11 @@ mod tests {
fn from_data_working() {
let (device, queue) = gfx_dev_and_queue!();
let (buffer, _) = ImmutableBuffer::from_data(12u32, &Usage::all(),
let (buffer, _) = ImmutableBuffer::from_data(12u32, BufferUsage::all(),
iter::once(queue.family()),
queue.clone()).unwrap();
let dest = CpuAccessibleBuffer::from_data(&device, &Usage::all(),
let dest = CpuAccessibleBuffer::from_data(device.clone(), BufferUsage::all(),
iter::once(queue.family()), 0).unwrap();
let _ = AutoCommandBufferBuilder::new(device.clone(), queue.family()).unwrap()
@ -548,11 +553,11 @@ mod tests {
fn from_iter_working() {
let (device, queue) = gfx_dev_and_queue!();
let (buffer, _) = ImmutableBuffer::from_iter((0 .. 512u32).map(|n| n * 2), &Usage::all(),
let (buffer, _) = ImmutableBuffer::from_iter((0 .. 512u32).map(|n| n * 2), BufferUsage::all(),
iter::once(queue.family()),
queue.clone()).unwrap();
let dest = CpuAccessibleBuffer::from_iter(&device, &Usage::all(),
let dest = CpuAccessibleBuffer::from_iter(device.clone(), BufferUsage::all(),
iter::once(queue.family()),
(0 .. 512).map(|_| 0u32)).unwrap();
@ -573,7 +578,7 @@ mod tests {
fn writing_forbidden() {
let (device, queue) = gfx_dev_and_queue!();
let (buffer, _) = ImmutableBuffer::from_data(12u32, &Usage::all(),
let (buffer, _) = ImmutableBuffer::from_data(12u32, BufferUsage::all(),
iter::once(queue.family()),
queue.clone()).unwrap();
@ -590,11 +595,11 @@ mod tests {
let (device, queue) = gfx_dev_and_queue!();
let (buffer, _) = unsafe {
ImmutableBuffer::<u32>::uninitialized(device.clone(), &Usage::all(),
ImmutableBuffer::<u32>::uninitialized(device.clone(), BufferUsage::all(),
iter::once(queue.family())).unwrap()
};
let src = CpuAccessibleBuffer::from_data(&device, &Usage::all(),
let src = CpuAccessibleBuffer::from_data(device.clone(), BufferUsage::all(),
iter::once(queue.family()), 0).unwrap();
let _ = AutoCommandBufferBuilder::new(device.clone(), queue.family()).unwrap()
@ -609,11 +614,11 @@ mod tests {
let (device, queue) = gfx_dev_and_queue!();
let (buffer, init) = unsafe {
ImmutableBuffer::<u32>::uninitialized(device.clone(), &Usage::all(),
ImmutableBuffer::<u32>::uninitialized(device.clone(), BufferUsage::all(),
iter::once(queue.family())).unwrap()
};
let src = CpuAccessibleBuffer::from_data(&device, &Usage::all(),
let src = CpuAccessibleBuffer::from_data(device.clone(), BufferUsage::all(),
iter::once(queue.family()), 0).unwrap();
let _ = AutoCommandBufferBuilder::new(device.clone(), queue.family()).unwrap()
@ -630,11 +635,11 @@ mod tests {
let (device, queue) = gfx_dev_and_queue!();
let (buffer, init) = unsafe {
ImmutableBuffer::<u32>::uninitialized(device.clone(), &Usage::all(),
ImmutableBuffer::<u32>::uninitialized(device.clone(), BufferUsage::all(),
iter::once(queue.family())).unwrap()
};
let src = CpuAccessibleBuffer::from_data(&device, &Usage::all(),
let src = CpuAccessibleBuffer::from_data(device.clone(), BufferUsage::all(),
iter::once(queue.family()), 0).unwrap();
let cb1 = AutoCommandBufferBuilder::new(device.clone(), queue.family()).unwrap()

View File

@ -68,12 +68,12 @@ pub use self::device_local::DeviceLocalBuffer;
pub use self::immutable::ImmutableBuffer;
pub use self::slice::BufferSlice;
pub use self::sys::BufferCreationError;
pub use self::sys::Usage as BufferUsage;
pub use self::traits::BufferAccess;
pub use self::traits::BufferInner;
pub use self::traits::Buffer;
pub use self::traits::TypedBuffer;
pub use self::traits::TypedBufferAccess;
pub use self::usage::BufferUsage;
pub use self::view::BufferView;
pub use self::view::BufferViewRef;
@ -86,3 +86,4 @@ pub mod view;
mod slice;
mod traits;
mod usage;

View File

@ -20,6 +20,7 @@ use buffer::traits::Buffer;
use device::Device;
use device::DeviceOwned;
use device::Queue;
use sync::AccessError;
/// A subpart of a buffer.
///
@ -241,7 +242,7 @@ unsafe impl<T: ?Sized, B> BufferAccess for BufferSlice<T, B> where B: BufferAcce
}
#[inline]
fn try_gpu_lock(&self, exclusive_access: bool, queue: &Queue) -> bool {
fn try_gpu_lock(&self, exclusive_access: bool, queue: &Queue) -> Result<(), AccessError> {
self.resource.try_gpu_lock(exclusive_access, queue)
}

View File

@ -31,6 +31,8 @@ use std::ptr;
use std::sync::Arc;
use smallvec::SmallVec;
use buffer::BufferUsage;
use buffer::usage::usage_to_bits;
use device::Device;
use device::DeviceOwned;
use memory::DeviceMemory;
@ -62,14 +64,14 @@ impl UnsafeBuffer {
/// Panics if `sparse.sparse` is false and `sparse.sparse_residency` or
/// `sparse.sparse_aliased` is true.
///
pub unsafe fn new<'a, I>(device: &Arc<Device>, size: usize, usage: &Usage, sharing: Sharing<I>,
sparse: SparseLevel)
pub unsafe fn new<'a, I>(device: Arc<Device>, size: usize, usage: BufferUsage,
sharing: Sharing<I>, sparse: SparseLevel)
-> Result<(UnsafeBuffer, MemoryRequirements), BufferCreationError>
where I: Iterator<Item = u32>
{
let vk = device.pointers();
let usage_bits = usage.to_usage_bits();
let usage_bits = usage_to_bits(usage);
// Checking sparse features.
assert!(sparse.sparse || !sparse.sparse_residency, "Can't enable sparse residency without \
@ -301,170 +303,6 @@ impl SparseLevel {
}
}
/// Describes how a buffer is going to be used. This is **not** an optimization.
///
/// If you try to use a buffer in a way that you didn't declare, a panic will happen.
///
/// Some methods are provided to build `Usage` structs for some common situations. However
/// there is no restriction in the combination of usages that can be enabled.
#[derive(Debug, Copy, Clone)]
pub struct Usage {
pub transfer_source: bool,
pub transfer_dest: bool,
pub uniform_texel_buffer: bool,
pub storage_texel_buffer: bool,
pub uniform_buffer: bool,
pub storage_buffer: bool,
pub index_buffer: bool,
pub vertex_buffer: bool,
pub indirect_buffer: bool,
}
impl Usage {
/// Builds a `Usage` with all values set to false.
#[inline]
pub fn none() -> Usage {
Usage {
transfer_source: false,
transfer_dest: false,
uniform_texel_buffer: false,
storage_texel_buffer: false,
uniform_buffer: false,
storage_buffer: false,
index_buffer: false,
vertex_buffer: false,
indirect_buffer: false,
}
}
/// Builds a `Usage` with all values set to true. Can be used for quick prototyping.
#[inline]
pub fn all() -> Usage {
Usage {
transfer_source: true,
transfer_dest: true,
uniform_texel_buffer: true,
storage_texel_buffer: true,
uniform_buffer: true,
storage_buffer: true,
index_buffer: true,
vertex_buffer: true,
indirect_buffer: true,
}
}
/// Builds a `Usage` with `transfer_source` set to true and the rest to false.
#[inline]
pub fn transfer_source() -> Usage {
Usage {
transfer_source: true,
.. Usage::none()
}
}
/// Builds a `Usage` with `transfer_dest` set to true and the rest to false.
#[inline]
pub fn transfer_dest() -> Usage {
Usage {
transfer_dest: true,
.. Usage::none()
}
}
/// Builds a `Usage` with `vertex_buffer` set to true and the rest to false.
#[inline]
pub fn vertex_buffer() -> Usage {
Usage {
vertex_buffer: true,
.. Usage::none()
}
}
/// Builds a `Usage` with `vertex_buffer` and `transfer_dest` set to true and the rest to false.
#[inline]
pub fn vertex_buffer_transfer_dest() -> Usage {
Usage {
vertex_buffer: true,
transfer_dest: true,
.. Usage::none()
}
}
/// Builds a `Usage` with `index_buffer` set to true and the rest to false.
#[inline]
pub fn index_buffer() -> Usage {
Usage {
index_buffer: true,
.. Usage::none()
}
}
/// Builds a `Usage` with `index_buffer` and `transfer_dest` set to true and the rest to false.
#[inline]
pub fn index_buffer_transfer_dest() -> Usage {
Usage {
index_buffer: true,
transfer_dest: true,
.. Usage::none()
}
}
/// Builds a `Usage` with `uniform_buffer` set to true and the rest to false.
#[inline]
pub fn uniform_buffer() -> Usage {
Usage {
uniform_buffer: true,
.. Usage::none()
}
}
/// Builds a `Usage` with `uniform_buffer` and `transfer_dest` set to true and the rest
/// to false.
#[inline]
pub fn uniform_buffer_transfer_dest() -> Usage {
Usage {
uniform_buffer: true,
transfer_dest: true,
.. Usage::none()
}
}
/// Builds a `Usage` with `indirect_buffer` set to true and the rest to false.
#[inline]
pub fn indirect_buffer() -> Usage {
Usage {
indirect_buffer: true,
.. Usage::none()
}
}
/// Builds a `Usage` with `indirect_buffer` and `transfer_dest` set to true and the rest
/// to false.
#[inline]
pub fn indirect_buffer_transfer_dest() -> Usage {
Usage {
indirect_buffer: true,
transfer_dest: true,
.. Usage::none()
}
}
#[inline]
fn to_usage_bits(&self) -> vk::BufferUsageFlagBits {
let mut result = 0;
if self.transfer_source { result |= vk::BUFFER_USAGE_TRANSFER_SRC_BIT; }
if self.transfer_dest { result |= vk::BUFFER_USAGE_TRANSFER_DST_BIT; }
if self.uniform_texel_buffer { result |= vk::BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT; }
if self.storage_texel_buffer { result |= vk::BUFFER_USAGE_STORAGE_TEXEL_BUFFER_BIT; }
if self.uniform_buffer { result |= vk::BUFFER_USAGE_UNIFORM_BUFFER_BIT; }
if self.storage_buffer { result |= vk::BUFFER_USAGE_STORAGE_BUFFER_BIT; }
if self.index_buffer { result |= vk::BUFFER_USAGE_INDEX_BUFFER_BIT; }
if self.vertex_buffer { result |= vk::BUFFER_USAGE_VERTEX_BUFFER_BIT; }
if self.indirect_buffer { result |= vk::BUFFER_USAGE_INDIRECT_BUFFER_BIT; }
result
}
}
/// Error that can happen when creating a buffer.
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum BufferCreationError {
@ -536,7 +374,7 @@ mod tests {
use super::BufferCreationError;
use super::SparseLevel;
use super::UnsafeBuffer;
use super::Usage;
use super::BufferUsage;
use device::Device;
use device::DeviceOwned;
@ -546,7 +384,7 @@ mod tests {
fn create() {
let (device, _) = gfx_dev_and_queue!();
let (buf, reqs) = unsafe {
UnsafeBuffer::new(&device, 128, &Usage::all(), Sharing::Exclusive::<Empty<_>>,
UnsafeBuffer::new(device.clone(), 128, BufferUsage::all(), Sharing::Exclusive::<Empty<_>>,
SparseLevel::none())
}.unwrap();
@ -561,7 +399,7 @@ mod tests {
let (device, _) = gfx_dev_and_queue!();
let sparse = SparseLevel { sparse: false, sparse_residency: true, sparse_aliased: false };
let _ = unsafe {
UnsafeBuffer::new(&device, 128, &Usage::all(), Sharing::Exclusive::<Empty<_>>,
UnsafeBuffer::new(device, 128, BufferUsage::all(), Sharing::Exclusive::<Empty<_>>,
sparse)
};
}
@ -572,7 +410,7 @@ mod tests {
let (device, _) = gfx_dev_and_queue!();
let sparse = SparseLevel { sparse: false, sparse_residency: false, sparse_aliased: true };
let _ = unsafe {
UnsafeBuffer::new(&device, 128, &Usage::all(), Sharing::Exclusive::<Empty<_>>,
UnsafeBuffer::new(device, 128, BufferUsage::all(), Sharing::Exclusive::<Empty<_>>,
sparse)
};
}
@ -582,7 +420,7 @@ mod tests {
let (device, _) = gfx_dev_and_queue!();
let sparse = SparseLevel { sparse: true, sparse_residency: false, sparse_aliased: false };
unsafe {
match UnsafeBuffer::new(&device, 128, &Usage::all(), Sharing::Exclusive::<Empty<_>>,
match UnsafeBuffer::new(device, 128, BufferUsage::all(), Sharing::Exclusive::<Empty<_>>,
sparse)
{
Err(BufferCreationError::SparseBindingFeatureNotEnabled) => (),
@ -596,7 +434,7 @@ mod tests {
let (device, _) = gfx_dev_and_queue!(sparse_binding);
let sparse = SparseLevel { sparse: true, sparse_residency: true, sparse_aliased: false };
unsafe {
match UnsafeBuffer::new(&device, 128, &Usage::all(), Sharing::Exclusive::<Empty<_>>,
match UnsafeBuffer::new(device, 128, BufferUsage::all(), Sharing::Exclusive::<Empty<_>>,
sparse)
{
Err(BufferCreationError::SparseResidencyBufferFeatureNotEnabled) => (),
@ -610,7 +448,7 @@ mod tests {
let (device, _) = gfx_dev_and_queue!(sparse_binding);
let sparse = SparseLevel { sparse: true, sparse_residency: false, sparse_aliased: true };
unsafe {
match UnsafeBuffer::new(&device, 128, &Usage::all(), Sharing::Exclusive::<Empty<_>>,
match UnsafeBuffer::new(device, 128, BufferUsage::all(), Sharing::Exclusive::<Empty<_>>,
sparse)
{
Err(BufferCreationError::SparseResidencyAliasedFeatureNotEnabled) => (),

View File

@ -15,6 +15,7 @@ use device::DeviceOwned;
use device::Queue;
use image::ImageAccess;
use memory::Content;
use sync::AccessError;
use SafeDeref;
use VulkanObject;
@ -246,8 +247,7 @@ pub unsafe trait BufferAccess: DeviceOwned {
/// The only way to know that the GPU has stopped accessing a queue is when the buffer object
/// gets destroyed. Therefore you are encouraged to use temporary objects or handles (similar
/// to a lock) in order to represent a GPU access.
// TODO: return Result?
fn try_gpu_lock(&self, exclusive_access: bool, queue: &Queue) -> bool;
fn try_gpu_lock(&self, exclusive_access: bool, queue: &Queue) -> Result<(), AccessError>;
/// Locks the resource for usage on the GPU. Supposes that the resource is already locked, and
/// simply increases the lock by one.
@ -290,7 +290,7 @@ unsafe impl<T> BufferAccess for T where T: SafeDeref, T::Target: BufferAccess {
}
#[inline]
fn try_gpu_lock(&self, exclusive_access: bool, queue: &Queue) -> bool {
fn try_gpu_lock(&self, exclusive_access: bool, queue: &Queue) -> Result<(), AccessError> {
(**self).try_gpu_lock(exclusive_access, queue)
}

196
vulkano/src/buffer/usage.rs Normal file
View File

@ -0,0 +1,196 @@
// Copyright (c) 2016 The vulkano developers
// Licensed under the Apache License, Version 2.0
// <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT
// license <LICENSE-MIT or http://opensource.org/licenses/MIT>,
// 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::ops::BitOr;
use vk;
/// Describes how a buffer is going to be used. This is **not** an optimization.
///
/// If you try to use a buffer in a way that you didn't declare, a panic will happen.
///
/// Some methods are provided to build `BufferUsage` structs for some common situations. However
/// there is no restriction in the combination of BufferUsages that can be enabled.
#[derive(Debug, Copy, Clone)]
pub struct BufferUsage {
pub transfer_source: bool,
pub transfer_dest: bool,
pub uniform_texel_buffer: bool,
pub storage_texel_buffer: bool,
pub uniform_buffer: bool,
pub storage_buffer: bool,
pub index_buffer: bool,
pub vertex_buffer: bool,
pub indirect_buffer: bool,
}
impl BufferUsage {
/// Builds a `BufferUsage` with all values set to false.
#[inline]
pub fn none() -> BufferUsage {
BufferUsage {
transfer_source: false,
transfer_dest: false,
uniform_texel_buffer: false,
storage_texel_buffer: false,
uniform_buffer: false,
storage_buffer: false,
index_buffer: false,
vertex_buffer: false,
indirect_buffer: false,
}
}
/// Builds a `BufferUsage` with all values set to true. Can be used for quick prototyping.
#[inline]
pub fn all() -> BufferUsage {
BufferUsage {
transfer_source: true,
transfer_dest: true,
uniform_texel_buffer: true,
storage_texel_buffer: true,
uniform_buffer: true,
storage_buffer: true,
index_buffer: true,
vertex_buffer: true,
indirect_buffer: true,
}
}
/// Builds a `BufferUsage` with `transfer_source` set to true and the rest to false.
#[inline]
pub fn transfer_source() -> BufferUsage {
BufferUsage {
transfer_source: true,
.. BufferUsage::none()
}
}
/// Builds a `BufferUsage` with `transfer_dest` set to true and the rest to false.
#[inline]
pub fn transfer_dest() -> BufferUsage {
BufferUsage {
transfer_dest: true,
.. BufferUsage::none()
}
}
/// Builds a `BufferUsage` with `vertex_buffer` set to true and the rest to false.
#[inline]
pub fn vertex_buffer() -> BufferUsage {
BufferUsage {
vertex_buffer: true,
.. BufferUsage::none()
}
}
/// Builds a `BufferUsage` with `vertex_buffer` and `transfer_dest` set to true and the rest
/// to false.
#[inline]
pub fn vertex_buffer_transfer_dest() -> BufferUsage {
BufferUsage {
vertex_buffer: true,
transfer_dest: true,
.. BufferUsage::none()
}
}
/// Builds a `BufferUsage` with `index_buffer` set to true and the rest to false.
#[inline]
pub fn index_buffer() -> BufferUsage {
BufferUsage {
index_buffer: true,
.. BufferUsage::none()
}
}
/// Builds a `BufferUsage` with `index_buffer` and `transfer_dest` set to true and the rest to false.
#[inline]
pub fn index_buffer_transfer_dest() -> BufferUsage {
BufferUsage {
index_buffer: true,
transfer_dest: true,
.. BufferUsage::none()
}
}
/// Builds a `BufferUsage` with `uniform_buffer` set to true and the rest to false.
#[inline]
pub fn uniform_buffer() -> BufferUsage {
BufferUsage {
uniform_buffer: true,
.. BufferUsage::none()
}
}
/// Builds a `BufferUsage` with `uniform_buffer` and `transfer_dest` set to true and the rest
/// to false.
#[inline]
pub fn uniform_buffer_transfer_dest() -> BufferUsage {
BufferUsage {
uniform_buffer: true,
transfer_dest: true,
.. BufferUsage::none()
}
}
/// Builds a `BufferUsage` with `indirect_buffer` set to true and the rest to false.
#[inline]
pub fn indirect_buffer() -> BufferUsage {
BufferUsage {
indirect_buffer: true,
.. BufferUsage::none()
}
}
/// Builds a `BufferUsage` with `indirect_buffer` and `transfer_dest` set to true and the rest
/// to false.
#[inline]
pub fn indirect_buffer_transfer_dest() -> BufferUsage {
BufferUsage {
indirect_buffer: true,
transfer_dest: true,
.. BufferUsage::none()
}
}
}
impl BitOr for BufferUsage {
type Output = Self;
#[inline]
fn bitor(self, rhs: Self) -> Self {
BufferUsage {
transfer_source: self.transfer_source || rhs.transfer_source,
transfer_dest: self.transfer_dest || rhs.transfer_dest,
uniform_texel_buffer: self.uniform_texel_buffer || rhs.uniform_texel_buffer,
storage_texel_buffer: self.storage_texel_buffer || rhs.storage_texel_buffer,
uniform_buffer: self.uniform_buffer || rhs.uniform_buffer,
storage_buffer: self.storage_buffer || rhs.storage_buffer,
index_buffer: self.index_buffer || rhs.index_buffer,
vertex_buffer: self.vertex_buffer || rhs.vertex_buffer,
indirect_buffer: self.indirect_buffer || rhs.indirect_buffer,
}
}
}
/// Turns a `BufferUsage` into raw bits.
#[inline]
pub fn usage_to_bits(usage: BufferUsage) -> vk::BufferUsageFlagBits {
let mut result = 0;
if usage.transfer_source { result |= vk::BUFFER_USAGE_TRANSFER_SRC_BIT; }
if usage.transfer_dest { result |= vk::BUFFER_USAGE_TRANSFER_DST_BIT; }
if usage.uniform_texel_buffer { result |= vk::BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT; }
if usage.storage_texel_buffer { result |= vk::BUFFER_USAGE_STORAGE_TEXEL_BUFFER_BIT; }
if usage.uniform_buffer { result |= vk::BUFFER_USAGE_UNIFORM_BUFFER_BIT; }
if usage.storage_buffer { result |= vk::BUFFER_USAGE_STORAGE_BUFFER_BIT; }
if usage.index_buffer { result |= vk::BUFFER_USAGE_INDEX_BUFFER_BIT; }
if usage.vertex_buffer { result |= vk::BUFFER_USAGE_VERTEX_BUFFER_BIT; }
if usage.indirect_buffer { result |= vk::BUFFER_USAGE_INDIRECT_BUFFER_BIT; }
result
}

View File

@ -20,18 +20,18 @@
//! ```
//! # use std::sync::Arc;
//! use vulkano::buffer::immutable::ImmutableBuffer;
//! use vulkano::buffer::sys::Usage;
//! use vulkano::buffer::BufferUsage;
//! use vulkano::buffer::BufferView;
//! use vulkano::format;
//!
//! # let device: Arc<vulkano::device::Device> = return;
//! # let queue: Arc<vulkano::device::Queue> = return;
//! let usage = Usage {
//! let usage = BufferUsage {
//! storage_texel_buffer: true,
//! .. Usage::none()
//! .. BufferUsage::none()
//! };
//!
//! let (buffer, _future) = ImmutableBuffer::<[u32]>::from_iter((0..128).map(|n| n), &usage,
//! let (buffer, _future) = ImmutableBuffer::<[u32]>::from_iter((0..128).map(|n| n), usage,
//! Some(queue.family()),
//! queue.clone()).unwrap();
//! let _view = BufferView::new(buffer, format::R32Uint).unwrap();
@ -321,7 +321,7 @@ impl From<Error> for BufferViewCreationError {
#[cfg(test)]
mod tests {
use buffer::BufferView;
use buffer::sys::Usage;
use buffer::BufferUsage;
use buffer::view::BufferViewCreationError;
use buffer::immutable::ImmutableBuffer;
use format;
@ -331,12 +331,12 @@ mod tests {
// `VK_FORMAT_R8G8B8A8_UNORM` guaranteed to be a supported format
let (device, queue) = gfx_dev_and_queue!();
let usage = Usage {
let usage = BufferUsage {
uniform_texel_buffer: true,
.. Usage::none()
.. BufferUsage::none()
};
let (buffer, _) = ImmutableBuffer::<[[u8; 4]]>::from_iter((0..128).map(|_| [0; 4]), &usage,
let (buffer, _) = ImmutableBuffer::<[[u8; 4]]>::from_iter((0..128).map(|_| [0; 4]), usage,
Some(queue.family()), queue.clone()).unwrap();
let view = BufferView::new(buffer, format::R8G8B8A8Unorm).unwrap();
@ -348,12 +348,12 @@ mod tests {
// `VK_FORMAT_R8G8B8A8_UNORM` guaranteed to be a supported format
let (device, queue) = gfx_dev_and_queue!();
let usage = Usage {
let usage = BufferUsage {
storage_texel_buffer: true,
.. Usage::none()
.. BufferUsage::none()
};
let (buffer, _) = ImmutableBuffer::<[[u8; 4]]>::from_iter((0..128).map(|_| [0; 4]), &usage,
let (buffer, _) = ImmutableBuffer::<[[u8; 4]]>::from_iter((0..128).map(|_| [0; 4]), usage,
Some(queue.family()),
queue.clone()).unwrap();
let view = BufferView::new(buffer, format::R8G8B8A8Unorm).unwrap();
@ -366,12 +366,12 @@ mod tests {
// `VK_FORMAT_R32_UINT` guaranteed to be a supported format for atomics
let (device, queue) = gfx_dev_and_queue!();
let usage = Usage {
let usage = BufferUsage {
storage_texel_buffer: true,
.. Usage::none()
.. BufferUsage::none()
};
let (buffer, _) = ImmutableBuffer::<[u32]>::from_iter((0..128).map(|_| 0), &usage,
let (buffer, _) = ImmutableBuffer::<[u32]>::from_iter((0..128).map(|_| 0), usage,
Some(queue.family()),
queue.clone()).unwrap();
let view = BufferView::new(buffer, format::R32Uint).unwrap();
@ -386,7 +386,7 @@ mod tests {
let (device, queue) = gfx_dev_and_queue!();
let (buffer, _) = ImmutableBuffer::<[[u8; 4]]>::from_iter((0..128).map(|_| [0; 4]),
&Usage::none(),
BufferUsage::none(),
Some(queue.family()),
queue.clone()).unwrap();
@ -400,14 +400,14 @@ mod tests {
fn unsupported_format() {
let (device, queue) = gfx_dev_and_queue!();
let usage = Usage {
let usage = BufferUsage {
uniform_texel_buffer: true,
storage_texel_buffer: true,
.. Usage::none()
.. BufferUsage::none()
};
let (buffer, _) = ImmutableBuffer::<[[f64; 4]]>::from_iter((0..128).map(|_| [0.0; 4]),
&usage, Some(queue.family()),
usage, Some(queue.family()),
queue.clone()).unwrap();
// TODO: what if R64G64B64A64Sfloat is supported?

View File

@ -24,7 +24,7 @@ use command_buffer::pool::StandardCommandPool;
use device::Device;
use device::DeviceOwned;
use device::Queue;
use image::Layout;
use image::ImageLayout;
use image::ImageAccess;
use instance::QueueFamily;
use sync::AccessCheckError;
@ -108,7 +108,7 @@ unsafe impl<P> CommandBuffer for AutoCommandBufferBuilder<P>
}
#[inline]
fn check_image_access(&self, image: &ImageAccess, layout: Layout, exclusive: bool, queue: &Queue)
fn check_image_access(&self, image: &ImageAccess, layout: ImageLayout, exclusive: bool, queue: &Queue)
-> Result<Option<(PipelineStages, AccessFlagBits)>, AccessCheckError>
{
self.inner.check_image_access(image, layout, exclusive, queue)

View File

@ -22,7 +22,7 @@ use command_buffer::CommandBufferExecError;
use device::Device;
use device::DeviceOwned;
use device::Queue;
use image::Layout;
use image::ImageLayout;
use image::ImageAccess;
use instance::QueueFamily;
use sync::AccessCheckError;
@ -68,7 +68,7 @@ unsafe impl<I> CommandBuffer for AbstractStorageLayer<I> where I: CommandBuffer
}
#[inline]
fn check_image_access(&self, image: &ImageAccess, layout: Layout, exclusive: bool, queue: &Queue)
fn check_image_access(&self, image: &ImageAccess, layout: ImageLayout, exclusive: bool, queue: &Queue)
-> Result<Option<(PipelineStages, AccessFlagBits)>, AccessCheckError>
{
self.inner.check_image_access(image, layout, exclusive, queue)

View File

@ -22,7 +22,7 @@ use command_buffer::CommandBufferBuilder;
use command_buffer::CommandBufferExecError;
use command_buffer::commands_raw;
use framebuffer::FramebufferAbstract;
use image::Layout;
use image::ImageLayout;
use image::ImageAccess;
use instance::QueueFamily;
use device::Device;
@ -159,8 +159,8 @@ struct ResourceEntry {
final_stages: PipelineStages,
final_access: AccessFlagBits,
exclusive: bool,
initial_layout: Layout,
final_layout: Layout,
initial_layout: ImageLayout,
final_layout: ImageLayout,
}
impl<I> SubmitSyncBuilderLayer<I> {
@ -187,8 +187,8 @@ impl<I> SubmitSyncBuilderLayer<I> {
final_stages: stages,
final_access: access,
exclusive: exclusive,
initial_layout: Layout::Undefined,
final_layout: Layout::Undefined,
initial_layout: ImageLayout::Undefined,
final_layout: ImageLayout::Undefined,
});
},
@ -198,7 +198,7 @@ impl<I> SubmitSyncBuilderLayer<I> {
entry.final_stages = entry.final_stages | stages;
entry.final_access = entry.final_access | access;
entry.exclusive = entry.exclusive || exclusive;
entry.final_layout = Layout::Undefined;
entry.final_layout = ImageLayout::Undefined;
},
}
}
@ -250,14 +250,14 @@ impl<I> SubmitSyncBuilderLayer<I> {
// TODO: slow
for index in 0 .. FramebufferAbstract::attachments(framebuffer).len() {
let key = Key::FramebufferAttachment(Box::new(framebuffer.clone()), index as u32);
let desc = framebuffer.attachment(index).expect("Wrong implementation of FramebufferAbstract trait");
let desc = framebuffer.attachment_desc(index).expect("Wrong implementation of FramebufferAbstract trait");
let image = FramebufferAbstract::attachments(framebuffer)[index];
let initial_layout = match self.behavior {
SubmitSyncBuilderLayerBehavior::Explicit => desc.initial_layout,
SubmitSyncBuilderLayerBehavior::UseLayoutHint => {
match desc.initial_layout {
Layout::Undefined | Layout::Preinitialized => desc.initial_layout,
ImageLayout::Undefined | ImageLayout::Preinitialized => desc.initial_layout,
_ => image.parent().initial_layout_requirement(),
}
},
@ -267,7 +267,7 @@ impl<I> SubmitSyncBuilderLayer<I> {
SubmitSyncBuilderLayerBehavior::Explicit => desc.final_layout,
SubmitSyncBuilderLayerBehavior::UseLayoutHint => {
match desc.final_layout {
Layout::Undefined | Layout::Preinitialized => desc.final_layout,
ImageLayout::Undefined | ImageLayout::Preinitialized => desc.final_layout,
_ => image.parent().final_layout_requirement(),
}
},
@ -570,7 +570,7 @@ unsafe impl<I, O, B> AddCommand<commands_raw::CmdDrawIndirectRaw<B>> for SubmitS
#[inline]
fn add(mut self, command: commands_raw::CmdDrawIndirectRaw<B>) -> Result<Self::Out, CommandAddError> {
self.add_buffer(command.buffer(), true,
self.add_buffer(command.buffer(), false,
PipelineStages { draw_indirect: true, .. PipelineStages::none() },
AccessFlagBits { indirect_command_read: true, .. AccessFlagBits::none() });
@ -741,7 +741,7 @@ unsafe impl<I> CommandBuffer for SubmitSyncLayer<I> where I: CommandBuffer {
for (key, entry) in self.resources.iter() {
match key {
&Key::Buffer(ref buf) => {
let err = match future.check_buffer_access(&buf, entry.exclusive, queue) {
let prev_err = match future.check_buffer_access(&buf, entry.exclusive, queue) {
Ok(_) => {
unsafe { buf.increase_gpu_lock(); }
continue;
@ -749,17 +749,16 @@ unsafe impl<I> CommandBuffer for SubmitSyncLayer<I> where I: CommandBuffer {
Err(err) => err
};
if !buf.try_gpu_lock(entry.exclusive, queue) {
match err {
AccessCheckError::Unknown => panic!(), // TODO: use the err returned by try_gpu_lock
AccessCheckError::Denied(err) => return Err(err.into()),
}
match (buf.try_gpu_lock(entry.exclusive, queue), prev_err) {
(Ok(_), _) => (),
(Err(err), AccessCheckError::Unknown) => return Err(err.into()),
(_, AccessCheckError::Denied(err)) => return Err(err.into()),
}
},
&Key::Image(ref img) => {
let err = match future.check_image_access(img, entry.initial_layout,
entry.exclusive, queue)
let prev_err = match future.check_image_access(img, entry.initial_layout,
entry.exclusive, queue)
{
Ok(_) => {
unsafe { img.increase_gpu_lock(); }
@ -768,19 +767,18 @@ unsafe impl<I> CommandBuffer for SubmitSyncLayer<I> where I: CommandBuffer {
Err(err) => err
};
if !img.try_gpu_lock(entry.exclusive, queue) {
match err {
AccessCheckError::Unknown => panic!(), // TODO: use the err returned by try_gpu_lock
AccessCheckError::Denied(err) => return Err(err.into()),
}
match (img.try_gpu_lock(entry.exclusive, queue), prev_err) {
(Ok(_), _) => (),
(Err(err), AccessCheckError::Unknown) => return Err(err.into()),
(_, AccessCheckError::Denied(err)) => return Err(err.into()),
}
},
&Key::FramebufferAttachment(ref fb, idx) => {
let img = fb.attachments()[idx as usize].parent();
let err = match future.check_image_access(img, entry.initial_layout,
entry.exclusive, queue)
let prev_err = match future.check_image_access(img, entry.initial_layout,
entry.exclusive, queue)
{
Ok(_) => {
unsafe { img.increase_gpu_lock(); }
@ -789,11 +787,12 @@ unsafe impl<I> CommandBuffer for SubmitSyncLayer<I> where I: CommandBuffer {
Err(err) => err
};
if !img.try_gpu_lock(entry.exclusive, queue) {
match err {
AccessCheckError::Unknown => panic!(), // TODO: use the err returned by try_gpu_lock
AccessCheckError::Denied(err) => return Err(err.into()),
}
// FIXME: this is bad because dropping the submit sync layer doesn't drop the
// attachments of the framebuffer, meaning that they will stay locked
match (img.try_gpu_lock(entry.exclusive, queue), prev_err) {
(Ok(_), _) => (),
(Err(err), AccessCheckError::Unknown) => return Err(err.into()),
(_, AccessCheckError::Denied(err)) => return Err(err.into()),
}
},
}
@ -830,7 +829,7 @@ unsafe impl<I> CommandBuffer for SubmitSyncLayer<I> where I: CommandBuffer {
}
#[inline]
fn check_image_access(&self, image: &ImageAccess, layout: Layout, exclusive: bool, queue: &Queue)
fn check_image_access(&self, image: &ImageAccess, layout: ImageLayout, exclusive: bool, queue: &Queue)
-> Result<Option<(PipelineStages, AccessFlagBits)>, AccessCheckError>
{
// TODO: check the queue family
@ -844,7 +843,7 @@ unsafe impl<I> CommandBuffer for SubmitSyncLayer<I> where I: CommandBuffer {
continue;
}
if layout != Layout::Undefined && value.final_layout != layout {
if layout != ImageLayout::Undefined && value.final_layout != layout {
return Err(AccessCheckError::Denied(AccessError::UnexpectedImageLayout {
allowed: value.final_layout,
requested: layout,

View File

@ -28,7 +28,7 @@ use framebuffer::FramebufferAbstract;
use framebuffer::RenderPass;
use framebuffer::RenderPassAbstract;
use framebuffer::Subpass;
use image::Layout;
use image::ImageLayout;
use image::ImageAccess;
use instance::QueueFamily;
use sync::AccessCheckError;
@ -317,7 +317,7 @@ unsafe impl<P> CommandBuffer for UnsafeCommandBuffer<P> where P: CommandPool {
}
#[inline]
fn check_image_access(&self, image: &ImageAccess, layout: Layout, exclusive: bool, queue: &Queue)
fn check_image_access(&self, image: &ImageAccess, layout: ImageLayout, exclusive: bool, queue: &Queue)
-> Result<Option<(PipelineStages, AccessFlagBits)>, AccessCheckError>
{
Err(AccessCheckError::Unknown)

View File

@ -144,7 +144,7 @@ mod tests {
fn basic() {
let (device, queue) = gfx_dev_and_queue!();
let buffer = CpuAccessibleBuffer::from_data(&device, &BufferUsage::transfer_dest(),
let buffer = CpuAccessibleBuffer::from_data(&device, BufferUsage::transfer_dest(),
Some(queue.family()), 0u32).unwrap();
let _ = PrimaryCbBuilder::new(&device, queue.family())

View File

@ -20,7 +20,7 @@ use command_buffer::cb::AddCommand;
use command_buffer::cb::UnsafeCommandBufferBuilder;
use command_buffer::pool::CommandPool;
use image::ImageAccess;
use image::Layout;
use image::ImageLayout;
use sync::AccessFlagBits;
use sync::PipelineStages;
@ -102,8 +102,8 @@ impl<'a> CmdPipelineBarrier<'a> {
self.dependency_flags = 0;
}
self.src_stage_mask |= source.into();
self.dst_stage_mask |= dest.into();
self.src_stage_mask |= Into::<vk::PipelineStageFlags>::into(source);
self.dst_stage_mask |= Into::<vk::PipelineStageFlags>::into(dest);
}
/// Adds a memory barrier. This means that all the memory writes by the given source stages
@ -197,7 +197,7 @@ impl<'a> CmdPipelineBarrier<'a> {
pub unsafe fn add_image_memory_barrier<I: ?Sized>(&mut self, image: &'a I, mipmaps: Range<u32>,
layers: Range<u32>, source_stage: PipelineStages, source_access: AccessFlagBits,
dest_stage: PipelineStages, dest_access: AccessFlagBits, by_region: bool,
queue_transfer: Option<(u32, u32)>, current_layout: Layout, new_layout: Layout)
queue_transfer: Option<(u32, u32)>, current_layout: ImageLayout, new_layout: ImageLayout)
where I: ImageAccess
{
self.add_execution_dependency(source_stage, dest_stage, by_region);

View File

@ -22,7 +22,7 @@ use command_buffer::submit::SubmitCommandBufferBuilder;
use device::Device;
use device::DeviceOwned;
use device::Queue;
use image::Layout;
use image::ImageLayout;
use image::ImageAccess;
use instance::QueueFamily;
use sync::now;
@ -136,7 +136,7 @@ pub unsafe trait CommandBuffer: DeviceOwned {
fn check_buffer_access(&self, buffer: &BufferAccess, exclusive: bool, queue: &Queue)
-> Result<Option<(PipelineStages, AccessFlagBits)>, AccessCheckError>;
fn check_image_access(&self, image: &ImageAccess, layout: Layout, exclusive: bool, queue: &Queue)
fn check_image_access(&self, image: &ImageAccess, layout: ImageLayout, exclusive: bool, queue: &Queue)
-> Result<Option<(PipelineStages, AccessFlagBits)>, AccessCheckError>;
// FIXME: lots of other methods
@ -174,7 +174,7 @@ unsafe impl<T> CommandBuffer for T where T: SafeDeref, T::Target: CommandBuffer
}
#[inline]
fn check_image_access(&self, image: &ImageAccess, layout: Layout, exclusive: bool, queue: &Queue)
fn check_image_access(&self, image: &ImageAccess, layout: ImageLayout, exclusive: bool, queue: &Queue)
-> Result<Option<(PipelineStages, AccessFlagBits)>, AccessCheckError>
{
(**self).check_image_access(image, layout, exclusive, queue)
@ -284,7 +284,7 @@ unsafe impl<F, Cb> GpuFuture for CommandBufferExecFuture<F, Cb>
}
#[inline]
fn check_image_access(&self, image: &ImageAccess, layout: Layout, exclusive: bool, queue: &Queue)
fn check_image_access(&self, image: &ImageAccess, layout: ImageLayout, exclusive: bool, queue: &Queue)
-> Result<Option<(PipelineStages, AccessFlagBits)>, AccessCheckError>
{
match self.command_buffer.check_image_access(image, layout, exclusive, queue) {

View File

@ -27,7 +27,7 @@ use device::Device;
use device::DeviceOwned;
use image::ImageAccess;
use image::ImageView;
use image::sys::Layout;
use image::ImageLayout;
use sampler::Sampler;
use sync::AccessFlagBits;
use sync::PipelineStages;
@ -290,7 +290,7 @@ unsafe impl<L, R, T> SimpleDescriptorSetImageExt<L, R> for T
num_mipmaps: 1, // FIXME:
first_layer: 0, // FIXME:
num_layers: 1, // FIXME:
layout: Layout::General, // FIXME:
layout: ImageLayout::General, // FIXME:
stage: PipelineStages::none(), // FIXME:
access: AccessFlagBits::none(), // FIXME:
})
@ -332,7 +332,7 @@ unsafe impl<L, R, T> SimpleDescriptorSetImageExt<L, R> for (T, Arc<Sampler>)
num_mipmaps: 1, // FIXME:
first_layer: 0, // FIXME:
num_layers: 1, // FIXME:
layout: Layout::General, // FIXME:
layout: ImageLayout::General, // FIXME:
stage: PipelineStages::none(), // FIXME:
access: AccessFlagBits::none(), // FIXME:
})
@ -375,7 +375,7 @@ unsafe impl<L, R, T> SimpleDescriptorSetImageExt<L, R> for Vec<(T, Arc<Sampler>)
num_mipmaps: 1, // FIXME:
first_layer: 0, // FIXME:
num_layers: 1, // FIXME:
layout: Layout::General, // FIXME:
layout: ImageLayout::General, // FIXME:
stage: PipelineStages::none(), // FIXME:
access: AccessFlagBits::none(), // FIXME:
});
@ -475,7 +475,7 @@ pub struct SimpleDescriptorSetImg<I> {
num_mipmaps: u32,
first_layer: u32,
num_layers: u32,
layout: Layout,
layout: ImageLayout,
stage: PipelineStages,
access: AccessFlagBits,
}

View File

@ -547,7 +547,7 @@ impl UnsafeDescriptorSet {
/// command buffer contains a pointer/reference to a descriptor set, it is illegal to write
/// to it.
///
pub unsafe fn write<I>(&mut self, device: &Arc<Device>, writes: I)
pub unsafe fn write<I>(&mut self, device: &Device, writes: I)
where I: Iterator<Item = DescriptorWrite>
{
let vk = device.pointers();

View File

@ -23,7 +23,7 @@ use descriptor::pipeline_layout::PipelineLayoutDescPcRange;
/// use vulkano::descriptor::pipeline_layout::PipelineLayoutDesc;
///
/// # let device: Arc<Device> = return;
/// let pipeline_layout = EmptyPipelineDesc.build(&device).unwrap();
/// let pipeline_layout = EmptyPipelineDesc.build(device.clone()).unwrap();
/// ```
#[derive(Debug, Copy, Clone)]
pub struct EmptyPipelineDesc;

View File

@ -48,7 +48,7 @@ impl<L> PipelineLayout<L> where L: PipelineLayoutDesc {
/// - Panics if one of the layout returned by `provided_set_layout()` belongs to a different
/// device than the one passed as parameter.
#[inline]
pub fn new(device: &Arc<Device>, desc: L)
pub fn new(device: Arc<Device>, desc: L)
-> Result<PipelineLayout<L>, PipelineLayoutCreationError>
{
let vk = device.pointers();

View File

@ -99,7 +99,7 @@ pub unsafe trait PipelineLayoutDesc {
///
/// > **Note**: This is just a shortcut for `PipelineLayout::new`.
#[inline]
fn build(self, device: &Arc<Device>)
fn build(self, device: Arc<Device>)
-> Result<PipelineLayout<Self>, PipelineLayoutCreationError>
where Self: Sized
{

View File

@ -299,29 +299,20 @@ impl Device {
Ok((device, output_queues))
}
/// See the docs of wait().
// FIXME: must synchronize all queuees
#[inline]
pub fn wait_raw(&self) -> Result<(), OomError> {
unsafe {
try!(check_errors(self.vk.DeviceWaitIdle(self.device)));
Ok(())
}
}
/// Waits until all work on this device has finished. You should never need to call
/// this function, but it can be useful for debugging or benchmarking purposes.
///
/// This is the Vulkan equivalent of `glFinish`.
/// > **Note**: This is the Vulkan equivalent of OpenGL's `glFinish`.
///
/// # Panic
/// # Safety
///
/// - Panics if the device or host ran out of memory.
/// This function is not thread-safe. You must not submit anything to any of the queue
/// of the device (either explicitely or implicitely, for example with a future's destructor)
/// while this function is waiting.
///
// FIXME: must synchronize all queuees
#[inline]
pub fn wait(&self) {
self.wait_raw().unwrap();
pub unsafe fn wait(&self) -> Result<(), OomError> {
try!(check_errors(self.vk.DeviceWaitIdle(self.device)));
Ok(())
}
/// Returns the instance used to create this device.
@ -357,7 +348,7 @@ impl Device {
}
// The weak pointer is empty, so we create the pool.
let new_pool = StdMemoryPool::new(me);
let new_pool = StdMemoryPool::new(me.clone());
*pool = Arc::downgrade(&new_pool);
new_pool
}

View File

@ -7,43 +7,20 @@
// notice may not be copied, modified, or distributed except
// according to those terms.
use std::cmp;
use std::sync::Arc;
use SafeDeref;
use image::ImageViewAccess;
use image::sys::UnsafeImageView;
//use sync::AccessFlagBits;
//use sync::PipelineStages;
/// A list of attachments.
// TODO: rework this trait
pub unsafe trait AttachmentsList {
/// Returns the image views of this list.
// TODO: better return type
fn raw_image_view_handles(&self) -> Vec<&UnsafeImageView>;
/// Returns the dimensions of the intersection of the views. Returns `None` if the list is
/// empty.
///
/// For example if one view is 256x256x2 and another one is 128x512x3, then this function
/// should return 128x256x2.
fn intersection_dimensions(&self) -> Option<[u32; 3]>;
// TODO: meh for API
fn as_image_view_accesses(&self) -> Vec<&ImageViewAccess>;
}
unsafe impl<T> AttachmentsList for T where T: SafeDeref, T::Target: AttachmentsList {
#[inline]
fn raw_image_view_handles(&self) -> Vec<&UnsafeImageView> {
(**self).raw_image_view_handles()
}
#[inline]
fn intersection_dimensions(&self) -> Option<[u32; 3]> {
(**self).intersection_dimensions()
}
#[inline]
fn as_image_view_accesses(&self) -> Vec<&ImageViewAccess> {
(**self).as_image_view_accesses()
@ -51,16 +28,6 @@ unsafe impl<T> AttachmentsList for T where T: SafeDeref, T::Target: AttachmentsL
}
unsafe impl AttachmentsList for () {
#[inline]
fn raw_image_view_handles(&self) -> Vec<&UnsafeImageView> {
vec![]
}
#[inline]
fn intersection_dimensions(&self) -> Option<[u32; 3]> {
None
}
#[inline]
fn as_image_view_accesses(&self) -> Vec<&ImageViewAccess> {
vec![]
@ -68,106 +35,19 @@ unsafe impl AttachmentsList for () {
}
unsafe impl AttachmentsList for Vec<Arc<ImageViewAccess + Send + Sync>> {
#[inline]
fn raw_image_view_handles(&self) -> Vec<&UnsafeImageView> {
self.iter().map(|img| img.inner()).collect()
}
#[inline]
fn intersection_dimensions(&self) -> Option<[u32; 3]> {
let mut dims = None;
for view in self.iter() {
debug_assert_eq!(view.dimensions().depth(), 1);
match dims {
None => {
dims = Some([
view.dimensions().width(),
view.dimensions().height(),
view.dimensions().array_layers()
]);
},
Some(ref mut d) => {
d[0] = cmp::min(view.dimensions().width(), d[0]);
d[1] = cmp::min(view.dimensions().height(), d[1]);
d[2] = cmp::min(view.dimensions().array_layers(), d[2]);
},
}
}
dims
}
#[inline]
fn as_image_view_accesses(&self) -> Vec<&ImageViewAccess> {
self.iter().map(|p| &**p as &ImageViewAccess).collect()
}
}
macro_rules! impl_into_atch_list {
($first:ident $(, $rest:ident)*) => (
unsafe impl<$first $(, $rest)*> AttachmentsList for ($first, $($rest),*)
where $first: ImageViewAccess,
$($rest: ImageViewAccess,)*
{
#[inline]
#[allow(non_snake_case)]
fn raw_image_view_handles(&self) -> Vec<&UnsafeImageView> {
let &(ref $first, $(ref $rest,)*) = self;
vec![
&$first.inner(),
$(
&$rest.inner(),
)*
]
}
#[inline]
#[allow(non_snake_case)]
fn intersection_dimensions(&self) -> Option<[u32; 3]> {
let &(ref $first, $(ref $rest,)*) = self;
let dims = {
let d = $first.dimensions();
debug_assert_eq!(d.depth(), 1);
[d.width(), d.height(), d.array_layers()]
};
$(
let dims = {
let d = $rest.dimensions();
debug_assert_eq!(d.depth(), 1);
[
cmp::min(d.width(), dims[0]),
cmp::min(d.height(), dims[1]),
cmp::min(d.array_layers(), dims[2])
]
};
)*
Some(dims)
}
#[inline]
#[allow(non_snake_case)]
fn as_image_view_accesses(&self) -> Vec<&ImageViewAccess> {
let &(ref $first, $(ref $rest,)*) = self;
vec![
&*$first,
$(
&*$rest,
)*
]
}
}
impl_into_atch_list!($($rest),*);
);
() => ();
unsafe impl<A, B> AttachmentsList for (A, B)
where A: AttachmentsList, B: ImageViewAccess
{
#[inline]
fn as_image_view_accesses(&self) -> Vec<&ImageViewAccess> {
let mut list = self.0.as_image_view_accesses();
list.push(&self.1);
list
}
}
impl_into_atch_list!(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V, W, X, Y, Z);

View File

@ -0,0 +1,232 @@
// Copyright (c) 2017 The vulkano developers
// Licensed under the Apache License, Version 2.0
// <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT
// license <LICENSE-MIT or http://opensource.org/licenses/MIT>,
// at your option. All files in the project carrying such
// notice may not be copied, modified, or distributed except
// according to those terms.
//! This module contains the `ensure_image_view_compatible` function, which verifies whether
//! an image view can be used as a render pass attachment.
use std::error;
use std::fmt;
use format::Format;
use framebuffer::RenderPassDesc;
use image::ImageViewAccess;
/// Checks whether the given image view is allowed to be the nth attachment of the given render
/// pass.
///
/// # Panic
///
/// Panicks if the attachment number is out of range.
// TODO: add a specializable trait instead, that uses this function
// TODO: ImageView instead of ImageViewAccess?
pub fn ensure_image_view_compatible<Rp, I>(render_pass: &Rp, attachment_num: usize, image: &I)
-> Result<(), IncompatibleRenderPassAttachmentError>
where Rp: ?Sized + RenderPassDesc,
I: ?Sized + ImageViewAccess
{
let attachment_desc = render_pass.attachment_desc(attachment_num)
.expect("Attachment num out of range");
if image.format() != attachment_desc.format {
return Err(IncompatibleRenderPassAttachmentError::FormatMismatch {
expected: attachment_desc.format,
obtained: image.format(),
});
}
if image.samples() != attachment_desc.samples {
return Err(IncompatibleRenderPassAttachmentError::SamplesMismatch {
expected: attachment_desc.samples,
obtained: image.samples(),
});
}
if !image.identity_swizzle() {
return Err(IncompatibleRenderPassAttachmentError::NotIdentitySwizzled);
}
for subpass_num in 0 .. render_pass.num_subpasses() {
let subpass = render_pass.subpass_desc(subpass_num).expect("Subpass num out of range ; \
wrong RenderPassDesc trait impl");
if subpass.color_attachments.iter().any(|&(n, _)| n == attachment_num) {
debug_assert!(image.parent().has_color()); // Was normally checked by the render pass.
if !image.parent().inner().usage_color_attachment() {
return Err(IncompatibleRenderPassAttachmentError::MissingColorAttachmentUsage);
}
}
if let Some((ds, _)) = subpass.depth_stencil {
if ds == attachment_num {
// Was normally checked by the render pass.
debug_assert!(image.parent().has_depth() || image.parent().has_stencil());
if !image.parent().inner().usage_depth_stencil_attachment() {
return Err(IncompatibleRenderPassAttachmentError::MissingDepthStencilAttachmentUsage);
}
}
}
if subpass.input_attachments.iter().any(|&(n, _)| n == attachment_num) {
if !image.parent().inner().usage_input_attachment() {
return Err(IncompatibleRenderPassAttachmentError::MissingInputAttachmentUsage);
}
}
}
// TODO: consider forbidding LoadOp::Load if image is transient
// TODO: are all image layouts allowed? check this
Ok(())
}
/// Error that can happen when an image is not compatible with a render pass attachment slot.
#[derive(Copy, Clone, Debug)]
pub enum IncompatibleRenderPassAttachmentError {
/// The image format expected by the render pass doesn't match the actual format of
/// the image.
FormatMismatch {
/// Format expected by the render pass.
expected: Format,
/// Format of the image.
obtained: Format,
},
/// The number of samples expected by the render pass doesn't match the number of samples of
/// the image.
SamplesMismatch {
/// Number of samples expected by the render pass.
expected: u32,
/// Number of samples of the image.
obtained: u32,
},
/// The image view has a component swizzle that is different from identity.
NotIdentitySwizzled,
/// The image is used as a color attachment but is missing the color attachment usage.
MissingColorAttachmentUsage,
/// The image is used as a depth/stencil attachment but is missing the depth-stencil attachment
/// usage.
MissingDepthStencilAttachmentUsage,
/// The image is used as an input attachment but is missing the input attachment usage.
MissingInputAttachmentUsage,
}
impl error::Error for IncompatibleRenderPassAttachmentError {
#[inline]
fn description(&self) -> &str {
match *self {
IncompatibleRenderPassAttachmentError::FormatMismatch { .. } => {
"mismatch between the format expected by the render pass and the actual format"
},
IncompatibleRenderPassAttachmentError::SamplesMismatch { .. } => {
"mismatch between the number of samples expected by the render pass and the actual \
number of samples"
},
IncompatibleRenderPassAttachmentError::NotIdentitySwizzled => {
"the image view does not use identity swizzling"
},
IncompatibleRenderPassAttachmentError::MissingColorAttachmentUsage => {
"the image is used as a color attachment but is missing the color attachment usage"
},
IncompatibleRenderPassAttachmentError::MissingDepthStencilAttachmentUsage => {
"the image is used as a depth/stencil attachment but is missing the depth-stencil \
attachment usage"
},
IncompatibleRenderPassAttachmentError::MissingInputAttachmentUsage => {
"the image is used as an input attachment but is missing the input \
attachment usage"
},
}
}
}
impl fmt::Display for IncompatibleRenderPassAttachmentError {
#[inline]
fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
write!(fmt, "{}", error::Error::description(self))
}
}
#[cfg(test)]
mod tests {
use format::Format;
use framebuffer::EmptySinglePassRenderPassDesc;
use image::AttachmentImage;
use image::ImageView;
use super::ensure_image_view_compatible;
use super::IncompatibleRenderPassAttachmentError;
#[test]
fn basic_ok() {
let (device, _) = gfx_dev_and_queue!();
let rp = single_pass_renderpass!(device.clone(),
attachments: {
color: {
load: Clear,
store: Store,
format: Format::R8G8B8A8Unorm,
samples: 1,
}
},
pass: {
color: [color],
depth_stencil: {}
}
).unwrap();
let img = AttachmentImage::new(device, [128, 128], Format::R8G8B8A8Unorm).unwrap();
ensure_image_view_compatible(&rp, 0, &img.access()).unwrap();
}
#[test]
fn format_mismatch() {
let (device, _) = gfx_dev_and_queue!();
let rp = single_pass_renderpass!(device.clone(),
attachments: {
color: {
load: Clear,
store: Store,
format: Format::R16G16Sfloat,
samples: 1,
}
},
pass: {
color: [color],
depth_stencil: {}
}
).unwrap();
let img = AttachmentImage::new(device, [128, 128], Format::R8G8B8A8Unorm).unwrap();
match ensure_image_view_compatible(&rp, 0, &img.access()) {
Err(IncompatibleRenderPassAttachmentError::FormatMismatch {
expected: Format::R16G16Sfloat, obtained: Format::R8G8B8A8Unorm }) => (),
e => panic!("{:?}", e)
}
}
#[test]
#[should_panic(expected = "Attachment num out of range")]
fn attachment_out_of_range() {
let (device, _) = gfx_dev_and_queue!();
let rp = EmptySinglePassRenderPassDesc;
let img = AttachmentImage::new(device, [128, 128], Format::R8G8B8A8Unorm).unwrap();
let _ = ensure_image_view_compatible(&rp, 0, &img.access());
}
// TODO: more tests
}

View File

@ -14,12 +14,10 @@ use format::ClearValue;
use format::Format;
use format::FormatTy;
use framebuffer::RenderPass;
use framebuffer::RenderPassDescAttachmentsList;
use framebuffer::RenderPassDescClearValues;
use framebuffer::RenderPassCompatible;
use framebuffer::RenderPassCreationError;
use image::Layout as ImageLayout;
use image::ImageViewAccess;
use image::ImageLayout as ImageLayout;
use sync::AccessFlagBits;
use sync::PipelineStages;
@ -44,42 +42,46 @@ use vk;
/// - The provided methods shouldn't be overriden with fancy implementations. For example
/// `build_render_pass` must build a render pass from the description and not a different one.
///
pub unsafe trait RenderPassDesc: RenderPassDescClearValues<Vec<ClearValue>> +
RenderPassDescAttachmentsList<Vec<Arc<ImageViewAccess + Send + Sync>>>
{
pub unsafe trait RenderPassDesc: RenderPassDescClearValues<Vec<ClearValue>> {
/// Returns the number of attachments of the render pass.
fn num_attachments(&self) -> usize;
/// Returns the description of an attachment.
///
/// Returns `None` if `num` is superior to `num_attachments()`.
fn attachment(&self, num: usize) -> Option<LayoutAttachmentDescription>;
fn attachment_desc(&self, num: usize) -> Option<LayoutAttachmentDescription>;
/// Returns an iterator to the list of attachments.
#[inline]
fn attachments(&self) -> RenderPassDescAttachments<Self> where Self: Sized {
fn attachment_descs(&self) -> RenderPassDescAttachments<Self> where Self: Sized {
RenderPassDescAttachments { render_pass: self, num: 0 }
}
/// Returns the number of subpasses of the render pass.
fn num_subpasses(&self) -> usize;
/// Returns the description of a suvpass.
/// Returns the description of a subpass.
///
/// Returns `None` if `num` is superior to `num_subpasses()`.
fn subpass(&self, num: usize) -> Option<LayoutPassDescription>;
fn subpass_desc(&self, num: usize) -> Option<LayoutPassDescription>;
/// Returns an iterator to the list of subpasses.
#[inline]
fn subpasses(&self) -> RenderPassDescSubpasses<Self> where Self: Sized {
fn subpass_descs(&self) -> RenderPassDescSubpasses<Self> where Self: Sized {
RenderPassDescSubpasses { render_pass: self, num: 0 }
}
/// Returns the number of dependencies of the render pass.
fn num_dependencies(&self) -> usize;
/// Returns the description of a dependency.
///
/// Returns `None` if `num` is superior to `num_dependencies()`.
fn dependency(&self, num: usize) -> Option<LayoutPassDependencyDescription>;
fn dependency_desc(&self, num: usize) -> Option<LayoutPassDependencyDescription>;
/// Returns an iterator to the list of dependencies.
#[inline]
fn dependencies(&self) -> RenderPassDescDependencies<Self> where Self: Sized {
fn dependency_descs(&self) -> RenderPassDescDependencies<Self> where Self: Sized {
RenderPassDescDependencies { render_pass: self, num: 0 }
}
@ -112,17 +114,17 @@ pub unsafe trait RenderPassDesc: RenderPassDescClearValues<Vec<ClearValue>> +
/// Returns the number of color attachments of a subpass. Returns `None` if out of range.
#[inline]
fn num_color_attachments(&self, subpass: u32) -> Option<u32> {
(&self).subpasses().skip(subpass as usize).next().map(|p| p.color_attachments.len() as u32)
(&self).subpass_descs().skip(subpass as usize).next().map(|p| p.color_attachments.len() as u32)
}
/// Returns the number of samples of the attachments of a subpass. Returns `None` if out of
/// range or if the subpass has no attachment. TODO: return an enum instead?
#[inline]
fn num_samples(&self, subpass: u32) -> Option<u32> {
(&self).subpasses().skip(subpass as usize).next().and_then(|p| {
(&self).subpass_descs().skip(subpass as usize).next().and_then(|p| {
// TODO: chain input attachments as well?
p.color_attachments.iter().cloned().chain(p.depth_stencil.clone().into_iter())
.filter_map(|a| (&self).attachments().skip(a.0).next())
.filter_map(|a| (&self).attachment_descs().skip(a.0).next())
.next().map(|a| a.samples)
})
}
@ -131,13 +133,13 @@ pub unsafe trait RenderPassDesc: RenderPassDescClearValues<Vec<ClearValue>> +
/// second element is `true` if there's a stencil attachment. Returns `None` if out of range.
#[inline]
fn has_depth_stencil_attachment(&self, subpass: u32) -> Option<(bool, bool)> {
(&self).subpasses().skip(subpass as usize).next().map(|p| {
(&self).subpass_descs().skip(subpass as usize).next().map(|p| {
let atch_num = match p.depth_stencil {
Some((d, _)) => d,
None => return (false, false)
};
match (&self).attachments().skip(atch_num).next().unwrap().format.ty() {
match (&self).attachment_descs().skip(atch_num).next().unwrap().format.ty() {
FormatTy::Depth => (true, false),
FormatTy::Stencil => (false, true),
FormatTy::DepthStencil => (true, true),
@ -149,13 +151,13 @@ pub unsafe trait RenderPassDesc: RenderPassDescClearValues<Vec<ClearValue>> +
/// Returns true if a subpass has a depth attachment or a depth-stencil attachment.
#[inline]
fn has_depth(&self, subpass: u32) -> Option<bool> {
(&self).subpasses().skip(subpass as usize).next().map(|p| {
(&self).subpass_descs().skip(subpass as usize).next().map(|p| {
let atch_num = match p.depth_stencil {
Some((d, _)) => d,
None => return false
};
match (&self).attachments().skip(atch_num).next().unwrap().format.ty() {
match (&self).attachment_descs().skip(atch_num).next().unwrap().format.ty() {
FormatTy::Depth => true,
FormatTy::Stencil => false,
FormatTy::DepthStencil => true,
@ -168,7 +170,7 @@ pub unsafe trait RenderPassDesc: RenderPassDescClearValues<Vec<ClearValue>> +
/// layout is not `DepthStencilReadOnlyOptimal`.
#[inline]
fn has_writable_depth(&self, subpass: u32) -> Option<bool> {
(&self).subpasses().skip(subpass as usize).next().map(|p| {
(&self).subpass_descs().skip(subpass as usize).next().map(|p| {
let atch_num = match p.depth_stencil {
Some((d, l)) => {
if l == ImageLayout::DepthStencilReadOnlyOptimal { return false; }
@ -177,7 +179,7 @@ pub unsafe trait RenderPassDesc: RenderPassDescClearValues<Vec<ClearValue>> +
None => return false
};
match (&self).attachments().skip(atch_num).next().unwrap().format.ty() {
match (&self).attachment_descs().skip(atch_num).next().unwrap().format.ty() {
FormatTy::Depth => true,
FormatTy::Stencil => false,
FormatTy::DepthStencil => true,
@ -189,13 +191,13 @@ pub unsafe trait RenderPassDesc: RenderPassDescClearValues<Vec<ClearValue>> +
/// Returns true if a subpass has a stencil attachment or a depth-stencil attachment.
#[inline]
fn has_stencil(&self, subpass: u32) -> Option<bool> {
(&self).subpasses().skip(subpass as usize).next().map(|p| {
(&self).subpass_descs().skip(subpass as usize).next().map(|p| {
let atch_num = match p.depth_stencil {
Some((d, _)) => d,
None => return false
};
match (&self).attachments().skip(atch_num).next().unwrap().format.ty() {
match (&self).attachment_descs().skip(atch_num).next().unwrap().format.ty() {
FormatTy::Depth => false,
FormatTy::Stencil => true,
FormatTy::DepthStencil => true,
@ -208,7 +210,7 @@ pub unsafe trait RenderPassDesc: RenderPassDescClearValues<Vec<ClearValue>> +
/// layout is not `DepthStencilReadOnlyOptimal`.
#[inline]
fn has_writable_stencil(&self, subpass: u32) -> Option<bool> {
(&self).subpasses().skip(subpass as usize).next().map(|p| {
(&self).subpass_descs().skip(subpass as usize).next().map(|p| {
let atch_num = match p.depth_stencil {
Some((d, l)) => {
if l == ImageLayout::DepthStencilReadOnlyOptimal { return false; }
@ -217,7 +219,7 @@ pub unsafe trait RenderPassDesc: RenderPassDescClearValues<Vec<ClearValue>> +
None => return false
};
match (&self).attachments().skip(atch_num).next().unwrap().format.ty() {
match (&self).attachment_descs().skip(atch_num).next().unwrap().format.ty() {
FormatTy::Depth => false,
FormatTy::Stencil => true,
FormatTy::DepthStencil => true,
@ -234,8 +236,8 @@ unsafe impl<T> RenderPassDesc for T where T: SafeDeref, T::Target: RenderPassDes
}
#[inline]
fn attachment(&self, num: usize) -> Option<LayoutAttachmentDescription> {
(**self).attachment(num)
fn attachment_desc(&self, num: usize) -> Option<LayoutAttachmentDescription> {
(**self).attachment_desc(num)
}
#[inline]
@ -244,8 +246,8 @@ unsafe impl<T> RenderPassDesc for T where T: SafeDeref, T::Target: RenderPassDes
}
#[inline]
fn subpass(&self, num: usize) -> Option<LayoutPassDescription> {
(**self).subpass(num)
fn subpass_desc(&self, num: usize) -> Option<LayoutPassDescription> {
(**self).subpass_desc(num)
}
#[inline]
@ -254,8 +256,8 @@ unsafe impl<T> RenderPassDesc for T where T: SafeDeref, T::Target: RenderPassDes
}
#[inline]
fn dependency(&self, num: usize) -> Option<LayoutPassDependencyDescription> {
(**self).dependency(num)
fn dependency_desc(&self, num: usize) -> Option<LayoutPassDependencyDescription> {
(**self).dependency_desc(num)
}
}
@ -273,7 +275,7 @@ impl<'a, R: ?Sized + 'a> Iterator for RenderPassDescAttachments<'a, R> where R:
if self.num < self.render_pass.num_attachments() {
let n = self.num;
self.num += 1;
Some(self.render_pass.attachment(n).expect("Wrong RenderPassDesc implementation"))
Some(self.render_pass.attachment_desc(n).expect("Wrong RenderPassDesc implementation"))
} else {
None
}
@ -294,7 +296,7 @@ impl<'a, R: ?Sized + 'a> Iterator for RenderPassDescSubpasses<'a, R> where R: Re
if self.num < self.render_pass.num_subpasses() {
let n = self.num;
self.num += 1;
Some(self.render_pass.subpass(n).expect("Wrong RenderPassDesc implementation"))
Some(self.render_pass.subpass_desc(n).expect("Wrong RenderPassDesc implementation"))
} else {
None
}
@ -315,7 +317,7 @@ impl<'a, R: ?Sized + 'a> Iterator for RenderPassDescDependencies<'a, R> where R:
if self.num < self.render_pass.num_dependencies() {
let n = self.num;
self.num += 1;
Some(self.render_pass.dependency(n).expect("Wrong RenderPassDesc implementation"))
Some(self.render_pass.dependency_desc(n).expect("Wrong RenderPassDesc implementation"))
} else {
None
}

View File

@ -8,17 +8,12 @@
// according to those terms.
use std::iter;
use std::sync::Arc;
use format::ClearValue;
use framebuffer::AttachmentsList;
use framebuffer::FramebufferCreationError;
use framebuffer::RenderPassDesc;
use framebuffer::RenderPassDescAttachmentsList;
use framebuffer::RenderPassDescClearValues;
use framebuffer::LayoutAttachmentDescription;
use framebuffer::LayoutPassDescription;
use framebuffer::LayoutPassDependencyDescription;
use image::ImageViewAccess;
/// Description of an empty render pass.
///
@ -49,7 +44,7 @@ unsafe impl RenderPassDesc for EmptySinglePassRenderPassDesc {
}
#[inline]
fn attachment(&self, num: usize) -> Option<LayoutAttachmentDescription> {
fn attachment_desc(&self, num: usize) -> Option<LayoutAttachmentDescription> {
None
}
@ -59,7 +54,7 @@ unsafe impl RenderPassDesc for EmptySinglePassRenderPassDesc {
}
#[inline]
fn subpass(&self, num: usize) -> Option<LayoutPassDescription> {
fn subpass_desc(&self, num: usize) -> Option<LayoutPassDescription> {
if num == 0 {
Some(LayoutPassDescription {
color_attachments: vec![],
@ -79,7 +74,7 @@ unsafe impl RenderPassDesc for EmptySinglePassRenderPassDesc {
}
#[inline]
fn dependency(&self, num: usize) -> Option<LayoutPassDependencyDescription> {
fn dependency_desc(&self, num: usize) -> Option<LayoutPassDependencyDescription> {
None
}
@ -143,24 +138,6 @@ unsafe impl RenderPassDesc for EmptySinglePassRenderPassDesc {
}
}
unsafe impl RenderPassDescAttachmentsList<Vec<Arc<ImageViewAccess + Send + Sync>>> for EmptySinglePassRenderPassDesc {
#[inline]
fn check_attachments_list(&self, list: Vec<Arc<ImageViewAccess + Send + Sync>>) -> Result<Box<AttachmentsList + Send + Sync>, FramebufferCreationError> {
if list.is_empty() {
Ok(Box::new(()) as Box<_>)
} else {
panic!() // FIXME: return error instead
}
}
}
unsafe impl RenderPassDescAttachmentsList<()> for EmptySinglePassRenderPassDesc {
#[inline]
fn check_attachments_list(&self, list: ()) -> Result<Box<AttachmentsList + Send + Sync>, FramebufferCreationError> {
Ok(Box::new(()) as Box<_>)
}
}
unsafe impl RenderPassDescClearValues<Vec<ClearValue>> for EmptySinglePassRenderPassDesc {
#[inline]
fn convert_clear_values(&self, values: Vec<ClearValue>) -> Box<Iterator<Item = ClearValue>> {

View File

@ -7,6 +7,7 @@
// notice may not be copied, modified, or distributed except
// according to those terms.
use std::cmp;
use std::error;
use std::fmt;
use std::marker::PhantomData;
@ -20,14 +21,16 @@ use device::DeviceOwned;
use format::ClearValue;
use framebuffer::AttachmentsList;
use framebuffer::FramebufferAbstract;
use framebuffer::IncompatibleRenderPassAttachmentError;
use framebuffer::LayoutAttachmentDescription;
use framebuffer::LayoutPassDependencyDescription;
use framebuffer::LayoutPassDescription;
use framebuffer::RenderPassAbstract;
use framebuffer::RenderPassDescClearValues;
use framebuffer::RenderPassDescAttachmentsList;
use framebuffer::RenderPassDesc;
use framebuffer::RenderPassSys;
use framebuffer::ensure_image_view_compatible;
use image::ImageView;
use image::ImageViewAccess;
use Error;
@ -37,88 +40,47 @@ use VulkanPointers;
use check_errors;
use vk;
/// Contains the list of images attached to a render pass.
/// Contains a render pass and the image views that are attached to it.
///
/// Creating a framebuffer is done by passing the render pass object, the dimensions of the
/// framebuffer, and the list of attachments to `Framebuffer::new()`.
/// Creating a framebuffer is done by calling `Framebuffer::start`, which returns a
/// `FramebufferBuilder` object. You can then add the framebuffer attachments one by one by
/// calling `add(image)`. When you are done, call `build()`.
///
/// Just like all render pass objects implement the `RenderPassAbstract` trait, all framebuffer
/// objects implement the `FramebufferAbstract` trait. This means that you can cast any
/// `Arc<Framebuffer<..>>` into an `Arc<FramebufferAbstract + Send + Sync>` for easier storage.
/// Both the `add` and the `build` functions perform various checks to make sure that the number
/// of images is correct and that each image is compatible with the attachment definition in the
/// render pass.
///
/// ## With a generic list of attachments
///
/// The list of attachments passed to `Framebuffer::new()` can be of various types, but one of the
/// possibilities is to pass an object of type `Vec<Arc<ImageView + Send + Sync>>`.
///
/// > **Note**: If you access a render pass object through the `RenderPassAbstract` trait, passing
/// > a `Vec<Arc<ImageView + Send + Sync>>` is the only possible method.
///
/// The framebuffer constructor will perform various checks to make sure that the number of images
/// is correct and that each image can be used with this render pass.
///
/// ```ignore // FIXME: unignore
/// ```
/// # use std::sync::Arc;
/// # use vulkano::framebuffer::RenderPassAbstract;
/// use vulkano::framebuffer::Framebuffer;
///
/// # let render_pass: Arc<RenderPassAbstract + Send + Sync> = return;
/// # let my_image: Arc<vulkano::image::ImageViewAccess> = return;
/// // let render_pass: Arc<RenderPassAbstract + Send + Sync> = ...;
/// let framebuffer = Framebuffer::new(render_pass.clone(), [1024, 768, 1],
/// vec![my_image.clone() as Arc<_>]).unwrap();
/// # let my_image: Arc<vulkano::image::AttachmentImage<vulkano::format::Format>> = return;
/// // let render_pass: Arc<_> = ...;
/// let framebuffer = Framebuffer::start(render_pass.clone())
/// .add(my_image).unwrap()
/// .build().unwrap();
/// ```
///
/// ## With a specialized list of attachments
/// Just like render pass objects implement the `RenderPassAbstract` trait, all framebuffer
/// objects implement the `FramebufferAbstract` trait. This means that you can cast any
/// `Arc<Framebuffer<..>>` into an `Arc<FramebufferAbstract + Send + Sync>` for easier storage.
///
/// The list of attachments can also be of any type `T`, as long as the render pass description
/// implements the trait `RenderPassDescAttachmentsList<T>`.
/// ## Framebuffer dimensions
///
/// For example if you pass a render pass object that implements
/// `RenderPassDescAttachmentsList<Foo>`, then you can pass a `Foo` as the list of attachments.
/// If you use `Framebuffer::start()` to create a framebuffer then vulkano will automatically
/// make sure that all the attachments have the same dimensions, as this is the most common
/// situation.
///
/// > **Note**: The reason why `Vec<Arc<ImageView + Send + Sync>>` always works (see previous section) is that
/// > render pass descriptions are required to always implement
/// > `RenderPassDescAttachmentsList<Vec<Arc<ImageViewAccess + Send + Sync>>>`.
/// Alternatively you can also use `with_intersecting_dimensions`, in which case the dimensions of
/// the framebuffer will be the intersection of the dimensions of all attachments, or
/// `with_dimensions` if you want to specify exact dimensions. If you use `with_dimensions`, you
/// are allowed to attach images that are larger than these dimensions.
///
/// When it comes to the `single_pass_renderpass!` and `ordered_passes_renderpass!` macros, you can
/// build a list of attachments by calling `start_attachments()` on the render pass description,
/// which will return an object that has a method whose name is the name of the first attachment
/// and that can be used to specify it. This method will return another object that has a method
/// whose name is the name of the second attachment, and so on. See the documentation of the macros
/// for more details. TODO: put link here
/// If the dimensions of the framebuffer don't match the dimensions of one of its attachment, then
/// only the top-left hand corner of the image will be drawn to.
///
/// ```ignore // FIXME: unignore
/// # #[macro_use] extern crate vulkano;
/// # fn main() {
/// # let device: std::sync::Arc<vulkano::device::Device> = return;
/// use std::sync::Arc;
/// use vulkano::format::Format;
/// use vulkano::framebuffer::Framebuffer;
///
/// let render_pass = single_pass_renderpass!(device.clone(),
/// attachments: {
/// // `foo` is a custom name we give to the first and only attachment.
/// foo: {
/// load: Clear,
/// store: Store,
/// format: Format::R8G8B8A8Unorm,
/// samples: 1,
/// }
/// },
/// pass: {
/// color: [foo], // Repeat the attachment name here.
/// depth_stencil: {}
/// }
/// ).unwrap();
///
/// # let my_image: Arc<vulkano::image::ImageViewAccess> = return;
/// let framebuffer = {
/// let atch = render_pass.desc().start_attachments().foo(my_image.clone() as Arc<_>);
/// Framebuffer::new(render_pass, [1024, 768, 1], atch).unwrap()
/// };
/// # }
/// ```
#[derive(Debug)]
pub struct Framebuffer<Rp, A> {
device: Arc<Device>,
@ -128,24 +90,199 @@ pub struct Framebuffer<Rp, A> {
resources: A,
}
impl<Rp> Framebuffer<Rp, Box<AttachmentsList + Send + Sync>> {
/// Builds a new framebuffer.
///
/// The `attachments` parameter depends on which render pass implementation is used.
// TODO: allow ImageView
pub fn new<Ia>(render_pass: Rp, dimensions: [u32; 3], attachments: Ia)
-> Result<Arc<Framebuffer<Rp, Box<AttachmentsList + Send + Sync>>>, FramebufferCreationError>
where Rp: RenderPassAbstract + RenderPassDescAttachmentsList<Ia>
{
let device = render_pass.device().clone();
impl<Rp> Framebuffer<Rp, ()> {
/// Starts building a framebuffer.
pub fn start(render_pass: Rp) -> FramebufferBuilder<Rp, ()> {
FramebufferBuilder {
render_pass: render_pass,
raw_ids: SmallVec::new(),
dimensions: FramebufferBuilderDimensions::AutoIdentical(None),
attachments: (),
}
}
// This function call is supposed to check whether the attachments are valid.
// For more safety, we do some additional `debug_assert`s below.
let attachments = try!(render_pass.check_attachments_list(attachments));
/// Starts building a framebuffer. The dimensions of the framebuffer will automatically be
/// the intersection of the dimensions of all the attachments.
pub fn with_intersecting_dimensions(render_pass: Rp) -> FramebufferBuilder<Rp, ()> {
FramebufferBuilder {
render_pass: render_pass,
raw_ids: SmallVec::new(),
dimensions: FramebufferBuilderDimensions::AutoSmaller(None),
attachments: (),
}
}
/// Starts building a framebuffer.
pub fn with_dimensions(render_pass: Rp, dimensions: [u32; 3]) -> FramebufferBuilder<Rp, ()> {
FramebufferBuilder {
render_pass: render_pass,
raw_ids: SmallVec::new(),
dimensions: FramebufferBuilderDimensions::Specific(dimensions),
attachments: (),
}
}
}
/// Prototype of a framebuffer.
pub struct FramebufferBuilder<Rp, A> {
render_pass: Rp,
raw_ids: SmallVec<[vk::ImageView; 8]>,
dimensions: FramebufferBuilderDimensions,
attachments: A,
}
impl<Rp, A> fmt::Debug for FramebufferBuilder<Rp, A> where Rp: fmt::Debug, A: fmt::Debug {
#[inline]
fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
fmt.debug_struct("FramebufferBuilder")
.field("render_pass", &self.render_pass)
.field("dimensions", &self.dimensions)
.field("attachments", &self.attachments)
.finish()
}
}
#[derive(Debug)]
enum FramebufferBuilderDimensions {
AutoIdentical(Option<[u32; 3]>),
AutoSmaller(Option<[u32; 3]>),
Specific([u32; 3]),
}
impl<Rp, A> FramebufferBuilder<Rp, A>
where Rp: RenderPassAbstract,
A: AttachmentsList,
{
/// Appends an attachment to the prototype of the framebuffer.
///
/// Attachments must be added in the same order as the one defined in the render pass.
pub fn add<T>(self, attachment: T)
-> Result<FramebufferBuilder<Rp, (A, T::Access)>, FramebufferCreationError>
where T: ImageView
{
let access = attachment.access();
if self.raw_ids.len() >= self.render_pass.num_attachments() {
return Err(FramebufferCreationError::AttachmentsCountMismatch {
expected: self.render_pass.num_attachments(),
obtained: self.raw_ids.len() + 1,
});
}
match ensure_image_view_compatible(&self.render_pass, self.raw_ids.len(), &access) {
Ok(()) => (),
Err(err) => return Err(FramebufferCreationError::IncompatibleAttachment(err))
};
let img_dims = access.dimensions();
debug_assert_eq!(img_dims.depth(), 1);
let dimensions = match self.dimensions {
FramebufferBuilderDimensions::AutoIdentical(None) => {
let dims = [img_dims.width(), img_dims.height(), img_dims.array_layers()];
FramebufferBuilderDimensions::AutoIdentical(Some(dims))
},
FramebufferBuilderDimensions::AutoIdentical(Some(current)) => {
if img_dims.width() != current[0] || img_dims.height() != current[1] ||
img_dims.array_layers() != current[2]
{
return Err(FramebufferCreationError::AttachmentDimensionsIncompatible {
expected: current,
obtained: [img_dims.width(), img_dims.height(), img_dims.array_layers()]
});
}
FramebufferBuilderDimensions::AutoIdentical(Some(current))
}
FramebufferBuilderDimensions::AutoSmaller(None) => {
let dims = [img_dims.width(), img_dims.height(), img_dims.array_layers()];
FramebufferBuilderDimensions::AutoSmaller(Some(dims))
},
FramebufferBuilderDimensions::AutoSmaller(Some(current)) => {
let new_dims = [
cmp::min(current[0], img_dims.width()),
cmp::min(current[1], img_dims.height()),
cmp::min(current[2], img_dims.array_layers())
];
FramebufferBuilderDimensions::AutoSmaller(Some(new_dims))
},
FramebufferBuilderDimensions::Specific(current) => {
if img_dims.width() < current[0] || img_dims.height() < current[1] ||
img_dims.array_layers() < current[2]
{
return Err(FramebufferCreationError::AttachmentDimensionsIncompatible {
expected: current,
obtained: [img_dims.width(), img_dims.height(), img_dims.array_layers()]
});
}
FramebufferBuilderDimensions::Specific([
img_dims.width(),
img_dims.height(),
img_dims.array_layers()
])
}
};
let mut raw_ids = self.raw_ids;
raw_ids.push(access.inner().internal_object());
Ok(FramebufferBuilder {
render_pass: self.render_pass,
raw_ids: raw_ids,
dimensions: dimensions,
attachments: (self.attachments, access),
})
}
/// Turns this builder into a `FramebufferBuilder<Rp, Box<AttachmentsList>>`.
///
/// This allows you to store the builder in situations where you don't know in advance the
/// number of attachments.
///
/// > **Note**: This is a very rare corner case and you shouldn't have to use this function
/// > in most situations.
#[inline]
pub fn boxed(self) -> FramebufferBuilder<Rp, Box<AttachmentsList>>
where A: 'static
{
FramebufferBuilder {
render_pass: self.render_pass,
raw_ids: self.raw_ids,
dimensions: self.dimensions,
attachments: Box::new(self.attachments) as Box<_>,
}
}
/// Builds the framebuffer.
pub fn build(self) -> Result<Framebuffer<Rp, A>, FramebufferCreationError> {
let device = self.render_pass.device().clone();
// Check the number of attachments.
if self.raw_ids.len() != self.render_pass.num_attachments() {
return Err(FramebufferCreationError::AttachmentsCountMismatch {
expected: self.render_pass.num_attachments(),
obtained: self.raw_ids.len(),
});
}
// Compute the dimensions.
let dimensions = match self.dimensions {
FramebufferBuilderDimensions::Specific(dims) |
FramebufferBuilderDimensions::AutoIdentical(Some(dims)) |
FramebufferBuilderDimensions::AutoSmaller(Some(dims)) => {
dims
},
FramebufferBuilderDimensions::AutoIdentical(None) |
FramebufferBuilderDimensions::AutoSmaller(None) => {
return Err(FramebufferCreationError::CantDetermineDimensions);
},
};
// Checking the dimensions against the limits.
{
let limits = render_pass.device().physical_device().limits();
let limits = device.physical_device().limits();
let limits = [limits.max_framebuffer_width(), limits.max_framebuffer_height(),
limits.max_framebuffer_layers()];
if dimensions[0] > limits[0] || dimensions[1] > limits[1] ||
@ -155,28 +292,16 @@ impl<Rp> Framebuffer<Rp, Box<AttachmentsList + Send + Sync>> {
}
}
// Checking the dimensions against the attachments.
if let Some(dims_constraints) = attachments.intersection_dimensions() {
if dims_constraints[0] < dimensions[0] || dims_constraints[1] < dimensions[1] ||
dims_constraints[2] < dimensions[2]
{
return Err(FramebufferCreationError::AttachmentTooSmall);
}
}
let ids: SmallVec<[vk::ImageView; 8]> =
attachments.raw_image_view_handles().into_iter().map(|v| v.internal_object()).collect();
let framebuffer = unsafe {
let vk = render_pass.device().pointers();
let vk = device.pointers();
let infos = vk::FramebufferCreateInfo {
sType: vk::STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO,
pNext: ptr::null(),
flags: 0, // reserved
renderPass: render_pass.inner().internal_object(),
attachmentCount: ids.len() as u32,
pAttachments: ids.as_ptr(),
renderPass: self.render_pass.inner().internal_object(),
attachmentCount: self.raw_ids.len() as u32,
pAttachments: self.raw_ids.as_ptr(),
width: dimensions[0],
height: dimensions[1],
layers: dimensions[2],
@ -188,13 +313,13 @@ impl<Rp> Framebuffer<Rp, Box<AttachmentsList + Send + Sync>> {
output
};
Ok(Arc::new(Framebuffer {
Ok(Framebuffer {
device: device,
render_pass: render_pass,
render_pass: self.render_pass,
framebuffer: framebuffer,
dimensions: dimensions,
resources: attachments,
}))
resources: self.attachments,
})
}
}
@ -263,8 +388,8 @@ unsafe impl<Rp, A> RenderPassDesc for Framebuffer<Rp, A> where Rp: RenderPassDes
}
#[inline]
fn attachment(&self, num: usize) -> Option<LayoutAttachmentDescription> {
self.render_pass.attachment(num)
fn attachment_desc(&self, num: usize) -> Option<LayoutAttachmentDescription> {
self.render_pass.attachment_desc(num)
}
#[inline]
@ -273,8 +398,8 @@ unsafe impl<Rp, A> RenderPassDesc for Framebuffer<Rp, A> where Rp: RenderPassDes
}
#[inline]
fn subpass(&self, num: usize) -> Option<LayoutPassDescription> {
self.render_pass.subpass(num)
fn subpass_desc(&self, num: usize) -> Option<LayoutPassDescription> {
self.render_pass.subpass_desc(num)
}
#[inline]
@ -283,17 +408,8 @@ unsafe impl<Rp, A> RenderPassDesc for Framebuffer<Rp, A> where Rp: RenderPassDes
}
#[inline]
fn dependency(&self, num: usize) -> Option<LayoutPassDependencyDescription> {
self.render_pass.dependency(num)
}
}
unsafe impl<At, Rp, A> RenderPassDescAttachmentsList<At> for Framebuffer<Rp, A>
where Rp: RenderPassDescAttachmentsList<At>
{
#[inline]
fn check_attachments_list(&self, atch: At) -> Result<Box<AttachmentsList + Send + Sync>, FramebufferCreationError> {
self.render_pass.check_attachments_list(atch)
fn dependency_desc(&self, num: usize) -> Option<LayoutPassDependencyDescription> {
self.render_pass.dependency_desc(num)
}
}
@ -344,17 +460,30 @@ unsafe impl<'a> VulkanObject for FramebufferSys<'a> {
}
/// Error that can happen when creating a framebuffer object.
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
#[repr(u32)]
#[derive(Copy, Clone, Debug)]
pub enum FramebufferCreationError {
/// Out of memory.
OomError(OomError),
/// The requested dimensions exceed the device's limits.
DimensionsTooLarge,
/// One of the attachments has a component swizzle that is different from identity.
AttachmentNotIdentitySwizzled,
/// One of the attachments is too small compared to the requested framebuffer dimensions.
AttachmentTooSmall,
/// The attachment has a size that isn't compatible with the requested framebuffer dimensions.
AttachmentDimensionsIncompatible {
/// Expected dimensions.
expected: [u32; 3],
/// Attachment dimensions.
obtained: [u32; 3],
},
/// The number of attachments doesn't match the number expected by the render pass.
AttachmentsCountMismatch {
/// Expected number of attachments.
expected: usize,
/// Number of attachments that were given.
obtained: usize,
},
/// One of the images cannot be used as the requested attachment.
IncompatibleAttachment(IncompatibleRenderPassAttachmentError),
/// The framebuffer has no attachment and no dimension was specified.
CantDetermineDimensions,
}
impl From<OomError> for FramebufferCreationError {
@ -371,12 +500,17 @@ impl error::Error for FramebufferCreationError {
FramebufferCreationError::OomError(_) => "no memory available",
FramebufferCreationError::DimensionsTooLarge => "the dimensions of the framebuffer \
are too large",
FramebufferCreationError::AttachmentNotIdentitySwizzled => {
"one of the attachments has a component swizzle that is different from identity"
FramebufferCreationError::AttachmentDimensionsIncompatible { .. } => {
"the attachment has a size that isn't compatible with the framebuffer dimensions"
},
FramebufferCreationError::AttachmentTooSmall => {
"one of the attachments is too small compared to the requested framebuffer \
dimensions"
FramebufferCreationError::AttachmentsCountMismatch { .. } => {
"the number of attachments doesn't match the number expected by the render pass"
},
FramebufferCreationError::IncompatibleAttachment(_) => {
"one of the images cannot be used as the requested attachment"
},
FramebufferCreationError::CantDetermineDimensions => {
"the framebuffer has no attachment and no dimension was specified"
},
}
}
@ -385,6 +519,7 @@ impl error::Error for FramebufferCreationError {
fn cause(&self) -> Option<&error::Error> {
match *self {
FramebufferCreationError::OomError(ref err) => Some(err),
FramebufferCreationError::IncompatibleAttachment(ref err) => Some(err),
_ => None,
}
}
@ -404,70 +539,314 @@ impl From<Error> for FramebufferCreationError {
}
}
/* FIXME: restore
#[cfg(test)]
mod tests {
use format::R8G8B8A8Unorm;
use std::sync::Arc;
use format::Format;
use framebuffer::EmptySinglePassRenderPassDesc;
use framebuffer::Framebuffer;
use framebuffer::FramebufferCreationError;
use framebuffer::RenderPassDesc;
use image::attachment::AttachmentImage;
#[test]
fn simple_create() {
let (device, _) = gfx_dev_and_queue!();
let render_pass = single_pass_renderpass! {
let render_pass = Arc::new(single_pass_renderpass!(device.clone(),
attachments: {
color: {
load: Clear,
store: DontCare,
format: R8G8B8A8Unorm,
format: Format::R8G8B8A8Unorm,
samples: 1,
}
},
pass: {
color: [color],
depth_stencil: {}
}
}.unwrap();
).unwrap());
let image = AttachmentImage::new(&device, [1024, 768], R8G8B8A8Unorm).unwrap();
let _ = Framebuffer::new(render_pass, [1024, 768, 1], example::AList {
color: image.clone()
}).unwrap();
let image = AttachmentImage::new(device.clone(), [1024, 768],
Format::R8G8B8A8Unorm).unwrap();
let _ = Framebuffer::start(render_pass).add(image.clone()).unwrap().build().unwrap();
}
#[test]
fn framebuffer_too_large() {
fn check_device_limits() {
let (device, _) = gfx_dev_and_queue!();
let render_pass = example::CustomRenderPass::new(&device, &example::Formats {
color: (R8G8B8A8Unorm, 1)
}).unwrap();
let image = AttachmentImage::new(&device, [1024, 768], R8G8B8A8Unorm).unwrap();
let alist = example::AList { color: image.clone() };
match Framebuffer::new(render_pass, [0xffffffff, 0xffffffff, 0xffffffff], alist) {
let rp = EmptySinglePassRenderPassDesc.build_render_pass(device).unwrap();
let res = Framebuffer::with_dimensions(rp, [0xffffffff, 0xffffffff, 0xffffffff]).build();
match res {
Err(FramebufferCreationError::DimensionsTooLarge) => (),
_ => panic!()
}
}
#[test]
fn attachment_too_small() {
fn attachment_format_mismatch() {
let (device, _) = gfx_dev_and_queue!();
let render_pass = example::CustomRenderPass::new(&device, &example::Formats {
color: (R8G8B8A8Unorm, 1)
}).unwrap();
let render_pass = Arc::new(single_pass_renderpass!(device.clone(),
attachments: {
color: {
load: Clear,
store: DontCare,
format: Format::R8G8B8A8Unorm,
samples: 1,
}
},
pass: {
color: [color],
depth_stencil: {}
}
).unwrap());
let image = AttachmentImage::new(&device, [512, 512], R8G8B8A8Unorm).unwrap();
let image = AttachmentImage::new(device.clone(), [1024, 768],
Format::R8Unorm).unwrap();
let alist = example::AList { color: image.clone() };
match Framebuffer::new(render_pass, [600, 600, 1], alist) {
Err(FramebufferCreationError::AttachmentTooSmall) => (),
match Framebuffer::start(render_pass).add(image.clone()) {
Err(FramebufferCreationError::IncompatibleAttachment(_)) => (),
_ => panic!()
}
}
}*/
// TODO: check samples mismatch
#[test]
fn attachment_dims_larger_than_specified_valid() {
let (device, _) = gfx_dev_and_queue!();
let render_pass = Arc::new(single_pass_renderpass!(device.clone(),
attachments: {
color: {
load: Clear,
store: DontCare,
format: Format::R8G8B8A8Unorm,
samples: 1,
}
},
pass: {
color: [color],
depth_stencil: {}
}
).unwrap());
let img = AttachmentImage::new(device.clone(), [600, 600], Format::R8G8B8A8Unorm).unwrap();
let _ = Framebuffer::with_dimensions(render_pass, [512, 512, 1])
.add(img).unwrap()
.build().unwrap();
}
#[test]
fn attachment_dims_smaller_than_specified() {
let (device, _) = gfx_dev_and_queue!();
let render_pass = Arc::new(single_pass_renderpass!(device.clone(),
attachments: {
color: {
load: Clear,
store: DontCare,
format: Format::R8G8B8A8Unorm,
samples: 1,
}
},
pass: {
color: [color],
depth_stencil: {}
}
).unwrap());
let img = AttachmentImage::new(device.clone(), [512, 700], Format::R8G8B8A8Unorm).unwrap();
match Framebuffer::with_dimensions(render_pass, [600, 600, 1]).add(img) {
Err(FramebufferCreationError::AttachmentDimensionsIncompatible { expected, obtained }) => {
assert_eq!(expected, [600, 600, 1]);
assert_eq!(obtained, [512, 700, 1]);
},
_ => panic!()
}
}
#[test]
fn multi_attachments_dims_not_identical() {
let (device, _) = gfx_dev_and_queue!();
let render_pass = Arc::new(single_pass_renderpass!(device.clone(),
attachments: {
a: {
load: Clear,
store: DontCare,
format: Format::R8G8B8A8Unorm,
samples: 1,
},
b: {
load: Clear,
store: DontCare,
format: Format::R8G8B8A8Unorm,
samples: 1,
}
},
pass: {
color: [a, b],
depth_stencil: {}
}
).unwrap());
let a = AttachmentImage::new(device.clone(), [512, 512], Format::R8G8B8A8Unorm).unwrap();
let b = AttachmentImage::new(device.clone(), [512, 513], Format::R8G8B8A8Unorm).unwrap();
match Framebuffer::start(render_pass).add(a).unwrap().add(b) {
Err(FramebufferCreationError::AttachmentDimensionsIncompatible { expected, obtained }) => {
assert_eq!(expected, [512, 512, 1]);
assert_eq!(obtained, [512, 513, 1]);
},
_ => panic!()
}
}
#[test]
fn multi_attachments_auto_smaller() {
let (device, _) = gfx_dev_and_queue!();
let render_pass = Arc::new(single_pass_renderpass!(device.clone(),
attachments: {
a: {
load: Clear,
store: DontCare,
format: Format::R8G8B8A8Unorm,
samples: 1,
},
b: {
load: Clear,
store: DontCare,
format: Format::R8G8B8A8Unorm,
samples: 1,
}
},
pass: {
color: [a, b],
depth_stencil: {}
}
).unwrap());
let a = AttachmentImage::new(device.clone(), [256, 512], Format::R8G8B8A8Unorm).unwrap();
let b = AttachmentImage::new(device.clone(), [512, 128], Format::R8G8B8A8Unorm).unwrap();
let fb = Framebuffer::with_intersecting_dimensions(render_pass)
.add(a).unwrap()
.add(b).unwrap()
.build().unwrap();
match (fb.width(), fb.height(), fb.layers()) {
(256, 128, 1) => (),
_ => panic!()
}
}
#[test]
fn not_enough_attachments() {
let (device, _) = gfx_dev_and_queue!();
let render_pass = Arc::new(single_pass_renderpass!(device.clone(),
attachments: {
a: {
load: Clear,
store: DontCare,
format: Format::R8G8B8A8Unorm,
samples: 1,
},
b: {
load: Clear,
store: DontCare,
format: Format::R8G8B8A8Unorm,
samples: 1,
}
},
pass: {
color: [a, b],
depth_stencil: {}
}
).unwrap());
let img = AttachmentImage::new(device.clone(), [256, 512], Format::R8G8B8A8Unorm).unwrap();
let res = Framebuffer::with_intersecting_dimensions(render_pass)
.add(img).unwrap()
.build();
match res {
Err(FramebufferCreationError::AttachmentsCountMismatch { expected: 2,
obtained: 1 }) => (),
_ => panic!()
}
}
#[test]
fn too_many_attachments() {
let (device, _) = gfx_dev_and_queue!();
let render_pass = Arc::new(single_pass_renderpass!(device.clone(),
attachments: {
a: {
load: Clear,
store: DontCare,
format: Format::R8G8B8A8Unorm,
samples: 1,
}
},
pass: {
color: [a],
depth_stencil: {}
}
).unwrap());
let a = AttachmentImage::new(device.clone(), [256, 512], Format::R8G8B8A8Unorm).unwrap();
let b = AttachmentImage::new(device.clone(), [256, 512], Format::R8G8B8A8Unorm).unwrap();
let res = Framebuffer::with_intersecting_dimensions(render_pass)
.add(a).unwrap()
.add(b);
match res {
Err(FramebufferCreationError::AttachmentsCountMismatch { expected: 1,
obtained: 2 }) => (),
_ => panic!()
}
}
#[test]
fn empty_working() {
let (device, _) = gfx_dev_and_queue!();
let rp = EmptySinglePassRenderPassDesc.build_render_pass(device).unwrap();
let _ = Framebuffer::with_dimensions(rp, [512, 512, 1]).build().unwrap();
}
#[test]
fn cant_determine_dimensions_auto() {
let (device, _) = gfx_dev_and_queue!();
let rp = EmptySinglePassRenderPassDesc.build_render_pass(device).unwrap();
let res = Framebuffer::start(rp).build();
match res {
Err(FramebufferCreationError::CantDetermineDimensions) => (),
_ => panic!()
}
}
#[test]
fn cant_determine_dimensions_intersect() {
let (device, _) = gfx_dev_and_queue!();
let rp = EmptySinglePassRenderPassDesc.build_render_pass(device).unwrap();
let res = Framebuffer::with_intersecting_dimensions(rp).build();
match res {
Err(FramebufferCreationError::CantDetermineDimensions) => (),
_ => panic!()
}
}
}

View File

@ -65,19 +65,14 @@ macro_rules! ordered_passes_renderpass {
#![allow(non_camel_case_types)]
#![allow(non_snake_case)]
use std::sync::Arc;
use $crate::format::ClearValue;
use $crate::format::Format;
use $crate::framebuffer::AttachmentsList;
use $crate::framebuffer::FramebufferCreationError;
use $crate::framebuffer::RenderPassDesc;
use $crate::framebuffer::RenderPassDescAttachmentsList;
use $crate::framebuffer::RenderPassDescClearValues;
use $crate::framebuffer::LayoutAttachmentDescription;
use $crate::framebuffer::LayoutPassDescription;
use $crate::framebuffer::LayoutPassDependencyDescription;
use $crate::image::Layout;
use $crate::image::ImageViewAccess;
use $crate::image::ImageLayout;
use $crate::sync::AccessFlagBits;
use $crate::sync::PipelineStages;
@ -87,37 +82,6 @@ macro_rules! ordered_passes_renderpass {
)*
}
impl CustomRenderPassDesc {
#[inline]
pub fn start_attachments(&self) -> atch::AttachmentsStart {
atch::AttachmentsStart
}
#[inline]
pub fn start_clear_values(&self) -> cv::ClearValuesStart {
cv::ClearValuesStart
}
}
pub mod atch {
use $crate::framebuffer::AttachmentsList;
use $crate::framebuffer::FramebufferCreationError;
use $crate::framebuffer::RenderPassDescAttachmentsList;
use $crate::image::traits::ImageViewAccess;
use super::CustomRenderPassDesc;
pub struct AttachmentsStart;
ordered_passes_renderpass!{[] __impl_attachments__ [] [] [$($atch_name),*] [A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z]}
}
pub mod cv {
use std::iter;
use $crate::format::ClearValue;
use $crate::framebuffer::RenderPassDescClearValues;
use super::CustomRenderPassDesc;
pub struct ClearValuesStart;
ordered_passes_renderpass!{[] __impl_clear_values__ [] [] [$($atch_name: $load),*] [A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z]}
}
#[allow(unsafe_code)]
unsafe impl RenderPassDesc for CustomRenderPassDesc {
#[inline]
@ -126,7 +90,7 @@ macro_rules! ordered_passes_renderpass {
}
#[inline]
fn attachment(&self, id: usize) -> Option<LayoutAttachmentDescription> {
fn attachment_desc(&self, id: usize) -> Option<LayoutAttachmentDescription> {
attachment(self, id)
}
@ -136,7 +100,7 @@ macro_rules! ordered_passes_renderpass {
}
#[inline]
fn subpass(&self, id: usize) -> Option<LayoutPassDescription> {
fn subpass_desc(&self, id: usize) -> Option<LayoutPassDescription> {
subpass(id)
}
@ -146,7 +110,7 @@ macro_rules! ordered_passes_renderpass {
}
#[inline]
fn dependency(&self, id: usize) -> Option<LayoutPassDependencyDescription> {
fn dependency_desc(&self, id: usize) -> Option<LayoutPassDependencyDescription> {
dependency(id)
}
}
@ -158,14 +122,6 @@ macro_rules! ordered_passes_renderpass {
}
}
unsafe impl RenderPassDescAttachmentsList<Vec<Arc<ImageViewAccess + Send + Sync>>> for CustomRenderPassDesc {
fn check_attachments_list(&self, list: Vec<Arc<ImageViewAccess + Send + Sync>>) -> Result<Box<AttachmentsList + Send + Sync>, FramebufferCreationError> {
// FIXME: correct safety checks
assert_eq!(list.len(), self.num_attachments());
Ok(Box::new(list) as Box<_>)
}
}
#[inline]
fn num_attachments() -> usize {
#![allow(unused_assignments)]
@ -233,19 +189,19 @@ macro_rules! ordered_passes_renderpass {
if id == cur_pass_num {
let mut depth = None;
$(
depth = Some(($depth_atch, Layout::DepthStencilAttachmentOptimal));
depth = Some(($depth_atch, ImageLayout::DepthStencilAttachmentOptimal));
)*
return Some(LayoutPassDescription {
color_attachments: vec![
$(
($color_atch, Layout::ColorAttachmentOptimal)
($color_atch, ImageLayout::ColorAttachmentOptimal)
),*
],
depth_stencil: depth,
input_attachments: vec![
$(
($input_atch, Layout::ShaderReadOnlyOptimal)
($input_atch, ImageLayout::ShaderReadOnlyOptimal)
),*
],
resolve_attachments: vec![],
@ -291,7 +247,7 @@ macro_rules! ordered_passes_renderpass {
/// Returns the initial and final layout of an attachment, given its num.
///
/// The value always correspond to the first and last usages of an attachment.
fn attachment_layouts(num: usize) -> (Layout, Layout) {
fn attachment_layouts(num: usize) -> (ImageLayout, ImageLayout) {
#![allow(unused_assignments)]
#![allow(unused_mut)]
#![allow(unused_variables)]
@ -309,40 +265,40 @@ macro_rules! ordered_passes_renderpass {
$(
if $depth_atch == num {
if initial_layout.is_none() {
initial_layout = Some(Layout::DepthStencilAttachmentOptimal);
initial_layout = Some(ImageLayout::DepthStencilAttachmentOptimal);
}
final_layout = Some(Layout::DepthStencilAttachmentOptimal);
final_layout = Some(ImageLayout::DepthStencilAttachmentOptimal);
}
)*
$(
if $color_atch == num {
if initial_layout.is_none() {
initial_layout = Some(Layout::ColorAttachmentOptimal);
initial_layout = Some(ImageLayout::ColorAttachmentOptimal);
}
final_layout = Some(Layout::ColorAttachmentOptimal);
final_layout = Some(ImageLayout::ColorAttachmentOptimal);
}
)*
$(
if $input_atch == num {
if initial_layout.is_none() {
initial_layout = Some(Layout::ShaderReadOnlyOptimal);
initial_layout = Some(ImageLayout::ShaderReadOnlyOptimal);
}
final_layout = Some(Layout::ShaderReadOnlyOptimal);
final_layout = Some(ImageLayout::ShaderReadOnlyOptimal);
}
)*
})*
$(if $atch_name == num {
// If the clear OP is Clear or DontCare, default to the Undefined layout.
if initial_layout == Some(Layout::DepthStencilAttachmentOptimal) ||
initial_layout == Some(Layout::ColorAttachmentOptimal)
if initial_layout == Some(ImageLayout::DepthStencilAttachmentOptimal) ||
initial_layout == Some(ImageLayout::ColorAttachmentOptimal)
{
if $crate::framebuffer::LoadOp::$load == $crate::framebuffer::LoadOp::Clear ||
$crate::framebuffer::LoadOp::$load == $crate::framebuffer::LoadOp::DontCare
{
initial_layout = Some(Layout::Undefined);
initial_layout = Some(ImageLayout::Undefined);
}
}
@ -360,178 +316,4 @@ macro_rules! ordered_passes_renderpass {
)*
}.build_render_pass($device)
});
([] __impl_attachments__ [] [] [] [$($params:ident),*]) => {
unsafe impl RenderPassDescAttachmentsList<AttachmentsStart> for CustomRenderPassDesc {
type List = ();
fn check_attachments_list(&self, attachments: AttachmentsStart) -> Result<(), FramebufferCreationError> {
Ok(()) // FIXME:
}
}
};
([] __impl_attachments__ [] [] [$next:ident $(, $rest:ident)*] [$first_param:ident, $($rest_params:ident),*]) => {
pub struct $next<$first_param> {
current: $first_param,
}
impl AttachmentsStart {
pub fn $next<$first_param>(self, next: $first_param) -> $next<$first_param> {
$next {
current: next,
}
}
}
impl<$first_param> $next<$first_param> {
fn check_attachments_list(self) -> Result<($first_param,), FramebufferCreationError> {
Ok((self.current,)) // FIXME: check attachment
}
}
ordered_passes_renderpass!{[] __impl_attachments__ [$next] [$first_param] [$($rest),*] [$($rest_params),*]}
};
([] __impl_attachments__ [$prev:ident] [$($prev_params:ident),*] [] [$($params:ident),*]) => {
unsafe impl<$($prev_params),*> RenderPassDescAttachmentsList<$prev<$($prev_params),*>> for CustomRenderPassDesc
where $($prev_params: ImageViewAccess + Send + Sync + 'static),*
{
//type List = ($($prev_params,)*);
fn check_attachments_list(&self, attachments: $prev<$($prev_params,)*>) -> Result<Box<AttachmentsList + Send + Sync>, FramebufferCreationError> {
Ok(Box::new(try!(attachments.check_attachments_list())))
// FIXME:
/*$({
if !l.$atch_name.identity_swizzle() {
return Err(FramebufferCreationError::AttachmentNotIdentitySwizzled);
}
})**/
}
}
};
([] __impl_attachments__ [$prev:ident] [$($prev_params:ident),*] [$next:ident $(, $rest:ident)*] [$first_param:ident, $($rest_params:ident),*]) => {
pub struct $next<$($prev_params,)* $first_param> {
prev: $prev<$($prev_params),*>,
current: $first_param,
}
impl<$($prev_params),*> $prev<$($prev_params),*> {
pub fn $next<$first_param>(self, next: $first_param) -> $next<$($prev_params,)* $first_param> {
$next {
prev: self,
current: next,
}
}
}
impl<$($prev_params,)* $first_param> $next<$($prev_params,)* $first_param> {
fn check_attachments_list(self) -> Result<($($prev_params,)* $first_param), FramebufferCreationError> {
let ($($prev_params,)*) = try!(self.prev.check_attachments_list());
// FIXME: check attachment
Ok(($($prev_params,)* self.current))
}
}
ordered_passes_renderpass!{[] __impl_attachments__ [$next] [$($prev_params,)* $first_param] [$($rest),*] [$($rest_params),*]}
};
([] __impl_clear_values__ [] [] [] [$($params:ident),*]) => {
unsafe impl RenderPassDescClearValues<ClearValuesStart> for CustomRenderPassDesc {
#[inline]
fn convert_clear_values(&self, values: ClearValuesStart) -> Box<Iterator<Item = ClearValue>> {
Box::new(iter::empty())
}
}
};
([] __impl_clear_values__ [] [] [$next:ident: Clear $(, $rest:ident: $rest_load:ident)*] [$first_param:ident, $($rest_params:ident),*]) => {
pub struct $next<$first_param> {
current: $first_param,
}
impl ClearValuesStart {
pub fn $next<$first_param>(self, next: $first_param) -> $next<$first_param> {
$next {
current: next,
}
}
}
impl<$first_param> $next<$first_param>
where $first_param: Into<ClearValue>
{
#[inline]
fn convert_clear_values(self) -> iter::Once<ClearValue> {
// FIXME: check format
iter::once(self.current.into())
}
}
ordered_passes_renderpass!{[] __impl_clear_values__ [$next] [$first_param] [$($rest: $rest_load),*] [$($rest_params),*]}
};
([] __impl_clear_values__ [] [] [$next:ident: $other:ident $(, $rest:ident: $rest_load:ident)*] [$first_param:ident, $($rest_params:ident),*]) => {
ordered_passes_renderpass!{[] __impl_clear_values__ [] [] [$($rest: $rest_load),*] [$first_param, $($rest_params),*]}
};
([] __impl_clear_values__ [$prev:ident] [$($prev_params:ident),*] [] [$($params:ident),*]) => {
unsafe impl<$($prev_params),*> RenderPassDescClearValues<$prev<$($prev_params),*>> for CustomRenderPassDesc
where $($prev_params: Into<ClearValue>),*
{
#[inline]
fn convert_clear_values(&self, values: $prev<$($prev_params,)*>) -> Box<Iterator<Item = ClearValue>> {
Box::new(values.convert_clear_values())
}
}
};
([] __impl_clear_values__ [$prev:ident] [$($prev_params:ident),*] [$next:ident: Clear $(, $rest:ident: $rest_load:ident)*] [$first_param:ident, $($rest_params:ident),*]) => {
pub struct $next<$($prev_params,)* $first_param> {
prev: $prev<$($prev_params,)*>,
current: $first_param,
}
impl<$($prev_params,)*> $prev<$($prev_params,)*> {
pub fn $next<$first_param>(self, next: $first_param) -> $next<$($prev_params,)* $first_param> {
$next {
prev: self,
current: next,
}
}
}
impl<$($prev_params,)* $first_param> $next<$($prev_params,)* $first_param>
where $first_param: Into<ClearValue>
$(, $prev_params: Into<ClearValue>)*
{
#[inline]
fn convert_clear_values(self) -> Box<Iterator<Item = ClearValue>> {
// TODO: subopptimal iterator
let prev = self.prev.convert_clear_values();
// FIXME: check format
Box::new(prev.chain(iter::once(self.current.into())))
}
}
ordered_passes_renderpass!{[] __impl_clear_values__ [$next] [$($prev_params,)* $first_param] [$($rest: $rest_load),*] [$($rest_params),*]}
};
([] __impl_clear_values__ [$prev:ident] [$($prev_params:ident),*] [$next:ident: $other:ident $(, $rest:ident: $rest_load:ident)*] [$first_param:ident, $($rest_params:ident),*]) => {
ordered_passes_renderpass!{[] __impl_clear_values__ [$prev] [$($prev_params,)*] [$($rest: $rest_load),*] [$first_param, $($rest_params),*]}
};
}

View File

@ -91,6 +91,8 @@
//!
pub use self::attachments_list::AttachmentsList;
pub use self::compat_atch::ensure_image_view_compatible;
pub use self::compat_atch::IncompatibleRenderPassAttachmentError;
pub use self::desc::LayoutAttachmentDescription;
pub use self::desc::LayoutPassDescription;
pub use self::desc::LayoutPassDependencyDescription;
@ -102,6 +104,7 @@ pub use self::desc::StoreOp;
pub use self::desc::LoadOp;
pub use self::empty::EmptySinglePassRenderPassDesc;
pub use self::framebuffer::Framebuffer;
pub use self::framebuffer::FramebufferBuilder;
pub use self::framebuffer::FramebufferCreationError;
pub use self::framebuffer::FramebufferSys;
pub use self::sys::RenderPass;
@ -110,7 +113,6 @@ pub use self::sys::RenderPassSys;
pub use self::traits::FramebufferAbstract;
pub use self::traits::RenderPassDescClearValues;
pub use self::traits::RenderPassCompatible;
pub use self::traits::RenderPassDescAttachmentsList;
pub use self::traits::RenderPassAbstract;
pub use self::traits::RenderPassSubpassInterface;
pub use self::traits::Subpass;
@ -118,6 +120,7 @@ pub use self::traits::Subpass;
#[macro_use]
mod macros;
mod attachments_list;
mod compat_atch;
mod desc;
mod empty;
mod framebuffer;

View File

@ -19,15 +19,12 @@ use smallvec::SmallVec;
use device::Device;
use device::DeviceOwned;
use format::ClearValue;
use framebuffer::AttachmentsList;
use framebuffer::EmptySinglePassRenderPassDesc;
use framebuffer::FramebufferCreationError;
use framebuffer::LayoutAttachmentDescription;
use framebuffer::LayoutPassDependencyDescription;
use framebuffer::LayoutPassDescription;
use framebuffer::LoadOp;
use framebuffer::RenderPassDescClearValues;
use framebuffer::RenderPassDescAttachmentsList;
use framebuffer::RenderPassDesc;
use framebuffer::RenderPassAbstract;
@ -73,12 +70,12 @@ impl<D> RenderPass<D> where D: RenderPassDesc {
// If the first use of an attachment in this render pass is as an input attachment, and
// the attachment is not also used as a color or depth/stencil attachment in the same
// subpass, then loadOp must not be VK_ATTACHMENT_LOAD_OP_CLEAR
debug_assert!(description.attachments().enumerate().all(|(atch_num, attachment)| {
debug_assert!(description.attachment_descs().enumerate().all(|(atch_num, attachment)| {
if attachment.load != LoadOp::Clear {
return true;
}
for p in description.subpasses() {
for p in description.subpass_descs() {
if p.color_attachments.iter().find(|&&(a, _)| a == atch_num).is_some() { return true; }
if let Some((a, _)) = p.depth_stencil { if a == atch_num { return true; } }
if p.input_attachments.iter().find(|&&(a, _)| a == atch_num).is_some() { return false; }
@ -87,7 +84,7 @@ impl<D> RenderPass<D> where D: RenderPassDesc {
true
}));
let attachments = description.attachments().map(|attachment| {
let attachments = description.attachment_descs().map(|attachment| {
debug_assert!(attachment.samples.is_power_of_two());
vk::AttachmentDescription {
@ -109,7 +106,7 @@ impl<D> RenderPass<D> where D: RenderPassDesc {
// This block allocates, for each pass, in order, all color attachment references, then all
// input attachment references, then all resolve attachment references, then the depth
// stencil attachment reference.
let attachment_references = description.subpasses().flat_map(|pass| {
let attachment_references = description.subpass_descs().flat_map(|pass| {
// Performing some validation with debug asserts.
debug_assert!(pass.resolve_attachments.is_empty() ||
pass.resolve_attachments.len() == pass.color_attachments.len());
@ -171,7 +168,7 @@ impl<D> RenderPass<D> where D: RenderPassDesc {
// Same as `attachment_references` but only for the preserve attachments.
// This is separate because attachment references are u32s and not `vkAttachmentReference`
// structs.
let preserve_attachments_references = description.subpasses().flat_map(|pass| {
let preserve_attachments_references = description.subpass_descs().flat_map(|pass| {
pass.preserve_attachments.into_iter().map(|offset| offset as u32)
}).collect::<SmallVec<[_; 16]>>();
@ -184,7 +181,7 @@ impl<D> RenderPass<D> where D: RenderPassDesc {
let mut preserve_ref_index = 0usize;
let mut out: SmallVec<[_; 16]> = SmallVec::new();
for pass in description.subpasses() {
for pass in description.subpass_descs() {
if pass.color_attachments.len() as u32 >
device.physical_device().limits().max_color_attachments()
{
@ -235,7 +232,7 @@ impl<D> RenderPass<D> where D: RenderPassDesc {
out
};
let dependencies = description.dependencies().map(|dependency| {
let dependencies = description.dependency_descs().map(|dependency| {
debug_assert!(dependency.source_subpass < passes.len());
debug_assert!(dependency.destination_subpass < passes.len());
@ -336,8 +333,8 @@ unsafe impl<D> RenderPassDesc for RenderPass<D> where D: RenderPassDesc {
}
#[inline]
fn attachment(&self, num: usize) -> Option<LayoutAttachmentDescription> {
self.desc.attachment(num)
fn attachment_desc(&self, num: usize) -> Option<LayoutAttachmentDescription> {
self.desc.attachment_desc(num)
}
#[inline]
@ -346,8 +343,8 @@ unsafe impl<D> RenderPassDesc for RenderPass<D> where D: RenderPassDesc {
}
#[inline]
fn subpass(&self, num: usize) -> Option<LayoutPassDescription> {
self.desc.subpass(num)
fn subpass_desc(&self, num: usize) -> Option<LayoutPassDescription> {
self.desc.subpass_desc(num)
}
#[inline]
@ -356,17 +353,8 @@ unsafe impl<D> RenderPassDesc for RenderPass<D> where D: RenderPassDesc {
}
#[inline]
fn dependency(&self, num: usize) -> Option<LayoutPassDependencyDescription> {
self.desc.dependency(num)
}
}
unsafe impl<A, D> RenderPassDescAttachmentsList<A> for RenderPass<D>
where D: RenderPassDescAttachmentsList<A>
{
#[inline]
fn check_attachments_list(&self, atch: A) -> Result<Box<AttachmentsList + Send + Sync>, FramebufferCreationError> {
self.desc.check_attachments_list(atch)
fn dependency_desc(&self, num: usize) -> Option<LayoutPassDependencyDescription> {
self.desc.dependency_desc(num)
}
}

View File

@ -9,8 +9,6 @@
use device::DeviceOwned;
use format::ClearValue;
use framebuffer::AttachmentsList;
use framebuffer::FramebufferCreationError;
use framebuffer::FramebufferSys;
use framebuffer::RenderPassDesc;
use framebuffer::RenderPassSys;
@ -108,40 +106,6 @@ unsafe impl<T> RenderPassAbstract for T where T: SafeDeref, T::Target: RenderPas
}
}
/// Extension trait for `RenderPassDesc`. Defines which types are allowed as an attachments list.
///
/// When the user creates a framebuffer, they need to pass a render pass object and a list of
/// attachments. In order for it to work, the render pass object must implement
/// `RenderPassDescAttachmentsList<A>` where `A` is the type of the list of attachments.
///
/// # Safety
///
/// This trait is unsafe because it's the job of the implementation to check whether the
/// attachments list is correct. What needs to be checked:
///
/// - That the attachments' format and samples count match the render pass layout.
/// - That the attachments have been created with the proper usage flags.
/// - That the attachments only expose one mipmap.
/// - That the attachments use identity components swizzling.
/// TODO: more stuff with aliasing
///
pub unsafe trait RenderPassDescAttachmentsList<A> {
/// Decodes a `A` into a list of attachments.
///
/// Checks that the attachments match the render pass, and returns a list. Returns an error if
/// one of the attachments is wrong.
fn check_attachments_list(&self, A) -> Result<Box<AttachmentsList + Send + Sync>, FramebufferCreationError>;
}
unsafe impl<A, T> RenderPassDescAttachmentsList<A> for T
where T: SafeDeref, T::Target: RenderPassDescAttachmentsList<A>
{
#[inline]
fn check_attachments_list(&self, atch: A) -> Result<Box<AttachmentsList + Send + Sync>, FramebufferCreationError> {
(**self).check_attachments_list(atch)
}
}
/// Extension trait for `RenderPassDesc`. Defines which types are allowed as a list of clear values.
///
/// When the user enters a render pass, they need to pass a list of clear values to apply to
@ -203,7 +167,7 @@ unsafe impl<A, B: ?Sized> RenderPassSubpassInterface<B> for A
where A: RenderPassDesc, B: ShaderInterfaceDef
{
fn is_compatible_with(&self, subpass: u32, other: &B) -> bool {
let pass_descr = match RenderPassDesc::subpasses(self).skip(subpass as usize).next() {
let pass_descr = match RenderPassDesc::subpass_descs(self).skip(subpass as usize).next() {
Some(s) => s,
None => return false,
};
@ -215,7 +179,7 @@ unsafe impl<A, B: ?Sized> RenderPassSubpassInterface<B> for A
None => return false,
};
let attachment_desc = (&self).attachments().skip(attachment_id).next().unwrap();
let attachment_desc = (&self).attachment_descs().skip(attachment_id).next().unwrap();
// FIXME: compare formats depending on the number of components and data type
/*if attachment_desc.format != element.format {

View File

@ -23,10 +23,10 @@ use image::Dimensions;
use image::ImageDimensions;
use image::ViewType;
use image::sys::ImageCreationError;
use image::sys::Layout;
use image::ImageLayout;
use image::ImageUsage;
use image::sys::UnsafeImage;
use image::sys::UnsafeImageView;
use image::sys::Usage;
use image::traits::ImageAccess;
use image::traits::ImageClearValue;
use image::traits::ImageContent;
@ -36,7 +36,8 @@ use image::traits::ImageView;
use memory::pool::AllocLayout;
use memory::pool::MemoryPool;
use memory::pool::MemoryPoolAlloc;
use memory::pool::StdMemoryPool;
use memory::pool::StdMemoryPoolAlloc;
use sync::AccessError;
use sync::Sharing;
/// ImageAccess whose purpose is to be used as a framebuffer attachment.
@ -69,7 +70,7 @@ use sync::Sharing;
///
// TODO: forbid reading transient images outside render passes?
#[derive(Debug)]
pub struct AttachmentImage<F, A = Arc<StdMemoryPool>> where A: MemoryPool {
pub struct AttachmentImage<F = Format, A = StdMemoryPoolAlloc> {
// Inner implementation.
image: UnsafeImage,
@ -77,14 +78,14 @@ pub struct AttachmentImage<F, A = Arc<StdMemoryPool>> where A: MemoryPool {
view: UnsafeImageView,
// Memory used to back the image.
memory: A::Alloc,
memory: A,
// Format.
format: F,
// Layout to use when the image is used as a framebuffer attachment.
// Must be either "depth-stencil optimal" or "color optimal".
attachment_layout: Layout,
attachment_layout: ImageLayout,
// Number of times this image is locked on the GPU side.
gpu_lock: AtomicUsize,
@ -96,16 +97,16 @@ impl<F> AttachmentImage<F> {
/// Returns an error if the dimensions are too large or if the backend doesn't support this
/// format as a framebuffer attachment.
#[inline]
pub fn new(device: &Arc<Device>, dimensions: [u32; 2], format: F)
pub fn new(device: Arc<Device>, dimensions: [u32; 2], format: F)
-> Result<Arc<AttachmentImage<F>>, ImageCreationError>
where F: FormatDesc
{
AttachmentImage::new_impl(device, dimensions, format, Usage::none())
AttachmentImage::new_impl(device, dimensions, format, ImageUsage::none())
}
/// Same as `new`, but lets you specify additional usages.
#[inline]
pub fn with_usage(device: &Arc<Device>, dimensions: [u32; 2], format: F, usage: Usage)
pub fn with_usage(device: Arc<Device>, dimensions: [u32; 2], format: F, usage: ImageUsage)
-> Result<Arc<AttachmentImage<F>>, ImageCreationError>
where F: FormatDesc
{
@ -117,19 +118,19 @@ impl<F> AttachmentImage<F> {
/// A transient image is special because its content is undefined outside of a render pass.
/// This means that the implementation has the possibility to not allocate any memory for it.
#[inline]
pub fn transient(device: &Arc<Device>, dimensions: [u32; 2], format: F)
pub fn transient(device: Arc<Device>, dimensions: [u32; 2], format: F)
-> Result<Arc<AttachmentImage<F>>, ImageCreationError>
where F: FormatDesc
{
let base_usage = Usage {
let base_usage = ImageUsage {
transient_attachment: true,
.. Usage::none()
.. ImageUsage::none()
};
AttachmentImage::new_impl(device, dimensions, format, base_usage)
}
fn new_impl(device: &Arc<Device>, dimensions: [u32; 2], format: F, base_usage: Usage)
fn new_impl(device: Arc<Device>, dimensions: [u32; 2], format: F, base_usage: ImageUsage)
-> Result<Arc<AttachmentImage<F>>, ImageCreationError>
where F: FormatDesc
{
@ -143,14 +144,14 @@ impl<F> AttachmentImage<F> {
_ => false
};
let usage = Usage {
let usage = ImageUsage {
color_attachment: !is_depth,
depth_stencil_attachment: is_depth,
.. base_usage
};
let (image, mem_reqs) = unsafe {
try!(UnsafeImage::new(device, &usage, format.format(),
try!(UnsafeImage::new(device.clone(), usage, format.format(),
ImageDimensions::Dim2d { width: dimensions[0], height: dimensions[1], array_layers: 1, cubemap_compatible: false },
1, 1, Sharing::Exclusive::<Empty<u32>>, false, false))
};
@ -164,7 +165,7 @@ impl<F> AttachmentImage<F> {
device_local.chain(any).next().unwrap()
};
let mem = try!(MemoryPool::alloc(&Device::standard_pool(device), mem_ty,
let mem = try!(MemoryPool::alloc(&Device::standard_pool(&device), mem_ty,
mem_reqs.size, mem_reqs.alignment, AllocLayout::Optimal));
debug_assert!((mem.offset() % mem_reqs.alignment) == 0);
unsafe { try!(image.bind_memory(mem.memory(), mem.offset())); }
@ -178,14 +179,14 @@ impl<F> AttachmentImage<F> {
view: view,
memory: mem,
format: format,
attachment_layout: if is_depth { Layout::DepthStencilAttachmentOptimal }
else { Layout::ColorAttachmentOptimal },
attachment_layout: if is_depth { ImageLayout::DepthStencilAttachmentOptimal }
else { ImageLayout::ColorAttachmentOptimal },
gpu_lock: AtomicUsize::new(0),
}))
}
}
impl<F, A> AttachmentImage<F, A> where A: MemoryPool {
impl<F, A> AttachmentImage<F, A> {
/// Returns the dimensions of the image.
#[inline]
pub fn dimensions(&self) -> [u32; 2] {
@ -195,13 +196,13 @@ impl<F, A> AttachmentImage<F, A> where A: MemoryPool {
}
/// GPU access to an attachment image.
pub struct AttachmentImageAccess<F, A> where A: MemoryPool {
pub struct AttachmentImageAccess<F, A> {
img: Arc<AttachmentImage<F, A>>,
// True if `try_gpu_lock` was already called on it.
already_locked: AtomicBool,
}
impl<F, A> Clone for AttachmentImageAccess<F, A> where A: MemoryPool {
impl<F, A> Clone for AttachmentImageAccess<F, A> {
#[inline]
fn clone(&self) -> AttachmentImageAccess<F, A> {
AttachmentImageAccess {
@ -212,8 +213,7 @@ impl<F, A> Clone for AttachmentImageAccess<F, A> where A: MemoryPool {
}
unsafe impl<F, A> ImageAccess for AttachmentImageAccess<F, A>
where F: 'static + Send + Sync,
A: MemoryPool
where F: 'static + Send + Sync
{
#[inline]
fn inner(&self) -> &UnsafeImage {
@ -221,12 +221,12 @@ unsafe impl<F, A> ImageAccess for AttachmentImageAccess<F, A>
}
#[inline]
fn initial_layout_requirement(&self) -> Layout {
fn initial_layout_requirement(&self) -> ImageLayout {
self.img.attachment_layout
}
#[inline]
fn final_layout_requirement(&self) -> Layout {
fn final_layout_requirement(&self) -> ImageLayout {
self.img.attachment_layout
}
@ -236,25 +236,30 @@ unsafe impl<F, A> ImageAccess for AttachmentImageAccess<F, A>
}
#[inline]
fn try_gpu_lock(&self, _: bool, _: &Queue) -> bool {
if self.already_locked.swap(true, Ordering::SeqCst) == true {
fn try_gpu_lock(&self, _: bool, _: &Queue) -> Result<(), AccessError> {
// FIXME: uncomment when it's working
// the problem is in the submit sync layer which locks framebuffer attachments and
// keeps them locked even after destruction
Ok(())
/*if self.already_locked.swap(true, Ordering::SeqCst) == true {
return false;
}
self.img.gpu_lock.compare_and_swap(0, 1, Ordering::SeqCst) == 0
self.img.gpu_lock.compare_and_swap(0, 1, Ordering::SeqCst) == 0*/
}
#[inline]
unsafe fn increase_gpu_lock(&self) {
debug_assert!(self.already_locked.load(Ordering::SeqCst));
// FIXME: uncomment when it's working
// the problem is in the submit sync layer which locks framebuffer attachments and
// keeps them locked even after destruction
/*debug_assert!(self.already_locked.load(Ordering::SeqCst));
let val = self.img.gpu_lock.fetch_add(1, Ordering::SeqCst);
debug_assert!(val >= 1);
debug_assert!(val >= 1);*/
}
}
impl<F, A> Drop for AttachmentImageAccess<F, A>
where A: MemoryPool
{
impl<F, A> Drop for AttachmentImageAccess<F, A> {
fn drop(&mut self) {
if self.already_locked.load(Ordering::SeqCst) {
let prev_val = self.img.gpu_lock.fetch_sub(1, Ordering::SeqCst);
@ -264,8 +269,7 @@ impl<F, A> Drop for AttachmentImageAccess<F, A>
}
unsafe impl<F, A> ImageClearValue<F::ClearValue> for AttachmentImageAccess<F, A>
where F: FormatDesc + 'static + Send + Sync,
A: MemoryPool
where F: FormatDesc + 'static + Send + Sync
{
#[inline]
fn decode(&self, value: F::ClearValue) -> Option<ClearValue> {
@ -274,8 +278,7 @@ unsafe impl<F, A> ImageClearValue<F::ClearValue> for AttachmentImageAccess<F, A>
}
unsafe impl<P, F, A> ImageContent<P> for AttachmentImageAccess<F, A>
where F: 'static + Send + Sync,
A: MemoryPool
where F: 'static + Send + Sync
{
#[inline]
fn matches_format(&self) -> bool {
@ -284,7 +287,7 @@ unsafe impl<P, F, A> ImageContent<P> for AttachmentImageAccess<F, A>
}
unsafe impl<F, A> Image for Arc<AttachmentImage<F, A>>
where F: 'static + Send + Sync, A: MemoryPool
where F: 'static + Send + Sync
{
type Access = AttachmentImageAccess<F, A>;
@ -313,7 +316,7 @@ unsafe impl<F, A> Image for Arc<AttachmentImage<F, A>>
}
unsafe impl<F, A> ImageView for Arc<AttachmentImage<F, A>>
where F: 'static + Send + Sync, A: MemoryPool
where F: 'static + Send + Sync
{
type Access = AttachmentImageAccess<F, A>;
@ -327,7 +330,7 @@ unsafe impl<F, A> ImageView for Arc<AttachmentImage<F, A>>
}
unsafe impl<F, A> ImageViewAccess for AttachmentImageAccess<F, A>
where F: 'static + Send + Sync, A: MemoryPool
where F: 'static + Send + Sync
{
#[inline]
fn parent(&self) -> &ImageAccess {
@ -346,23 +349,23 @@ unsafe impl<F, A> ImageViewAccess for AttachmentImageAccess<F, A>
}
#[inline]
fn descriptor_set_storage_image_layout(&self) -> Layout {
Layout::ShaderReadOnlyOptimal
fn descriptor_set_storage_image_layout(&self) -> ImageLayout {
ImageLayout::ShaderReadOnlyOptimal
}
#[inline]
fn descriptor_set_combined_image_sampler_layout(&self) -> Layout {
Layout::ShaderReadOnlyOptimal
fn descriptor_set_combined_image_sampler_layout(&self) -> ImageLayout {
ImageLayout::ShaderReadOnlyOptimal
}
#[inline]
fn descriptor_set_sampled_image_layout(&self) -> Layout {
Layout::ShaderReadOnlyOptimal
fn descriptor_set_sampled_image_layout(&self) -> ImageLayout {
ImageLayout::ShaderReadOnlyOptimal
}
#[inline]
fn descriptor_set_input_attachment_layout(&self) -> Layout {
Layout::ShaderReadOnlyOptimal
fn descriptor_set_input_attachment_layout(&self) -> ImageLayout {
ImageLayout::ShaderReadOnlyOptimal
}
#[inline]
@ -379,18 +382,18 @@ mod tests {
#[test]
fn create_regular() {
let (device, _) = gfx_dev_and_queue!();
let _img = AttachmentImage::new(&device, [32, 32], Format::R8G8B8A8Unorm).unwrap();
let _img = AttachmentImage::new(device, [32, 32], Format::R8G8B8A8Unorm).unwrap();
}
#[test]
fn create_transient() {
let (device, _) = gfx_dev_and_queue!();
let _img = AttachmentImage::transient(&device, [32, 32], Format::R8G8B8A8Unorm).unwrap();
let _img = AttachmentImage::transient(device, [32, 32], Format::R8G8B8A8Unorm).unwrap();
}
#[test]
fn d16_unorm_always_supported() {
let (device, _) = gfx_dev_and_queue!();
let _img = AttachmentImage::new(&device, [32, 32], Format::D16Unorm).unwrap();
let _img = AttachmentImage::new(device, [32, 32], Format::D16Unorm).unwrap();
}
}

View File

@ -18,10 +18,10 @@ use image::Dimensions;
use image::ImageDimensions;
use image::MipmapsCount;
use image::sys::ImageCreationError;
use image::sys::Layout;
use image::ImageLayout;
use image::ImageUsage;
use image::sys::UnsafeImage;
use image::sys::UnsafeImageView;
use image::sys::Usage;
use image::traits::ImageAccess;
use image::traits::ImageContent;
use image::traits::ImageViewAccess;
@ -32,6 +32,7 @@ use memory::pool::AllocLayout;
use memory::pool::MemoryPool;
use memory::pool::MemoryPoolAlloc;
use memory::pool::StdMemoryPool;
use sync::AccessError;
use sync::Sharing;
/// Image whose purpose is to be used for read-only purposes. You can write to the image once,
@ -50,7 +51,7 @@ impl<F> ImmutableImage<F> {
/// Builds a new immutable image.
// TODO: one mipmap is probably not a great default
#[inline]
pub fn new<'a, I>(device: &Arc<Device>, dimensions: Dimensions, format: F, queue_families: I)
pub fn new<'a, I>(device: Arc<Device>, dimensions: Dimensions, format: F, queue_families: I)
-> Result<Arc<ImmutableImage<F>>, ImageCreationError>
where F: FormatDesc, I: IntoIterator<Item = QueueFamily<'a>>
{
@ -58,16 +59,16 @@ impl<F> ImmutableImage<F> {
}
/// Builds a new immutable image with the given number of mipmaps.
pub fn with_mipmaps<'a, I, M>(device: &Arc<Device>, dimensions: Dimensions, format: F,
pub fn with_mipmaps<'a, I, M>(device: Arc<Device>, dimensions: Dimensions, format: F,
mipmaps: M, queue_families: I)
-> Result<Arc<ImmutableImage<F>>, ImageCreationError>
where F: FormatDesc, I: IntoIterator<Item = QueueFamily<'a>>, M: Into<MipmapsCount>
{
let usage = Usage {
let usage = ImageUsage {
transfer_source: true, // for blits
transfer_dest: true,
sampled: true,
.. Usage::none()
.. ImageUsage::none()
};
let queue_families = queue_families.into_iter().map(|f| f.id())
@ -80,7 +81,7 @@ impl<F> ImmutableImage<F> {
Sharing::Exclusive
};
try!(UnsafeImage::new(device, &usage, format.format(), dimensions.to_image_dimensions(),
try!(UnsafeImage::new(device.clone(), usage, format.format(), dimensions.to_image_dimensions(),
1, mipmaps, sharing, false, false))
};
@ -93,7 +94,7 @@ impl<F> ImmutableImage<F> {
device_local.chain(any).next().unwrap()
};
let mem = try!(MemoryPool::alloc(&Device::standard_pool(device), mem_ty,
let mem = try!(MemoryPool::alloc(&Device::standard_pool(&device), mem_ty,
mem_reqs.size, mem_reqs.alignment, AllocLayout::Optimal));
debug_assert!((mem.offset() % mem_reqs.alignment) == 0);
unsafe { try!(image.bind_memory(mem.memory(), mem.offset())); }
@ -173,13 +174,13 @@ unsafe impl<F, A> ImageAccess for ImmutableImage<F, A> where F: 'static + Send +
}
#[inline]
fn initial_layout_requirement(&self) -> Layout {
Layout::ShaderReadOnlyOptimal // TODO: ?
fn initial_layout_requirement(&self) -> ImageLayout {
ImageLayout::ShaderReadOnlyOptimal // TODO: ?
}
#[inline]
fn final_layout_requirement(&self) -> Layout {
Layout::ShaderReadOnlyOptimal // TODO: ?
fn final_layout_requirement(&self) -> ImageLayout {
ImageLayout::ShaderReadOnlyOptimal // TODO: ?
}
#[inline]
@ -188,8 +189,8 @@ unsafe impl<F, A> ImageAccess for ImmutableImage<F, A> where F: 'static + Send +
}
#[inline]
fn try_gpu_lock(&self, exclusive_access: bool, queue: &Queue) -> bool {
true // FIXME:
fn try_gpu_lock(&self, exclusive_access: bool, queue: &Queue) -> Result<(), AccessError> {
Ok(()) // FIXME:
}
#[inline]
@ -226,23 +227,23 @@ unsafe impl<F: 'static, A> ImageViewAccess for ImmutableImage<F, A>
}
#[inline]
fn descriptor_set_storage_image_layout(&self) -> Layout {
Layout::ShaderReadOnlyOptimal
fn descriptor_set_storage_image_layout(&self) -> ImageLayout {
ImageLayout::ShaderReadOnlyOptimal
}
#[inline]
fn descriptor_set_combined_image_sampler_layout(&self) -> Layout {
Layout::ShaderReadOnlyOptimal
fn descriptor_set_combined_image_sampler_layout(&self) -> ImageLayout {
ImageLayout::ShaderReadOnlyOptimal
}
#[inline]
fn descriptor_set_sampled_image_layout(&self) -> Layout {
Layout::ShaderReadOnlyOptimal
fn descriptor_set_sampled_image_layout(&self) -> ImageLayout {
ImageLayout::ShaderReadOnlyOptimal
}
#[inline]
fn descriptor_set_input_attachment_layout(&self) -> Layout {
Layout::ShaderReadOnlyOptimal
fn descriptor_set_input_attachment_layout(&self) -> ImageLayout {
ImageLayout::ShaderReadOnlyOptimal
}
#[inline]

View File

@ -0,0 +1,42 @@
// Copyright (c) 2016 The vulkano developers
// Licensed under the Apache License, Version 2.0
// <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT
// license <LICENSE-MIT or http://opensource.org/licenses/MIT>,
// at your option. All files in the project carrying such
// notice may not be copied, modified, or distributed except
// according to those terms.
use vk;
/// Layout of an image.
///
/// > **Note**: In vulkano, image layouts are mostly a low-level detail. You can ignore them,
/// > unless you use an unsafe function that states in its documentation that you must take care of
/// > an image's layout.
///
/// In the Vulkan API, each mipmap level of each array layer is in one of the layouts of this enum.
///
/// Unless you use some short of high-level shortcut function, an image always starts in either
/// the `Undefined` or the `Preinitialized` layout.
/// Before you can use an image for a given purpose, you must ensure that the image in question is
/// in the layout required for that purpose. For example if you want to write data to an image, you
/// must first transition the image to the `TransferDstOptimal` layout. The `General` layout can
/// also be used as a general-purpose fit-all layout, but using it will result in slower operations.
///
/// Transitionning between layouts can only be done through a GPU-side operation that is part of
/// a command buffer.
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
#[repr(u32)]
pub enum ImageLayout {
Undefined = vk::IMAGE_LAYOUT_UNDEFINED,
General = vk::IMAGE_LAYOUT_GENERAL,
ColorAttachmentOptimal = vk::IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
DepthStencilAttachmentOptimal = vk::IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL,
DepthStencilReadOnlyOptimal = vk::IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL,
ShaderReadOnlyOptimal = vk::IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
TransferSrcOptimal = vk::IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
TransferDstOptimal = vk::IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
Preinitialized = vk::IMAGE_LAYOUT_PREINITIALIZED,
PresentSrc = vk::IMAGE_LAYOUT_PRESENT_SRC_KHR,
}

View File

@ -48,22 +48,24 @@
pub use self::attachment::AttachmentImage;
pub use self::immutable::ImmutableImage;
pub use self::layout::ImageLayout;
pub use self::storage::StorageImage;
pub use self::swapchain::SwapchainImage;
pub use self::sys::ImageCreationError;
pub use self::sys::Layout;
pub use self::sys::Usage;
pub use self::traits::ImageAccess;
pub use self::traits::ImageViewAccess;
pub use self::traits::Image;
pub use self::traits::ImageView;
pub use self::usage::ImageUsage;
pub mod attachment; // TODO: make private
pub mod immutable; // TODO: make private
mod layout;
mod storage;
pub mod swapchain; // TODO: make private
pub mod sys;
pub mod traits;
mod usage;
/// Specifies how many mipmaps must be allocated.
///

View File

@ -22,10 +22,10 @@ use format::Format;
use image::Dimensions;
use image::ImageDimensions;
use image::sys::ImageCreationError;
use image::sys::Layout;
use image::ImageLayout;
use image::ImageUsage;
use image::sys::UnsafeImage;
use image::sys::UnsafeImageView;
use image::sys::Usage;
use image::traits::ImageAccess;
use image::traits::ImageClearValue;
use image::traits::ImageContent;
@ -37,6 +37,7 @@ use memory::pool::AllocLayout;
use memory::pool::MemoryPool;
use memory::pool::MemoryPoolAlloc;
use memory::pool::StdMemoryPool;
use sync::AccessError;
use sync::Sharing;
/// General-purpose image in device memory. Can be used for any usage, but will be slower than a
@ -67,7 +68,7 @@ pub struct StorageImage<F, A = Arc<StdMemoryPool>> where A: MemoryPool {
impl<F> StorageImage<F> {
/// Creates a new image with the given dimensions and format.
pub fn new<'a, I>(device: &Arc<Device>, dimensions: Dimensions, format: F, queue_families: I)
pub fn new<'a, I>(device: Arc<Device>, dimensions: Dimensions, format: F, queue_families: I)
-> Result<Arc<StorageImage<F>>, ImageCreationError>
where F: FormatDesc,
I: IntoIterator<Item = QueueFamily<'a>>
@ -80,7 +81,7 @@ impl<F> StorageImage<F> {
_ => false
};
let usage = Usage {
let usage = ImageUsage {
transfer_source: true,
transfer_dest: true,
sampled: true,
@ -101,7 +102,7 @@ impl<F> StorageImage<F> {
Sharing::Exclusive
};
try!(UnsafeImage::new(device, &usage, format.format(), dimensions.to_image_dimensions(),
try!(UnsafeImage::new(device.clone(), usage, format.format(), dimensions.to_image_dimensions(),
1, 1, Sharing::Exclusive::<Empty<u32>>, false, false))
};
@ -114,7 +115,7 @@ impl<F> StorageImage<F> {
device_local.chain(any).next().unwrap()
};
let mem = try!(MemoryPool::alloc(&Device::standard_pool(device), mem_ty,
let mem = try!(MemoryPool::alloc(&Device::standard_pool(&device), mem_ty,
mem_reqs.size, mem_reqs.alignment, AllocLayout::Optimal));
debug_assert!((mem.offset() % mem_reqs.alignment) == 0);
unsafe { try!(image.bind_memory(mem.memory(), mem.offset())); }
@ -190,13 +191,13 @@ unsafe impl<F, A> ImageAccess for StorageImage<F, A> where F: 'static + Send + S
}
#[inline]
fn initial_layout_requirement(&self) -> Layout {
Layout::General
fn initial_layout_requirement(&self) -> ImageLayout {
ImageLayout::General
}
#[inline]
fn final_layout_requirement(&self) -> Layout {
Layout::General
fn final_layout_requirement(&self) -> ImageLayout {
ImageLayout::General
}
#[inline]
@ -205,13 +206,13 @@ unsafe impl<F, A> ImageAccess for StorageImage<F, A> where F: 'static + Send + S
}
#[inline]
fn try_gpu_lock(&self, _: bool, _: &Queue) -> bool {
fn try_gpu_lock(&self, _: bool, _: &Queue) -> Result<(), AccessError> {
let val = self.gpu_lock.fetch_add(1, Ordering::SeqCst);
if val == 1 {
true
Ok(())
} else {
self.gpu_lock.fetch_sub(1, Ordering::SeqCst);
false
Err(AccessError::AlreadyInUse)
}
}
@ -259,23 +260,23 @@ unsafe impl<F, A> ImageViewAccess for StorageImage<F, A>
}
#[inline]
fn descriptor_set_storage_image_layout(&self) -> Layout {
Layout::General
fn descriptor_set_storage_image_layout(&self) -> ImageLayout {
ImageLayout::General
}
#[inline]
fn descriptor_set_combined_image_sampler_layout(&self) -> Layout {
Layout::General
fn descriptor_set_combined_image_sampler_layout(&self) -> ImageLayout {
ImageLayout::General
}
#[inline]
fn descriptor_set_sampled_image_layout(&self) -> Layout {
Layout::General
fn descriptor_set_sampled_image_layout(&self) -> ImageLayout {
ImageLayout::General
}
#[inline]
fn descriptor_set_input_attachment_layout(&self) -> Layout {
Layout::General
fn descriptor_set_input_attachment_layout(&self) -> ImageLayout {
ImageLayout::General
}
#[inline]
@ -293,7 +294,7 @@ mod tests {
#[test]
fn create() {
let (device, queue) = gfx_dev_and_queue!();
let _img = StorageImage::new(&device, Dimensions::Dim2d { width: 32, height: 32 },
let _img = StorageImage::new(device, Dimensions::Dim2d { width: 32, height: 32 },
Format::R8G8B8A8Unorm, Some(queue.family())).unwrap();
}
}

View File

@ -22,10 +22,11 @@ use image::traits::ImageContent;
use image::traits::ImageViewAccess;
use image::traits::Image;
use image::traits::ImageView;
use image::sys::Layout;
use image::ImageLayout;
use image::sys::UnsafeImage;
use image::sys::UnsafeImageView;
use swapchain::Swapchain;
use sync::AccessError;
use OomError;
@ -42,30 +43,27 @@ use OomError;
/// method on the swapchain), which will have the effect of showing the content of the image to
/// the screen. Once an image has been presented, it can no longer be used unless it is acquired
/// again.
// TODO: #[derive(Debug)] (needs https://github.com/aturon/crossbeam/issues/62)
// TODO: #[derive(Debug)]
pub struct SwapchainImage {
image: UnsafeImage,
view: UnsafeImageView,
format: Format,
swapchain: Arc<Swapchain>,
id: u32,
image_offset: usize,
view: UnsafeImageView,
}
impl SwapchainImage {
/// Builds a `SwapchainImage` from raw components.
///
/// This is an internal method that you shouldn't call.
pub unsafe fn from_raw(image: UnsafeImage, format: Format, swapchain: &Arc<Swapchain>, id: u32)
pub unsafe fn from_raw(swapchain: Arc<Swapchain>, id: usize)
-> Result<Arc<SwapchainImage>, OomError>
{
let image = swapchain.raw_image(id).unwrap();
let view = try!(UnsafeImageView::raw(&image, ViewType::Dim2d, 0 .. 1, 0 .. 1));
Ok(Arc::new(SwapchainImage {
image: image,
view: view,
format: format,
swapchain: swapchain.clone(),
id: id,
image_offset: id,
view: view,
}))
}
@ -74,49 +72,47 @@ impl SwapchainImage {
/// A `SwapchainImage` is always two-dimensional.
#[inline]
pub fn dimensions(&self) -> [u32; 2] {
let dims = self.image.dimensions();
let dims = self.my_image().dimensions();
[dims.width(), dims.height()]
}
/// Returns the format of the image.
// TODO: return `ColorFormat` or something like this instead, for stronger typing
#[inline]
pub fn format(&self) -> Format {
self.format
}
/// Returns the swapchain this image belongs to.
#[inline]
pub fn swapchain(&self) -> &Arc<Swapchain> {
&self.swapchain
}
#[inline]
fn my_image(&self) -> &UnsafeImage {
self.swapchain.raw_image(self.image_offset).unwrap()
}
}
unsafe impl ImageAccess for SwapchainImage {
#[inline]
fn inner(&self) -> &UnsafeImage {
&self.image
self.my_image()
}
#[inline]
fn initial_layout_requirement(&self) -> Layout {
Layout::PresentSrc
fn initial_layout_requirement(&self) -> ImageLayout {
ImageLayout::PresentSrc
}
#[inline]
fn final_layout_requirement(&self) -> Layout {
Layout::PresentSrc
fn final_layout_requirement(&self) -> ImageLayout {
ImageLayout::PresentSrc
}
#[inline]
fn conflict_key(&self, _: u32, _: u32, _: u32, _: u32) -> u64 {
self.image.key()
self.my_image().key()
}
#[inline]
fn try_gpu_lock(&self, _: bool, _: &Queue) -> bool {
fn try_gpu_lock(&self, _: bool, _: &Queue) -> Result<(), AccessError> {
// Swapchain image are only accessible after being acquired.
false
Err(AccessError::SwapchainImageAcquireOnly)
}
#[inline]
@ -128,7 +124,7 @@ unsafe impl ImageClearValue<<Format as FormatDesc>::ClearValue> for SwapchainIma
{
#[inline]
fn decode(&self, value: <Format as FormatDesc>::ClearValue) -> Option<ClearValue> {
Some(self.format.decode_clear_value(value))
Some(self.swapchain.format().decode_clear_value(value))
}
}
@ -147,8 +143,8 @@ unsafe impl ImageViewAccess for SwapchainImage {
#[inline]
fn dimensions(&self) -> Dimensions {
let dims = self.image.dimensions();
Dimensions::Dim2d { width: dims.width(), height: dims.height() }
let dims = self.swapchain.dimensions();
Dimensions::Dim2d { width: dims[0], height: dims[1] }
}
#[inline]
@ -157,23 +153,23 @@ unsafe impl ImageViewAccess for SwapchainImage {
}
#[inline]
fn descriptor_set_storage_image_layout(&self) -> Layout {
Layout::ShaderReadOnlyOptimal
fn descriptor_set_storage_image_layout(&self) -> ImageLayout {
ImageLayout::ShaderReadOnlyOptimal
}
#[inline]
fn descriptor_set_combined_image_sampler_layout(&self) -> Layout {
Layout::ShaderReadOnlyOptimal
fn descriptor_set_combined_image_sampler_layout(&self) -> ImageLayout {
ImageLayout::ShaderReadOnlyOptimal
}
#[inline]
fn descriptor_set_sampled_image_layout(&self) -> Layout {
Layout::ShaderReadOnlyOptimal
fn descriptor_set_sampled_image_layout(&self) -> ImageLayout {
ImageLayout::ShaderReadOnlyOptimal
}
#[inline]
fn descriptor_set_input_attachment_layout(&self) -> Layout {
Layout::ShaderReadOnlyOptimal
fn descriptor_set_input_attachment_layout(&self) -> ImageLayout {
ImageLayout::ShaderReadOnlyOptimal
}
#[inline]
@ -192,17 +188,17 @@ unsafe impl Image for SwapchainImage {
#[inline]
fn format(&self) -> Format {
self.image.format()
self.my_image().format()
}
#[inline]
fn samples(&self) -> u32 {
self.image.samples()
self.my_image().samples()
}
#[inline]
fn dimensions(&self) -> ImageDimensions {
self.image.dimensions()
self.my_image().dimensions()
}
}
@ -224,17 +220,17 @@ unsafe impl Image for Arc<SwapchainImage> {
#[inline]
fn format(&self) -> Format {
self.image.format()
self.my_image().format()
}
#[inline]
fn samples(&self) -> u32 {
self.image.samples()
self.my_image().samples()
}
#[inline]
fn dimensions(&self) -> ImageDimensions {
self.image.dimensions()
self.my_image().dimensions()
}
}

View File

@ -25,6 +25,7 @@ use device::Device;
use format::Format;
use format::FormatTy;
use image::ImageDimensions;
use image::ImageUsage;
use image::MipmapsCount;
use image::ViewType;
use memory::DeviceMemory;
@ -78,7 +79,7 @@ impl UnsafeImage {
/// - Panics if the number of samples is 0.
///
#[inline]
pub unsafe fn new<'a, Mi, I>(device: &Arc<Device>, usage: &Usage, format: Format,
pub unsafe fn new<'a, Mi, I>(device: Arc<Device>, usage: ImageUsage, format: Format,
dimensions: ImageDimensions, num_samples: u32, mipmaps: Mi,
sharing: Sharing<I>, linear_tiling: bool,
preinitialized_layout: bool)
@ -95,7 +96,7 @@ impl UnsafeImage {
}
// Non-templated version to avoid inlining and improve compile times.
unsafe fn new_impl(device: &Arc<Device>, usage: &Usage, format: Format,
unsafe fn new_impl(device: Arc<Device>, usage: ImageUsage, format: Format,
dimensions: ImageDimensions, num_samples: u32, mipmaps: MipmapsCount,
(sh_mode, sh_indices): (vk::SharingMode, SmallVec<[u32; 8]>),
linear_tiling: bool, preinitialized_layout: bool)
@ -153,7 +154,7 @@ impl UnsafeImage {
// If `transient_attachment` is true, then only `color_attachment`,
// `depth_stencil_attachment` and `input_attachment` can be true as well.
if usage.transient_attachment {
let u = Usage {
let u = ImageUsage {
transient_attachment: false,
color_attachment: false,
depth_stencil_attachment: false,
@ -161,7 +162,7 @@ impl UnsafeImage {
.. usage.clone()
};
if u != Usage::none() {
if u != ImageUsage::none() {
return Err(ImageCreationError::UnsupportedUsage);
}
}
@ -451,7 +452,7 @@ impl UnsafeImage {
/// Creates an image from a raw handle. The image won't be destroyed.
///
/// This function is for example used at the swapchain's initialization.
pub unsafe fn from_raw(device: &Arc<Device>, handle: u64, usage: u32, format: Format,
pub unsafe fn from_raw(device: Arc<Device>, handle: u64, usage: u32, format: Format,
dimensions: ImageDimensions, samples: u32, mipmaps: u32)
-> UnsafeImage
{
@ -972,135 +973,6 @@ impl Drop for UnsafeImageView {
}
}
/// Describes how an image is going to be used. This is **not** an optimization.
///
/// If you try to use an image in a way that you didn't declare, a panic will happen.
///
/// If `transient_attachment` is true, then only `color_attachment`, `depth_stencil_attachment`
/// and `input_attachment` can be true as well. The rest must be false or an error will be returned
/// when creating the image.
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub struct Usage {
/// Can be used a source for transfers. Includes blits.
pub transfer_source: bool,
/// Can be used a destination for transfers. Includes blits.
pub transfer_dest: bool,
/// Can be sampled from a shader.
pub sampled: bool,
/// Can be used as an image storage in a shader.
pub storage: bool,
/// Can be attached as a color attachment to a framebuffer.
pub color_attachment: bool,
/// Can be attached as a depth, stencil or depth-stencil attachment to a framebuffer.
pub depth_stencil_attachment: bool,
/// Indicates that this image will only ever be used as a temporary framebuffer attachment.
/// As soon as you leave a render pass, the content of transient images becomes undefined.
///
/// This is a hint to the Vulkan implementation that it may not need allocate any memory for
/// this image if the image can live entirely in some cache.
pub transient_attachment: bool,
/// Can be used as an input attachment. In other words, you can draw to it in a subpass then
/// read from it in a following pass.
pub input_attachment: bool,
}
impl Usage {
/// Builds a `Usage` with all values set to true. Note that using the returned value will
/// produce an error because of `transient_attachment` being true.
#[inline]
pub fn all() -> Usage {
Usage {
transfer_source: true,
transfer_dest: true,
sampled: true,
storage: true,
color_attachment: true,
depth_stencil_attachment: true,
transient_attachment: true,
input_attachment: true,
}
}
/// Builds a `Usage` with all values set to false. Useful as a default value.
///
/// # Example
///
/// ```rust
/// use vulkano::image::Usage as ImageUsage;
///
/// let _usage = ImageUsage {
/// transfer_dest: true,
/// sampled: true,
/// .. ImageUsage::none()
/// };
/// ```
#[inline]
pub fn none() -> Usage {
Usage {
transfer_source: false,
transfer_dest: false,
sampled: false,
storage: false,
color_attachment: false,
depth_stencil_attachment: false,
transient_attachment: false,
input_attachment: false,
}
}
#[doc(hidden)]
#[inline]
pub fn to_usage_bits(&self) -> vk::ImageUsageFlagBits {
let mut result = 0;
if self.transfer_source { result |= vk::IMAGE_USAGE_TRANSFER_SRC_BIT; }
if self.transfer_dest { result |= vk::IMAGE_USAGE_TRANSFER_DST_BIT; }
if self.sampled { result |= vk::IMAGE_USAGE_SAMPLED_BIT; }
if self.storage { result |= vk::IMAGE_USAGE_STORAGE_BIT; }
if self.color_attachment { result |= vk::IMAGE_USAGE_COLOR_ATTACHMENT_BIT; }
if self.depth_stencil_attachment { result |= vk::IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT; }
if self.transient_attachment { result |= vk::IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT; }
if self.input_attachment { result |= vk::IMAGE_USAGE_INPUT_ATTACHMENT_BIT; }
result
}
#[inline]
#[doc(hidden)]
pub fn from_bits(val: u32) -> Usage {
Usage {
transfer_source: (val & vk::IMAGE_USAGE_TRANSFER_SRC_BIT) != 0,
transfer_dest: (val & vk::IMAGE_USAGE_TRANSFER_DST_BIT) != 0,
sampled: (val & vk::IMAGE_USAGE_SAMPLED_BIT) != 0,
storage: (val & vk::IMAGE_USAGE_STORAGE_BIT) != 0,
color_attachment: (val & vk::IMAGE_USAGE_COLOR_ATTACHMENT_BIT) != 0,
depth_stencil_attachment: (val & vk::IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) != 0,
transient_attachment: (val & vk::IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT) != 0,
input_attachment: (val & vk::IMAGE_USAGE_INPUT_ATTACHMENT_BIT) != 0,
}
}
}
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
#[repr(u32)]
pub enum Layout {
Undefined = vk::IMAGE_LAYOUT_UNDEFINED,
General = vk::IMAGE_LAYOUT_GENERAL,
ColorAttachmentOptimal = vk::IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
DepthStencilAttachmentOptimal = vk::IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL,
DepthStencilReadOnlyOptimal = vk::IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL,
ShaderReadOnlyOptimal = vk::IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
TransferSrcOptimal = vk::IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
TransferDstOptimal = vk::IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
Preinitialized = vk::IMAGE_LAYOUT_PREINITIALIZED,
PresentSrc = vk::IMAGE_LAYOUT_PRESENT_SRC_KHR,
}
#[cfg(test)]
mod tests {
use std::iter::Empty;
@ -1108,7 +980,7 @@ mod tests {
use super::ImageCreationError;
use super::UnsafeImage;
use super::Usage;
use super::ImageUsage;
use image::ImageDimensions;
use format::Format;
@ -1118,13 +990,13 @@ mod tests {
fn create_sampled() {
let (device, _) = gfx_dev_and_queue!();
let usage = Usage {
let usage = ImageUsage {
sampled: true,
.. Usage::none()
.. ImageUsage::none()
};
let (_img, _) = unsafe {
UnsafeImage::new(&device, &usage, Format::R8G8B8A8Unorm,
UnsafeImage::new(device, usage, Format::R8G8B8A8Unorm,
ImageDimensions::Dim2d { width: 32, height: 32, array_layers: 1,
cubemap_compatible: false }, 1, 1,
Sharing::Exclusive::<Empty<_>>, false, false)
@ -1135,14 +1007,14 @@ mod tests {
fn create_transient() {
let (device, _) = gfx_dev_and_queue!();
let usage = Usage {
let usage = ImageUsage {
transient_attachment: true,
color_attachment: true,
.. Usage::none()
.. ImageUsage::none()
};
let (_img, _) = unsafe {
UnsafeImage::new(&device, &usage, Format::R8G8B8A8Unorm,
UnsafeImage::new(device, usage, Format::R8G8B8A8Unorm,
ImageDimensions::Dim2d { width: 32, height: 32, array_layers: 1,
cubemap_compatible: false }, 1, 1,
Sharing::Exclusive::<Empty<_>>, false, false)
@ -1153,13 +1025,13 @@ mod tests {
fn zero_sample() {
let (device, _) = gfx_dev_and_queue!();
let usage = Usage {
let usage = ImageUsage {
sampled: true,
.. Usage::none()
.. ImageUsage::none()
};
let res = unsafe {
UnsafeImage::new(&device, &usage, Format::R8G8B8A8Unorm,
UnsafeImage::new(device, usage, Format::R8G8B8A8Unorm,
ImageDimensions::Dim2d { width: 32, height: 32, array_layers: 1,
cubemap_compatible: false }, 0, 1,
Sharing::Exclusive::<Empty<_>>, false, false)
@ -1175,13 +1047,13 @@ mod tests {
fn non_po2_sample() {
let (device, _) = gfx_dev_and_queue!();
let usage = Usage {
let usage = ImageUsage {
sampled: true,
.. Usage::none()
.. ImageUsage::none()
};
let res = unsafe {
UnsafeImage::new(&device, &usage, Format::R8G8B8A8Unorm,
UnsafeImage::new(device, usage, Format::R8G8B8A8Unorm,
ImageDimensions::Dim2d { width: 32, height: 32, array_layers: 1,
cubemap_compatible: false }, 5, 1,
Sharing::Exclusive::<Empty<_>>, false, false)
@ -1197,13 +1069,13 @@ mod tests {
fn zero_mipmap() {
let (device, _) = gfx_dev_and_queue!();
let usage = Usage {
let usage = ImageUsage {
sampled: true,
.. Usage::none()
.. ImageUsage::none()
};
let res = unsafe {
UnsafeImage::new(&device, &usage, Format::R8G8B8A8Unorm,
UnsafeImage::new(device, usage, Format::R8G8B8A8Unorm,
ImageDimensions::Dim2d { width: 32, height: 32, array_layers: 1,
cubemap_compatible: false }, 1, 0,
Sharing::Exclusive::<Empty<_>>, false, false)
@ -1220,13 +1092,13 @@ mod tests {
fn mipmaps_too_high() {
let (device, _) = gfx_dev_and_queue!();
let usage = Usage {
let usage = ImageUsage {
sampled: true,
.. Usage::none()
.. ImageUsage::none()
};
let res = unsafe {
UnsafeImage::new(&device, &usage, Format::R8G8B8A8Unorm,
UnsafeImage::new(device, usage, Format::R8G8B8A8Unorm,
ImageDimensions::Dim2d { width: 32, height: 32, array_layers: 1,
cubemap_compatible: false }, 1, u32::MAX,
Sharing::Exclusive::<Empty<_>>, false, false)
@ -1245,13 +1117,13 @@ mod tests {
fn shader_storage_image_multisample() {
let (device, _) = gfx_dev_and_queue!();
let usage = Usage {
let usage = ImageUsage {
storage: true,
.. Usage::none()
.. ImageUsage::none()
};
let res = unsafe {
UnsafeImage::new(&device, &usage, Format::R8G8B8A8Unorm,
UnsafeImage::new(device, usage, Format::R8G8B8A8Unorm,
ImageDimensions::Dim2d { width: 32, height: 32, array_layers: 1,
cubemap_compatible: false }, 2, 1,
Sharing::Exclusive::<Empty<_>>, false, false)
@ -1268,13 +1140,13 @@ mod tests {
fn compressed_not_color_attachment() {
let (device, _) = gfx_dev_and_queue!();
let usage = Usage {
let usage = ImageUsage {
color_attachment: true,
.. Usage::none()
.. ImageUsage::none()
};
let res = unsafe {
UnsafeImage::new(&device, &usage, Format::ASTC_5x4UnormBlock,
UnsafeImage::new(device, usage, Format::ASTC_5x4UnormBlock,
ImageDimensions::Dim2d { width: 32, height: 32, array_layers: 1,
cubemap_compatible: false }, 1, u32::MAX,
Sharing::Exclusive::<Empty<_>>, false, false)
@ -1291,14 +1163,14 @@ mod tests {
fn transient_forbidden_with_some_usages() {
let (device, _) = gfx_dev_and_queue!();
let usage = Usage {
let usage = ImageUsage {
transient_attachment: true,
sampled: true,
.. Usage::none()
.. ImageUsage::none()
};
let res = unsafe {
UnsafeImage::new(&device, &usage, Format::R8G8B8A8Unorm,
UnsafeImage::new(device, usage, Format::R8G8B8A8Unorm,
ImageDimensions::Dim2d { width: 32, height: 32, array_layers: 1,
cubemap_compatible: false }, 1, 1,
Sharing::Exclusive::<Empty<_>>, false, false)
@ -1314,13 +1186,13 @@ mod tests {
fn cubecompatible_dims_mismatch() {
let (device, _) = gfx_dev_and_queue!();
let usage = Usage {
let usage = ImageUsage {
sampled: true,
.. Usage::none()
.. ImageUsage::none()
};
let res = unsafe {
UnsafeImage::new(&device, &usage, Format::R8G8B8A8Unorm,
UnsafeImage::new(device, usage, Format::R8G8B8A8Unorm,
ImageDimensions::Dim2d { width: 32, height: 64, array_layers: 1,
cubemap_compatible: true }, 1, 1,
Sharing::Exclusive::<Empty<_>>, false, false)

View File

@ -19,10 +19,11 @@ use format::PossibleStencilFormatDesc;
use format::PossibleDepthStencilFormatDesc;
use image::Dimensions;
use image::ImageDimensions;
use image::sys::Layout;
use image::ImageLayout;
use image::sys::UnsafeImage;
use image::sys::UnsafeImageView;
use sampler::Sampler;
use sync::AccessError;
use SafeDeref;
use VulkanObject;
@ -110,10 +111,10 @@ pub unsafe trait ImageAccess {
}
/// Returns the layout that the image has when it is first used in a primary command buffer.
fn initial_layout_requirement(&self) -> Layout;
fn initial_layout_requirement(&self) -> ImageLayout;
/// Returns the layout that the image must be returned to before the end of the command buffer.
fn final_layout_requirement(&self) -> Layout;
fn final_layout_requirement(&self) -> ImageLayout;
/// Wraps around this `ImageAccess` and returns an identical `ImageAccess` but whose initial
/// layout requirement is either `Undefined` or `Preinitialized`.
@ -208,7 +209,7 @@ pub unsafe trait ImageAccess {
/// The only way to know that the GPU has stopped accessing a queue is when the image object
/// gets destroyed. Therefore you are encouraged to use temporary objects or handles (similar
/// to a lock) in order to represent a GPU access.
fn try_gpu_lock(&self, exclusive_access: bool, queue: &Queue) -> bool;
fn try_gpu_lock(&self, exclusive_access: bool, queue: &Queue) -> Result<(), AccessError>;
/// Locks the resource for usage on the GPU. Supposes that the resource is already locked, and
/// simply increases the lock by one.
@ -224,12 +225,12 @@ unsafe impl<T> ImageAccess for T where T: SafeDeref, T::Target: ImageAccess {
}
#[inline]
fn initial_layout_requirement(&self) -> Layout {
fn initial_layout_requirement(&self) -> ImageLayout {
(**self).initial_layout_requirement()
}
#[inline]
fn final_layout_requirement(&self) -> Layout {
fn final_layout_requirement(&self) -> ImageLayout {
(**self).final_layout_requirement()
}
@ -241,7 +242,7 @@ unsafe impl<T> ImageAccess for T where T: SafeDeref, T::Target: ImageAccess {
}
#[inline]
fn try_gpu_lock(&self, exclusive_access: bool, queue: &Queue) -> bool {
fn try_gpu_lock(&self, exclusive_access: bool, queue: &Queue) -> Result<(), AccessError> {
(**self).try_gpu_lock(exclusive_access, queue)
}
@ -268,16 +269,16 @@ unsafe impl<I> ImageAccess for ImageAccessFromUndefinedLayout<I>
}
#[inline]
fn initial_layout_requirement(&self) -> Layout {
fn initial_layout_requirement(&self) -> ImageLayout {
if self.preinitialized {
Layout::Preinitialized
ImageLayout::Preinitialized
} else {
Layout::Undefined
ImageLayout::Undefined
}
}
#[inline]
fn final_layout_requirement(&self) -> Layout {
fn final_layout_requirement(&self) -> ImageLayout {
self.image.final_layout_requirement()
}
@ -289,7 +290,7 @@ unsafe impl<I> ImageAccess for ImageAccessFromUndefinedLayout<I>
}
#[inline]
fn try_gpu_lock(&self, exclusive_access: bool, queue: &Queue) -> bool {
fn try_gpu_lock(&self, exclusive_access: bool, queue: &Queue) -> Result<(), AccessError> {
self.image.try_gpu_lock(exclusive_access, queue)
}
@ -342,13 +343,13 @@ pub unsafe trait ImageViewAccess {
}
/// Returns the image layout to use in a descriptor with the given subresource.
fn descriptor_set_storage_image_layout(&self) -> Layout;
fn descriptor_set_storage_image_layout(&self) -> ImageLayout;
/// Returns the image layout to use in a descriptor with the given subresource.
fn descriptor_set_combined_image_sampler_layout(&self) -> Layout;
fn descriptor_set_combined_image_sampler_layout(&self) -> ImageLayout;
/// Returns the image layout to use in a descriptor with the given subresource.
fn descriptor_set_sampled_image_layout(&self) -> Layout;
fn descriptor_set_sampled_image_layout(&self) -> ImageLayout;
/// Returns the image layout to use in a descriptor with the given subresource.
fn descriptor_set_input_attachment_layout(&self) -> Layout;
fn descriptor_set_input_attachment_layout(&self) -> ImageLayout;
/// Returns true if the view doesn't use components swizzling.
///
@ -383,19 +384,19 @@ unsafe impl<T> ImageViewAccess for T where T: SafeDeref, T::Target: ImageViewAcc
}
#[inline]
fn descriptor_set_storage_image_layout(&self) -> Layout {
fn descriptor_set_storage_image_layout(&self) -> ImageLayout {
(**self).descriptor_set_storage_image_layout()
}
#[inline]
fn descriptor_set_combined_image_sampler_layout(&self) -> Layout {
fn descriptor_set_combined_image_sampler_layout(&self) -> ImageLayout {
(**self).descriptor_set_combined_image_sampler_layout()
}
#[inline]
fn descriptor_set_sampled_image_layout(&self) -> Layout {
fn descriptor_set_sampled_image_layout(&self) -> ImageLayout {
(**self).descriptor_set_sampled_image_layout()
}
#[inline]
fn descriptor_set_input_attachment_layout(&self) -> Layout {
fn descriptor_set_input_attachment_layout(&self) -> ImageLayout {
(**self).descriptor_set_input_attachment_layout()
}
@ -411,5 +412,5 @@ unsafe impl<T> ImageViewAccess for T where T: SafeDeref, T::Target: ImageViewAcc
}
pub unsafe trait AttachmentImageView: ImageViewAccess {
fn accept(&self, initial_layout: Layout, final_layout: Layout) -> bool;
fn accept(&self, initial_layout: ImageLayout, final_layout: ImageLayout) -> bool;
}

145
vulkano/src/image/usage.rs Normal file
View File

@ -0,0 +1,145 @@
// Copyright (c) 2016 The vulkano developers
// Licensed under the Apache License, Version 2.0
// <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT
// license <LICENSE-MIT or http://opensource.org/licenses/MIT>,
// 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::ops::BitOr;
use vk;
/// Describes how an image is going to be used. This is **not** an optimization.
///
/// If you try to use an image in a way that you didn't declare, a panic will happen.
///
/// If `transient_attachment` is true, then only `color_attachment`, `depth_stencil_attachment`
/// and `input_attachment` can be true as well. The rest must be false or an error will be returned
/// when creating the image.
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub struct ImageUsage {
/// Can be used a source for transfers. Includes blits.
pub transfer_source: bool,
/// Can be used a destination for transfers. Includes blits.
pub transfer_dest: bool,
/// Can be sampled from a shader.
pub sampled: bool,
/// Can be used as an image storage in a shader.
pub storage: bool,
/// Can be attached as a color attachment to a framebuffer.
pub color_attachment: bool,
/// Can be attached as a depth, stencil or depth-stencil attachment to a framebuffer.
pub depth_stencil_attachment: bool,
/// Indicates that this image will only ever be used as a temporary framebuffer attachment.
/// As soon as you leave a render pass, the content of transient images becomes undefined.
///
/// This is a hint to the Vulkan implementation that it may not need allocate any memory for
/// this image if the image can live entirely in some cache.
pub transient_attachment: bool,
/// Can be used as an input attachment. In other words, you can draw to it in a subpass then
/// read from it in a following pass.
pub input_attachment: bool,
}
impl ImageUsage {
/// Builds a `ImageUsage` with all values set to true. Note that using the returned value will
/// produce an error because of `transient_attachment` being true.
#[inline]
pub fn all() -> ImageUsage {
ImageUsage {
transfer_source: true,
transfer_dest: true,
sampled: true,
storage: true,
color_attachment: true,
depth_stencil_attachment: true,
transient_attachment: true,
input_attachment: true,
}
}
/// Builds a `ImageUsage` with all values set to false. Useful as a default value.
///
/// # Example
///
/// ```rust
/// use vulkano::image::ImageUsage as ImageUsage;
///
/// let _usage = ImageUsage {
/// transfer_dest: true,
/// sampled: true,
/// .. ImageUsage::none()
/// };
/// ```
#[inline]
pub fn none() -> ImageUsage {
ImageUsage {
transfer_source: false,
transfer_dest: false,
sampled: false,
storage: false,
color_attachment: false,
depth_stencil_attachment: false,
transient_attachment: false,
input_attachment: false,
}
}
// TODO: these functions shouldn't be public-hidden
#[doc(hidden)]
#[inline]
pub fn to_usage_bits(&self) -> vk::ImageUsageFlagBits {
let mut result = 0;
if self.transfer_source { result |= vk::IMAGE_USAGE_TRANSFER_SRC_BIT; }
if self.transfer_dest { result |= vk::IMAGE_USAGE_TRANSFER_DST_BIT; }
if self.sampled { result |= vk::IMAGE_USAGE_SAMPLED_BIT; }
if self.storage { result |= vk::IMAGE_USAGE_STORAGE_BIT; }
if self.color_attachment { result |= vk::IMAGE_USAGE_COLOR_ATTACHMENT_BIT; }
if self.depth_stencil_attachment { result |= vk::IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT; }
if self.transient_attachment { result |= vk::IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT; }
if self.input_attachment { result |= vk::IMAGE_USAGE_INPUT_ATTACHMENT_BIT; }
result
}
// TODO: these functions shouldn't be public-hidden
#[inline]
#[doc(hidden)]
pub fn from_bits(val: u32) -> ImageUsage {
ImageUsage {
transfer_source: (val & vk::IMAGE_USAGE_TRANSFER_SRC_BIT) != 0,
transfer_dest: (val & vk::IMAGE_USAGE_TRANSFER_DST_BIT) != 0,
sampled: (val & vk::IMAGE_USAGE_SAMPLED_BIT) != 0,
storage: (val & vk::IMAGE_USAGE_STORAGE_BIT) != 0,
color_attachment: (val & vk::IMAGE_USAGE_COLOR_ATTACHMENT_BIT) != 0,
depth_stencil_attachment: (val & vk::IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) != 0,
transient_attachment: (val & vk::IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT) != 0,
input_attachment: (val & vk::IMAGE_USAGE_INPUT_ATTACHMENT_BIT) != 0,
}
}
}
impl BitOr for ImageUsage {
type Output = Self;
#[inline]
fn bitor(self, rhs: Self) -> Self {
ImageUsage {
transfer_source: self.transfer_source || rhs.transfer_source,
transfer_dest: self.transfer_dest || rhs.transfer_dest,
sampled: self.sampled || rhs.sampled,
storage: self.storage || rhs.storage,
color_attachment: self.color_attachment || rhs.color_attachment,
depth_stencil_attachment: self.depth_stencil_attachment || rhs.depth_stencil_attachment,
transient_attachment: self.transient_attachment || rhs.transient_attachment,
input_attachment: self.input_attachment || rhs.input_attachment,
}
}
}

View File

@ -417,6 +417,7 @@ mod tests {
}
#[test]
#[ignore] // TODO: test fails for now on Mesa+Intel
fn oom_multi() {
let (device, _) = gfx_dev_and_queue!();
let mem_ty = device.physical_device().memory_types().filter(|m| !m.is_lazily_allocated())

View File

@ -36,7 +36,7 @@ impl StdHostVisibleMemoryTypePool {
/// - Panics if the `device` and `memory_type` don't belong to the same physical device.
///
#[inline]
pub fn new(device: &Arc<Device>, memory_type: MemoryType)
pub fn new(device: Arc<Device>, memory_type: MemoryType)
-> Arc<StdHostVisibleMemoryTypePool>
{
assert_eq!(&**device.physical_device().instance() as *const Instance,

View File

@ -35,7 +35,7 @@ impl StdNonHostVisibleMemoryTypePool {
/// - Panics if the `device` and `memory_type` don't belong to the same physical device.
///
#[inline]
pub fn new(device: &Arc<Device>, memory_type: MemoryType)
pub fn new(device: Arc<Device>, memory_type: MemoryType)
-> Arc<StdNonHostVisibleMemoryTypePool>
{
assert_eq!(&**device.physical_device().instance() as *const Instance,

View File

@ -38,7 +38,7 @@ pub struct StdMemoryPool {
impl StdMemoryPool {
/// Creates a new pool.
#[inline]
pub fn new(device: &Arc<Device>) -> Arc<StdMemoryPool> {
pub fn new(device: Arc<Device>) -> Arc<StdMemoryPool> {
let cap = device.physical_device().memory_types().len();
let hasher = BuildHasherDefault::<FnvHasher>::default();
@ -76,14 +76,14 @@ unsafe impl MemoryPool for Arc<StdMemoryPool> {
Entry::Vacant(entry) => {
match memory_type.is_host_visible() {
true => {
let pool = StdHostVisibleMemoryTypePool::new(&self.device, memory_type);
let pool = StdHostVisibleMemoryTypePool::new(self.device.clone(), memory_type);
entry.insert(Pool::HostVisible(pool.clone()));
let alloc = try!(StdHostVisibleMemoryTypePool::alloc(&pool, size, alignment));
let inner = StdMemoryPoolAllocInner::HostVisible(alloc);
Ok(StdMemoryPoolAlloc { inner: inner, pool: self.clone() })
},
false => {
let pool = StdNonHostVisibleMemoryTypePool::new(&self.device, memory_type);
let pool = StdNonHostVisibleMemoryTypePool::new(self.device.clone(), memory_type);
entry.insert(Pool::NonHostVisible(pool.clone()));
let alloc = try!(StdNonHostVisibleMemoryTypePool::alloc(&pool, size, alignment));
let inner = StdMemoryPoolAllocInner::NonHostVisible(alloc);

View File

@ -76,13 +76,13 @@ impl PipelineCache {
///
/// let cache = if let Some(data) = data {
/// // This is unsafe because there is no way to be sure that the file contains valid data.
/// unsafe { PipelineCache::with_data(&device, &data).unwrap() }
/// unsafe { PipelineCache::with_data(device.clone(), &data).unwrap() }
/// } else {
/// PipelineCache::empty(&device).unwrap()
/// PipelineCache::empty(device.clone()).unwrap()
/// };
/// ```
#[inline]
pub unsafe fn with_data(device: &Arc<Device>, initial_data: &[u8])
pub unsafe fn with_data(device: Arc<Device>, initial_data: &[u8])
-> Result<Arc<PipelineCache>, OomError>
{
PipelineCache::new_impl(device, Some(initial_data))
@ -97,15 +97,15 @@ impl PipelineCache {
/// # use vulkano::device::Device;
/// use vulkano::pipeline::cache::PipelineCache;
/// # let device: Arc<Device> = return;
/// let cache = PipelineCache::empty(&device).unwrap();
/// let cache = PipelineCache::empty(device.clone()).unwrap();
/// ```
#[inline]
pub fn empty(device: &Arc<Device>) -> Result<Arc<PipelineCache>, OomError> {
pub fn empty(device: Arc<Device>) -> Result<Arc<PipelineCache>, OomError> {
unsafe { PipelineCache::new_impl(device, None) }
}
// Actual implementation of the constructor.
unsafe fn new_impl(device: &Arc<Device>, initial_data: Option<&[u8]>)
unsafe fn new_impl(device: Arc<Device>, initial_data: Option<&[u8]>)
-> Result<Arc<PipelineCache>, OomError>
{
let vk = device.pointers();
@ -232,7 +232,7 @@ mod tests {
#[should_panic]
fn merge_self_forbidden() {
let (device, queue) = gfx_dev_and_queue!();
let pipeline = PipelineCache::empty(&device).unwrap();
let pipeline = PipelineCache::empty(device).unwrap();
pipeline.merge(&[&pipeline]).unwrap();
}
}

View File

@ -56,7 +56,7 @@ struct Inner {
impl ComputePipeline<()> {
/// Builds a new `ComputePipeline`.
pub fn new<Css, Csl>(device: &Arc<Device>, shader: &ComputeShaderEntryPoint<Css, Csl>,
pub fn new<Css, Csl>(device: Arc<Device>, shader: &ComputeShaderEntryPoint<Css, Csl>,
specialization: &Css)
-> Result<ComputePipeline<PipelineLayout<Csl>>, ComputePipelineCreationError>
where Csl: PipelineLayoutDescNames + Clone,
@ -64,7 +64,7 @@ impl ComputePipeline<()> {
{
let vk = device.pointers();
let pipeline_layout = shader.layout().clone().build(device).unwrap(); // TODO: error
let pipeline_layout = shader.layout().clone().build(device.clone()).unwrap(); // TODO: error
PipelineLayoutSuperset::ensure_superset_of(pipeline_layout.desc(), shader.layout())?;

View File

@ -33,14 +33,11 @@ use descriptor::pipeline_layout::PipelineLayoutNotSupersetError;
use descriptor::pipeline_layout::PipelineLayoutSys;
use descriptor::pipeline_layout::EmptyPipelineDesc;
use format::ClearValue;
use framebuffer::AttachmentsList;
use framebuffer::LayoutAttachmentDescription;
use framebuffer::LayoutPassDescription;
use framebuffer::LayoutPassDependencyDescription;
use framebuffer::FramebufferCreationError;
use framebuffer::RenderPassAbstract;
use framebuffer::RenderPassDesc;
use framebuffer::RenderPassDescAttachmentsList;
use framebuffer::RenderPassDescClearValues;
use framebuffer::RenderPassSubpassInterface;
use framebuffer::RenderPassSys;
@ -184,7 +181,7 @@ impl<Vdef, Rp> GraphicsPipeline<Vdef, (), Rp>
/// the other constructors for other possibilities.
#[inline]
pub fn new<'a, Vsp, Vi, Vo, Vl, Fs, Fi, Fo, Fl>
(device: &Arc<Device>,
(device: Arc<Device>,
params: GraphicsPipelineParams<'a, Vdef, Vsp, Vi, Vo, Vl, (), (), (), EmptyPipelineDesc,
(), (), (), EmptyPipelineDesc, (), (), (), EmptyPipelineDesc,
Fs, Fi, Fo, Fl, Rp>)
@ -203,7 +200,7 @@ impl<Vdef, Rp> GraphicsPipeline<Vdef, (), Rp>
let pl = params.vertex_shader.layout().clone()
.union(params.fragment_shader.layout().clone())
.build(device).unwrap(); // TODO: error
.build(device.clone()).unwrap(); // TODO: error
GraphicsPipeline::new_inner::<_, _, _, _, (), (), (), EmptyPipelineDesc, (), (), (),
EmptyPipelineDesc, (), (), (), EmptyPipelineDesc, _, _, _, _>
@ -219,7 +216,7 @@ impl<Vdef, Rp> GraphicsPipeline<Vdef, (), Rp>
/// shader. See the other constructors for other possibilities.
#[inline]
pub fn with_geometry_shader<'a, Vsp, Vi, Vo, Vl, Gsp, Gi, Go, Gl, Fs, Fi, Fo, Fl>
(device: &Arc<Device>,
(device: Arc<Device>,
params: GraphicsPipelineParams<'a, Vdef, Vsp, Vi, Vo, Vl, (), (), (), EmptyPipelineDesc,
(), (), (), EmptyPipelineDesc, Gsp, Gi, Go, Gl, Fs, Fi,
Fo, Fl, Rp>)
@ -252,9 +249,9 @@ impl<Vdef, Rp> GraphicsPipeline<Vdef, (), Rp>
let pl = params.vertex_shader.layout().clone()
.union(params.fragment_shader.layout().clone())
.union(params.geometry_shader.as_ref().unwrap().layout().clone()) // FIXME: unwrap()
.build(device).unwrap(); // TODO: error
.build(device.clone()).unwrap(); // TODO: error
GraphicsPipeline::new_inner(device, params, pl)
GraphicsPipeline::new_inner(device.clone(), params, pl)
}
/// Builds a new graphics pipeline object with tessellation shaders.
@ -268,7 +265,7 @@ impl<Vdef, Rp> GraphicsPipeline<Vdef, (), Rp>
#[inline]
pub fn with_tessellation<'a, Vsp, Vi, Vo, Vl, Tcs, Tci, Tco, Tcl, Tes, Tei, Teo, Tel, Fs, Fi,
Fo, Fl>
(device: &Arc<Device>,
(device: Arc<Device>,
params: GraphicsPipelineParams<'a, Vdef, Vsp, Vi, Vo, Vl, Tcs, Tci, Tco, Tcl, Tes,
Tei, Teo, Tel, (), (), (), EmptyPipelineDesc, Fs, Fi,
Fo, Fl, Rp>)
@ -308,7 +305,7 @@ impl<Vdef, Rp> GraphicsPipeline<Vdef, (), Rp>
.union(params.fragment_shader.layout().clone())
.union(params.tessellation.as_ref().unwrap().tessellation_control_shader.layout().clone()) // FIXME: unwrap()
.union(params.tessellation.as_ref().unwrap().tessellation_evaluation_shader.layout().clone()) // FIXME: unwrap()
.build(device).unwrap(); // TODO: error
.build(device.clone()).unwrap(); // TODO: error
GraphicsPipeline::new_inner(device, params, pl)
}
@ -324,7 +321,7 @@ impl<Vdef, Rp> GraphicsPipeline<Vdef, (), Rp>
#[inline]
pub fn with_tessellation_and_geometry<'a, Vsp, Vi, Vo, Vl, Tcs, Tci, Tco, Tcl, Tes, Tei, Teo, Tel, Gsp, Gi,
Go, Gl, Fs, Fi, Fo, Fl>
(device: &Arc<Device>,
(device: Arc<Device>,
params: GraphicsPipelineParams<'a, Vdef, Vsp, Vi, Vo, Vl, Tcs, Tci, Tco, Tcl, Tes,
Tei, Teo, Tel, Gsp, Gi, Go, Gl, Fs, Fi,
Fo, Fl, Rp>)
@ -377,7 +374,7 @@ impl<Vdef, Rp> GraphicsPipeline<Vdef, (), Rp>
.union(params.tessellation.as_ref().unwrap().tessellation_control_shader.layout().clone()) // FIXME: unwrap()
.union(params.tessellation.as_ref().unwrap().tessellation_evaluation_shader.layout().clone()) // FIXME: unwrap()
.union(params.geometry_shader.as_ref().unwrap().layout().clone()) // FIXME: unwrap()
.build(device).unwrap(); // TODO: error
.build(device.clone()).unwrap(); // TODO: error
GraphicsPipeline::new_inner(device, params, pl)
}
@ -388,7 +385,7 @@ impl<Vdef, L, Rp> GraphicsPipeline<Vdef, L, Rp>
{
fn new_inner<'a, Vsp, Vi, Vo, Vl, Tcs, Tci, Tco, Tcl, Tes, Tei, Teo, Tel, Gsp, Gi, Go, Gl, Fs,
Fi, Fo, Fl>
(device: &Arc<Device>,
(device: Arc<Device>,
params: GraphicsPipelineParams<'a, Vdef, Vsp, Vi, Vo, Vl, Tcs, Tci, Tco, Tcl, Tes,
Tei, Teo, Tel, Gsp, Gi, Go, Gl, Fs, Fi, Fo, Fl, Rp>,
pipeline_layout: L)
@ -1153,8 +1150,8 @@ unsafe impl<Mv, L, Rp> RenderPassDesc for GraphicsPipeline<Mv, L, Rp>
}
#[inline]
fn attachment(&self, num: usize) -> Option<LayoutAttachmentDescription> {
self.render_pass.attachment(num)
fn attachment_desc(&self, num: usize) -> Option<LayoutAttachmentDescription> {
self.render_pass.attachment_desc(num)
}
#[inline]
@ -1163,8 +1160,8 @@ unsafe impl<Mv, L, Rp> RenderPassDesc for GraphicsPipeline<Mv, L, Rp>
}
#[inline]
fn subpass(&self, num: usize) -> Option<LayoutPassDescription> {
self.render_pass.subpass(num)
fn subpass_desc(&self, num: usize) -> Option<LayoutPassDescription> {
self.render_pass.subpass_desc(num)
}
#[inline]
@ -1173,17 +1170,8 @@ unsafe impl<Mv, L, Rp> RenderPassDesc for GraphicsPipeline<Mv, L, Rp>
}
#[inline]
fn dependency(&self, num: usize) -> Option<LayoutPassDependencyDescription> {
self.render_pass.dependency(num)
}
}
unsafe impl<A, Mv, L, Rp> RenderPassDescAttachmentsList<A> for GraphicsPipeline<Mv, L, Rp>
where Rp: RenderPassDescAttachmentsList<A>
{
#[inline]
fn check_attachments_list(&self, atch: A) -> Result<Box<AttachmentsList + Send + Sync>, FramebufferCreationError> {
self.render_pass.check_attachments_list(atch)
fn dependency_desc(&self, num: usize) -> Option<LayoutPassDependencyDescription> {
self.render_pass.dependency_desc(num)
}
}

View File

@ -1,664 +0,0 @@
// Copyright (c) 2016 The vulkano developers
// Licensed under the Apache License, Version 2.0
// <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT
// license <LICENSE-MIT or http://opensource.org/licenses/MIT>,
// at your option. All files in the project carrying such
// notice may not be copied, modified, or distributed except
// according to those terms.
//! # Vertex sources definition
//!
//! When you create a graphics pipeline object, you need to pass an object which indicates the
//! layout of the vertex buffer(s) that will serve as input for the vertex shader. This is done
//! by passing an implementation of the `VertexDefinition` trait.
//!
//! In addition to this, the object that you pass when you create the graphics pipeline must also
//! implement the `VertexSource` trait. This trait has a template parameter which corresponds to the
//! list of vertex buffers.
//!
//! The vulkano library provides some structs that already implement these traits.
//! The most common situation is a single vertex buffer and no instancing, in which case you can
//! pass a `SingleBufferDefinition` when you create the pipeline.
//!
//! # Implementing `Vertex`
//!
//! The implementations of the `VertexDefinition` trait that are provided by vulkano (like
//! `SingleBufferDefinition`) require you to use a buffer whose content is `[V]` where `V`
//! implements the `Vertex` trait.
//!
//! The `Vertex` trait is unsafe, but can be implemented on a struct with the `impl_vertex!`
//! macro.
//!
//! # Example
//!
//! ```ignore // TODO:
//! # #[macro_use] extern crate vulkano
//! # fn main() {
//! # use std::sync::Arc;
//! # use vulkano::device::Device;
//! # use vulkano::device::Queue;
//! use vulkano::buffer::BufferAccess;
//! use vulkano::buffer::Usage as BufferUsage;
//! use vulkano::memory::HostVisible;
//! use vulkano::pipeline::vertex::;
//! # let device: Arc<Device> = return;
//! # let queue: Arc<Queue> = return;
//!
//! struct Vertex {
//! position: [f32; 2]
//! }
//!
//! impl_vertex!(Vertex, position);
//!
//! let usage = BufferUsage {
//! vertex_buffer: true,
//! .. BufferUsage::none()
//! };
//!
//! let vertex_buffer = BufferAccess::<[Vertex], _>::array(&device, 128, &usage, HostVisible, &queue)
//! .expect("failed to create buffer");
//!
//! // TODO: finish example
//! # }
//! ```
use std::error;
use std::fmt;
use std::marker::PhantomData;
use std::mem;
use std::option::IntoIter as OptionIntoIter;
use std::sync::Arc;
use std::vec::IntoIter as VecIntoIter;
use buffer::BufferAccess;
use buffer::BufferInner;
use buffer::TypedBufferAccess;
use format::Format;
use pipeline::shader::ShaderInterfaceDef;
use SafeDeref;
use vk;
/// How the vertex source should be unrolled.
#[derive(Copy, Clone, Debug)]
#[repr(u32)]
pub enum InputRate {
/// Each element of the source corresponds to a vertex.
Vertex = vk::VERTEX_INPUT_RATE_VERTEX,
/// Each element of the source corresponds to an instance.
Instance = vk::VERTEX_INPUT_RATE_INSTANCE,
}
/// 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 binded depends on the shader.
pub unsafe trait Vertex: 'static + Send + Sync {
/// Returns the characteristics of a vertex member by its name.
fn member(name: &str) -> Option<VertexMemberInfo>;
}
unsafe impl Vertex for () {
#[inline]
fn member(_: &str) -> Option<VertexMemberInfo> {
None
}
}
/// Information about a member of a vertex struct.
pub struct VertexMemberInfo {
/// Offset of the member in bytes from the start of the struct.
pub offset: usize,
/// Type of data. This is used to check that the interface is matching.
pub ty: VertexMemberTy,
/// Number of consecutive elements of that type.
pub array_size: usize,
}
/// Type of a member of a vertex struct.
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
#[allow(missing_docs)]
pub enum VertexMemberTy {
I8,
U8,
I16,
U16,
I32,
U32,
F32,
F64,
}
impl VertexMemberTy {
/// Returns true if a combination of `(type, array_size)` matches a format.
#[inline]
pub fn matches(&self, array_size: usize, format: Format, num_locs: u32) -> bool {
// TODO: implement correctly
let my_size = match *self {
VertexMemberTy::I8 => 1,
VertexMemberTy::U8 => 1,
VertexMemberTy::I16 => 2,
VertexMemberTy::U16 => 2,
VertexMemberTy::I32 => 4,
VertexMemberTy::U32 => 4,
VertexMemberTy::F32 => 4,
VertexMemberTy::F64 => 8,
};
let format_size = match format.size() {
None => return false,
Some(s) => s,
};
array_size * my_size == format_size * num_locs as usize
}
}
/// Information about a single attribute within a vertex.
/// TODO: change that API
pub struct AttributeInfo {
/// Number of bytes between the start of a vertex and the location of attribute.
pub offset: usize,
/// VertexMember type of the attribute.
pub format: Format,
}
/// Trait for types that describe the definition of the vertex input used by a graphics pipeline.
pub unsafe trait VertexDefinition<I>: VertexSource<Vec<Arc<BufferAccess + Send + Sync>>> {
/// Iterator that returns the offset, the stride (in bytes) and input rate of each buffer.
type BuffersIter: ExactSizeIterator<Item = (u32, usize, InputRate)>;
/// Iterator that returns the attribute location, buffer id, and infos.
type AttribsIter: ExactSizeIterator<Item = (u32, u32, AttributeInfo)>;
/// Builds the vertex definition to use to link this definition to a vertex shader's input
/// interface.
fn definition(&self, interface: &I) -> Result<(Self::BuffersIter, Self::AttribsIter),
IncompatibleVertexDefinitionError>;
}
unsafe impl<I, T> VertexDefinition<I> for T where T: SafeDeref, T::Target: VertexDefinition<I> {
type BuffersIter = <T::Target as VertexDefinition<I>>::BuffersIter;
type AttribsIter = <T::Target as VertexDefinition<I>>::AttribsIter;
#[inline]
fn definition(&self, interface: &I) -> Result<(Self::BuffersIter, Self::AttribsIter),
IncompatibleVertexDefinitionError>
{
(**self).definition(interface)
}
}
/// Error that can happen when the vertex definition doesn't match the input of the vertex shader.
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum IncompatibleVertexDefinitionError {
/// An attribute of the vertex shader is missing in the vertex source.
MissingAttribute {
/// Name of the missing attribute.
attribute: String,
},
/// The format of an attribute does not match.
FormatMismatch {
/// Name of the attribute.
attribute: String,
/// The format in the vertex shader.
shader: (Format, usize),
/// The format in the vertex definition.
definition: (VertexMemberTy, usize),
},
}
impl error::Error for IncompatibleVertexDefinitionError {
#[inline]
fn description(&self) -> &str {
match *self {
IncompatibleVertexDefinitionError::MissingAttribute { .. } => "an attribute is missing",
IncompatibleVertexDefinitionError::FormatMismatch { .. } => {
"the format of an attribute does not match"
},
}
}
}
impl fmt::Display for IncompatibleVertexDefinitionError {
#[inline]
fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
write!(fmt, "{}", error::Error::description(self))
}
}
/// Extension trait of `VertexDefinition`. The `L` parameter is an acceptable vertex source for this
/// vertex definition.
pub unsafe trait VertexSource<L> {
/// Checks and returns the list of buffers with offsets, number of vertices and number of instances.
// TODO: return error if problem
// TODO: better than a Vec
// TODO: return a struct instead
fn decode<'l>(&self, &'l L) -> (Vec<BufferInner<'l>>, usize, usize);
}
unsafe impl<L, T> VertexSource<L> for T where T: SafeDeref, T::Target: VertexSource<L> {
#[inline]
fn decode<'l>(&self, list: &'l L) -> (Vec<BufferInner<'l>>, usize, usize) {
(**self).decode(list)
}
}
/// Implementation of `VertexDefinition` for a single vertex buffer.
pub struct SingleBufferDefinition<T>(pub PhantomData<T>);
impl<T> SingleBufferDefinition<T> {
#[inline]
pub fn new() -> SingleBufferDefinition<T> { SingleBufferDefinition(PhantomData) }
}
unsafe impl<T, I> VertexDefinition<I> for SingleBufferDefinition<T>
where T: Vertex, I: ShaderInterfaceDef
{
type BuffersIter = OptionIntoIter<(u32, usize, InputRate)>;
type AttribsIter = VecIntoIter<(u32, u32, AttributeInfo)>;
fn definition(&self, interface: &I) -> Result<(Self::BuffersIter, Self::AttribsIter),
IncompatibleVertexDefinitionError>
{
let attrib = {
let mut attribs = Vec::with_capacity(interface.elements().len());
for e in interface.elements() {
let name = e.name.as_ref().unwrap();
let infos = match <T as Vertex>::member(name) {
Some(m) => m,
None => return Err(IncompatibleVertexDefinitionError::MissingAttribute {
attribute: name.clone().into_owned()
})
};
if !infos.ty.matches(infos.array_size, e.format,
e.location.end - e.location.start)
{
return Err(IncompatibleVertexDefinitionError::FormatMismatch {
attribute: name.clone().into_owned(),
shader: (e.format, (e.location.end - e.location.start) as usize),
definition: (infos.ty, infos.array_size),
})
}
let mut offset = infos.offset;
for loc in e.location.clone() {
attribs.push((loc, 0, AttributeInfo { offset: offset, format: e.format }));
offset += e.format.size().unwrap();
}
}
attribs
}.into_iter(); // TODO: meh
let buffers = Some((0, mem::size_of::<T>(), InputRate::Vertex)).into_iter();
Ok((buffers, attrib))
}
}
unsafe impl<V> VertexSource<Vec<Arc<BufferAccess + Send + Sync>>> for SingleBufferDefinition<V>
where V: Vertex
{
#[inline]
fn decode<'l>(&self, source: &'l Vec<Arc<BufferAccess + Send + Sync>>) -> (Vec<BufferInner<'l>>, usize, usize) {
// FIXME: safety
assert_eq!(source.len(), 1);
let len = source[0].size() / mem::size_of::<V>();
(vec![source[0].inner()], len, 1)
}
}
unsafe impl<'a, B, V> VertexSource<B> for SingleBufferDefinition<V>
where B: TypedBufferAccess<Content = [V]>, V: Vertex
{
#[inline]
fn decode<'l>(&self, source: &'l B) -> (Vec<BufferInner<'l>>, usize, usize) {
(vec![source.inner()], source.len(), 1)
}
}
/// Unstable.
// TODO: shouldn't be just `Two` but `Multi`
pub struct TwoBuffersDefinition<T, U>(pub PhantomData<(T, U)>);
impl<T, U> TwoBuffersDefinition<T, U> {
#[inline]
pub fn new() -> TwoBuffersDefinition<T, U> { TwoBuffersDefinition(PhantomData) }
}
unsafe impl<T, U, I> VertexDefinition<I> for TwoBuffersDefinition<T, U>
where T: Vertex, U: Vertex, I: ShaderInterfaceDef
{
type BuffersIter = VecIntoIter<(u32, usize, InputRate)>;
type AttribsIter = VecIntoIter<(u32, u32, AttributeInfo)>;
fn definition(&self, interface: &I) -> Result<(Self::BuffersIter, Self::AttribsIter),
IncompatibleVertexDefinitionError>
{
let attrib = {
let mut attribs = Vec::with_capacity(interface.elements().len());
for e in interface.elements() {
let name = e.name.as_ref().unwrap();
let (infos, buf_offset) = if let Some(infos) = <T as Vertex>::member(name) {
(infos, 0)
} else if let Some(infos) = <U as Vertex>::member(name) {
(infos, 1)
} else {
return Err(IncompatibleVertexDefinitionError::MissingAttribute {
attribute: name.clone().into_owned()
});
};
if !infos.ty.matches(infos.array_size, e.format,
e.location.end - e.location.start)
{
return Err(IncompatibleVertexDefinitionError::FormatMismatch {
attribute: name.clone().into_owned(),
shader: (e.format, (e.location.end - e.location.start) as usize),
definition: (infos.ty, infos.array_size),
})
}
let mut offset = infos.offset;
for loc in e.location.clone() {
attribs.push((loc, buf_offset, AttributeInfo { offset: offset, format: e.format }));
offset += e.format.size().unwrap();
}
}
attribs
}.into_iter(); // TODO: meh
let buffers = vec![
(0, mem::size_of::<T>(), InputRate::Vertex),
(1, mem::size_of::<U>(), InputRate::Vertex)
].into_iter();
Ok((buffers, attrib))
}
}
unsafe impl<T, U> VertexSource<Vec<Arc<BufferAccess + Send + Sync>>> for TwoBuffersDefinition<T, U>
where T: Vertex, U: Vertex
{
#[inline]
fn decode<'l>(&self, source: &'l Vec<Arc<BufferAccess + Send + Sync>>) -> (Vec<BufferInner<'l>>, usize, usize) {
unimplemented!() // FIXME: implement
}
}
unsafe impl<'a, T, U, Bt, Bu> VertexSource<(Bt, Bu)> for TwoBuffersDefinition<T, U>
where T: Vertex, Bt: TypedBufferAccess<Content = [T]>,
U: Vertex, Bu: TypedBufferAccess<Content = [U]>
{
#[inline]
fn decode<'l>(&self, source: &'l (Bt, Bu)) -> (Vec<BufferInner<'l>>, usize, usize) {
let vertices = [source.0.len(), source.1.len()].iter().cloned().min().unwrap();
(vec![source.0.inner(), source.1.inner()], vertices, 1)
}
}
/// Unstable.
// TODO: bad way to do things
pub struct OneVertexOneInstanceDefinition<T, U>(pub PhantomData<(T, U)>);
impl<T, U> OneVertexOneInstanceDefinition<T, U> {
#[inline]
pub fn new() -> OneVertexOneInstanceDefinition<T, U> { OneVertexOneInstanceDefinition(PhantomData) }
}
unsafe impl<T, U, I> VertexDefinition<I> for OneVertexOneInstanceDefinition<T, U>
where T: Vertex, U: Vertex, I: ShaderInterfaceDef
{
type BuffersIter = VecIntoIter<(u32, usize, InputRate)>;
type AttribsIter = VecIntoIter<(u32, u32, AttributeInfo)>;
fn definition(&self, interface: &I) -> Result<(Self::BuffersIter, Self::AttribsIter),
IncompatibleVertexDefinitionError>
{
let attrib = {
let mut attribs = Vec::with_capacity(interface.elements().len());
for e in interface.elements() {
let name = e.name.as_ref().unwrap();
let (infos, buf_offset) = if let Some(infos) = <T as Vertex>::member(name) {
(infos, 0)
} else if let Some(infos) = <U as Vertex>::member(name) {
(infos, 1)
} else {
return Err(IncompatibleVertexDefinitionError::MissingAttribute {
attribute: name.clone().into_owned()
});
};
if !infos.ty.matches(infos.array_size, e.format,
e.location.end - e.location.start)
{
return Err(IncompatibleVertexDefinitionError::FormatMismatch {
attribute: name.clone().into_owned(),
shader: (e.format, (e.location.end - e.location.start) as usize),
definition: (infos.ty, infos.array_size),
})
}
let mut offset = infos.offset;
for loc in e.location.clone() {
attribs.push((loc, buf_offset, AttributeInfo { offset: offset, format: e.format }));
offset += e.format.size().unwrap();
}
}
attribs
}.into_iter(); // TODO: meh
let buffers = vec![
(0, mem::size_of::<T>(), InputRate::Vertex),
(1, mem::size_of::<U>(), InputRate::Instance)
].into_iter();
Ok((buffers, attrib))
}
}
unsafe impl<T, U> VertexSource<Vec<Arc<BufferAccess + Send + Sync>>> for OneVertexOneInstanceDefinition<T, U>
where T: Vertex, U: Vertex
{
#[inline]
fn decode<'l>(&self, source: &'l Vec<Arc<BufferAccess + Send + Sync>>) -> (Vec<BufferInner<'l>>, usize, usize) {
// FIXME: safety
assert_eq!(source.len(), 2);
let len = source[0].size() / mem::size_of::<T>();
let inst = source[0].size() / mem::size_of::<U>();
(vec![source[0].inner(), source[1].inner()], len, inst)
}
}
unsafe impl<'a, T, U, Bt, Bu> VertexSource<(Bt, Bu)> for OneVertexOneInstanceDefinition<T, U>
where T: Vertex, Bt: TypedBufferAccess<Content = [T]>,
U: Vertex, Bu: TypedBufferAccess<Content = [U]>
{
#[inline]
fn decode<'l>(&self, source: &'l (Bt, Bu)) -> (Vec<BufferInner<'l>>, usize, usize) {
(vec![source.0.inner(), source.1.inner()], source.0.len(), source.1.len())
}
}
/// Implements the `Vertex` trait on a struct.
// TODO: add example
#[macro_export]
macro_rules! impl_vertex {
($out:ident $(, $member:ident)*) => (
#[allow(unsafe_code)]
unsafe impl $crate::pipeline::vertex::Vertex for $out {
#[inline(always)]
fn member(name: &str) -> Option<$crate::pipeline::vertex::VertexMemberInfo> {
use std::ptr;
#[allow(unused_imports)]
use $crate::format::Format;
use $crate::pipeline::vertex::VertexMemberInfo;
use $crate::pipeline::vertex::VertexMemberTy;
use $crate::pipeline::vertex::VertexMember;
$(
if name == stringify!($member) {
let (ty, array_size) = unsafe {
#[inline] fn f<T: VertexMember>(_: &T) -> (VertexMemberTy, usize)
{ T::format() }
let dummy: *const $out = ptr::null();
f(&(&*dummy).$member)
};
return Some(VertexMemberInfo {
offset: unsafe {
let dummy: *const $out = ptr::null();
let member = (&(&*dummy).$member) as *const _;
member as usize
},
ty: ty,
array_size: array_size,
});
}
)*
None
}
}
)
}
/// Trait for data types that can be used as vertex members. Used by the `impl_vertex!` macro.
pub unsafe trait VertexMember {
/// Returns the format and array size of the member.
fn format() -> (VertexMemberTy, usize);
}
unsafe impl VertexMember for i8 {
#[inline]
fn format() -> (VertexMemberTy, usize) {
(VertexMemberTy::I8, 1)
}
}
unsafe impl VertexMember for u8 {
#[inline]
fn format() -> (VertexMemberTy, usize) {
(VertexMemberTy::U8, 1)
}
}
unsafe impl VertexMember for i16 {
#[inline]
fn format() -> (VertexMemberTy, usize) {
(VertexMemberTy::I16, 1)
}
}
unsafe impl VertexMember for u16 {
#[inline]
fn format() -> (VertexMemberTy, usize) {
(VertexMemberTy::U16, 1)
}
}
unsafe impl VertexMember for i32 {
#[inline]
fn format() -> (VertexMemberTy, usize) {
(VertexMemberTy::I32, 1)
}
}
unsafe impl VertexMember for u32 {
#[inline]
fn format() -> (VertexMemberTy, usize) {
(VertexMemberTy::U32, 1)
}
}
unsafe impl VertexMember for f32 {
#[inline]
fn format() -> (VertexMemberTy, usize) {
(VertexMemberTy::F32, 1)
}
}
unsafe impl VertexMember for f64 {
#[inline]
fn format() -> (VertexMemberTy, usize) {
(VertexMemberTy::F64, 1)
}
}
unsafe impl<T> VertexMember for (T,)
where T: VertexMember
{
#[inline]
fn format() -> (VertexMemberTy, usize) {
<T as VertexMember>::format()
}
}
unsafe impl<T> VertexMember for (T, T)
where T: VertexMember
{
#[inline]
fn format() -> (VertexMemberTy, usize) {
let (ty, sz) = <T as VertexMember>::format();
(ty, sz * 2)
}
}
unsafe impl<T> VertexMember for (T, T, T)
where T: VertexMember
{
#[inline]
fn format() -> (VertexMemberTy, usize) {
let (ty, sz) = <T as VertexMember>::format();
(ty, sz * 3)
}
}
unsafe impl<T> VertexMember for (T, T, T, T)
where T: VertexMember
{
#[inline]
fn format() -> (VertexMemberTy, usize) {
let (ty, sz) = <T as VertexMember>::format();
(ty, sz * 4)
}
}
macro_rules! impl_vm_array {
($sz:expr) => (
unsafe impl<T> VertexMember for [T; $sz]
where T: VertexMember
{
#[inline]
fn format() -> (VertexMemberTy, usize) {
let (ty, sz) = <T as VertexMember>::format();
(ty, sz * $sz)
}
}
);
}
impl_vm_array!(1);
impl_vm_array!(2);
impl_vm_array!(3);
impl_vm_array!(4);
impl_vm_array!(5);
impl_vm_array!(6);
impl_vm_array!(7);
impl_vm_array!(8);
impl_vm_array!(9);
impl_vm_array!(10);
impl_vm_array!(11);
impl_vm_array!(12);
impl_vm_array!(13);
impl_vm_array!(14);
impl_vm_array!(15);
impl_vm_array!(16);
impl_vm_array!(32);
impl_vm_array!(64);

View File

@ -0,0 +1,120 @@
// Copyright (c) 2016 The vulkano developers
// Licensed under the Apache License, Version 2.0
// <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT
// license <LICENSE-MIT or http://opensource.org/licenses/MIT>,
// 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::error;
use std::fmt;
use std::sync::Arc;
use buffer::BufferAccess;
use buffer::BufferInner;
use format::Format;
use pipeline::vertex::VertexMemberTy;
use SafeDeref;
use vk;
/// Trait for types that describe the definition of the vertex input used by a graphics pipeline.
pub unsafe trait VertexDefinition<I>: VertexSource<Vec<Arc<BufferAccess + Send + Sync>>> {
/// Iterator that returns the offset, the stride (in bytes) and input rate of each buffer.
type BuffersIter: ExactSizeIterator<Item = (u32, usize, InputRate)>;
/// Iterator that returns the attribute location, buffer id, and infos.
type AttribsIter: ExactSizeIterator<Item = (u32, u32, AttributeInfo)>;
/// Builds the vertex definition to use to link this definition to a vertex shader's input
/// interface.
fn definition(&self, interface: &I) -> Result<(Self::BuffersIter, Self::AttribsIter),
IncompatibleVertexDefinitionError>;
}
unsafe impl<I, T> VertexDefinition<I> for T where T: SafeDeref, T::Target: VertexDefinition<I> {
type BuffersIter = <T::Target as VertexDefinition<I>>::BuffersIter;
type AttribsIter = <T::Target as VertexDefinition<I>>::AttribsIter;
#[inline]
fn definition(&self, interface: &I) -> Result<(Self::BuffersIter, Self::AttribsIter),
IncompatibleVertexDefinitionError>
{
(**self).definition(interface)
}
}
/// How the vertex source should be unrolled.
#[derive(Copy, Clone, Debug)]
#[repr(u32)]
pub enum InputRate {
/// Each element of the source corresponds to a vertex.
Vertex = vk::VERTEX_INPUT_RATE_VERTEX,
/// Each element of the source corresponds to an instance.
Instance = vk::VERTEX_INPUT_RATE_INSTANCE,
}
/// Information about a single attribute within a vertex.
/// TODO: change that API
pub struct AttributeInfo {
/// Number of bytes between the start of a vertex and the location of attribute.
pub offset: usize,
/// VertexMember type of the attribute.
pub format: Format,
}
/// Error that can happen when the vertex definition doesn't match the input of the vertex shader.
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum IncompatibleVertexDefinitionError {
/// An attribute of the vertex shader is missing in the vertex source.
MissingAttribute {
/// Name of the missing attribute.
attribute: String,
},
/// The format of an attribute does not match.
FormatMismatch {
/// Name of the attribute.
attribute: String,
/// The format in the vertex shader.
shader: (Format, usize),
/// The format in the vertex definition.
definition: (VertexMemberTy, usize),
},
}
impl error::Error for IncompatibleVertexDefinitionError {
#[inline]
fn description(&self) -> &str {
match *self {
IncompatibleVertexDefinitionError::MissingAttribute { .. } => "an attribute is missing",
IncompatibleVertexDefinitionError::FormatMismatch { .. } => {
"the format of an attribute does not match"
},
}
}
}
impl fmt::Display for IncompatibleVertexDefinitionError {
#[inline]
fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
write!(fmt, "{}", error::Error::description(self))
}
}
/// Extension trait of `VertexDefinition`. The `L` parameter is an acceptable vertex source for this
/// vertex definition.
pub unsafe trait VertexSource<L> {
/// Checks and returns the list of buffers with offsets, number of vertices and number of instances.
// TODO: return error if problem
// TODO: better than a Vec
// TODO: return a struct instead
fn decode<'l>(&self, &'l L) -> (Vec<BufferInner<'l>>, usize, usize);
}
unsafe impl<L, T> VertexSource<L> for T where T: SafeDeref, T::Target: VertexSource<L> {
#[inline]
fn decode<'l>(&self, list: &'l L) -> (Vec<BufferInner<'l>>, usize, usize) {
(**self).decode(list)
}
}

View File

@ -0,0 +1,188 @@
// Copyright (c) 2017 The vulkano developers
// Licensed under the Apache License, Version 2.0
// <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT
// license <LICENSE-MIT or http://opensource.org/licenses/MIT>,
// at your option. All files in the project carrying such
// notice may not be copied, modified, or distributed except
// according to those terms.
use pipeline::vertex::VertexMemberTy;
/// Implements the `Vertex` trait on a struct.
// TODO: add example
#[macro_export]
macro_rules! impl_vertex {
($out:ident $(, $member:ident)*) => (
#[allow(unsafe_code)]
unsafe impl $crate::pipeline::vertex::Vertex for $out {
#[inline(always)]
fn member(name: &str) -> Option<$crate::pipeline::vertex::VertexMemberInfo> {
use std::ptr;
#[allow(unused_imports)]
use $crate::format::Format;
use $crate::pipeline::vertex::VertexMemberInfo;
use $crate::pipeline::vertex::VertexMemberTy;
use $crate::pipeline::vertex::VertexMember;
$(
if name == stringify!($member) {
let (ty, array_size) = unsafe {
#[inline] fn f<T: VertexMember>(_: &T) -> (VertexMemberTy, usize)
{ T::format() }
let dummy: *const $out = ptr::null();
f(&(&*dummy).$member)
};
return Some(VertexMemberInfo {
offset: unsafe {
let dummy: *const $out = ptr::null();
let member = (&(&*dummy).$member) as *const _;
member as usize
},
ty: ty,
array_size: array_size,
});
}
)*
None
}
}
)
}
/// Trait for data types that can be used as vertex members. Used by the `impl_vertex!` macro.
pub unsafe trait VertexMember {
/// Returns the format and array size of the member.
fn format() -> (VertexMemberTy, usize);
}
unsafe impl VertexMember for i8 {
#[inline]
fn format() -> (VertexMemberTy, usize) {
(VertexMemberTy::I8, 1)
}
}
unsafe impl VertexMember for u8 {
#[inline]
fn format() -> (VertexMemberTy, usize) {
(VertexMemberTy::U8, 1)
}
}
unsafe impl VertexMember for i16 {
#[inline]
fn format() -> (VertexMemberTy, usize) {
(VertexMemberTy::I16, 1)
}
}
unsafe impl VertexMember for u16 {
#[inline]
fn format() -> (VertexMemberTy, usize) {
(VertexMemberTy::U16, 1)
}
}
unsafe impl VertexMember for i32 {
#[inline]
fn format() -> (VertexMemberTy, usize) {
(VertexMemberTy::I32, 1)
}
}
unsafe impl VertexMember for u32 {
#[inline]
fn format() -> (VertexMemberTy, usize) {
(VertexMemberTy::U32, 1)
}
}
unsafe impl VertexMember for f32 {
#[inline]
fn format() -> (VertexMemberTy, usize) {
(VertexMemberTy::F32, 1)
}
}
unsafe impl VertexMember for f64 {
#[inline]
fn format() -> (VertexMemberTy, usize) {
(VertexMemberTy::F64, 1)
}
}
unsafe impl<T> VertexMember for (T,)
where T: VertexMember
{
#[inline]
fn format() -> (VertexMemberTy, usize) {
<T as VertexMember>::format()
}
}
unsafe impl<T> VertexMember for (T, T)
where T: VertexMember
{
#[inline]
fn format() -> (VertexMemberTy, usize) {
let (ty, sz) = <T as VertexMember>::format();
(ty, sz * 2)
}
}
unsafe impl<T> VertexMember for (T, T, T)
where T: VertexMember
{
#[inline]
fn format() -> (VertexMemberTy, usize) {
let (ty, sz) = <T as VertexMember>::format();
(ty, sz * 3)
}
}
unsafe impl<T> VertexMember for (T, T, T, T)
where T: VertexMember
{
#[inline]
fn format() -> (VertexMemberTy, usize) {
let (ty, sz) = <T as VertexMember>::format();
(ty, sz * 4)
}
}
macro_rules! impl_vm_array {
($sz:expr) => (
unsafe impl<T> VertexMember for [T; $sz]
where T: VertexMember
{
#[inline]
fn format() -> (VertexMemberTy, usize) {
let (ty, sz) = <T as VertexMember>::format();
(ty, sz * $sz)
}
}
);
}
impl_vm_array!(1);
impl_vm_array!(2);
impl_vm_array!(3);
impl_vm_array!(4);
impl_vm_array!(5);
impl_vm_array!(6);
impl_vm_array!(7);
impl_vm_array!(8);
impl_vm_array!(9);
impl_vm_array!(10);
impl_vm_array!(11);
impl_vm_array!(12);
impl_vm_array!(13);
impl_vm_array!(14);
impl_vm_array!(15);
impl_vm_array!(16);
impl_vm_array!(32);
impl_vm_array!(64);

View File

@ -0,0 +1,84 @@
// Copyright (c) 2016 The vulkano developers
// Licensed under the Apache License, Version 2.0
// <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT
// license <LICENSE-MIT or http://opensource.org/licenses/MIT>,
// at your option. All files in the project carrying such
// notice may not be copied, modified, or distributed except
// according to those terms.
//! # Vertex sources definition
//!
//! When you create a graphics pipeline object, you need to pass an object which indicates the
//! layout of the vertex buffer(s) that will serve as input for the vertex shader. This is done
//! by passing an implementation of the `VertexDefinition` trait.
//!
//! In addition to this, the object that you pass when you create the graphics pipeline must also
//! implement the `VertexSource` trait. This trait has a template parameter which corresponds to the
//! list of vertex buffers.
//!
//! The vulkano library provides some structs that already implement these traits.
//! The most common situation is a single vertex buffer and no instancing, in which case you can
//! pass a `SingleBufferDefinition` when you create the pipeline.
//!
//! # Implementing `Vertex`
//!
//! The implementations of the `VertexDefinition` trait that are provided by vulkano (like
//! `SingleBufferDefinition`) require you to use a buffer whose content is `[V]` where `V`
//! implements the `Vertex` trait.
//!
//! The `Vertex` trait is unsafe, but can be implemented on a struct with the `impl_vertex!`
//! macro.
//!
//! # Example
//!
//! ```ignore // TODO:
//! # #[macro_use] extern crate vulkano
//! # fn main() {
//! # use std::sync::Arc;
//! # use vulkano::device::Device;
//! # use vulkano::device::Queue;
//! use vulkano::buffer::BufferAccess;
//! use vulkano::buffer::BufferUsage;
//! use vulkano::memory::HostVisible;
//! use vulkano::pipeline::vertex::;
//! # let device: Arc<Device> = return;
//! # let queue: Arc<Queue> = return;
//!
//! struct Vertex {
//! position: [f32; 2]
//! }
//!
//! impl_vertex!(Vertex, position);
//!
//! let usage = BufferUsage {
//! vertex_buffer: true,
//! .. BufferUsage::none()
//! };
//!
//! let vertex_buffer = BufferAccess::<[Vertex], _>::array(&device, 128, &usage, HostVisible, &queue)
//! .expect("failed to create buffer");
//!
//! // TODO: finish example
//! # }
//! ```
pub use self::definition::AttributeInfo;
pub use self::definition::IncompatibleVertexDefinitionError;
pub use self::definition::InputRate;
pub use self::definition::VertexDefinition;
pub use self::definition::VertexSource;
pub use self::impl_vertex::VertexMember;
pub use self::one_one::OneVertexOneInstanceDefinition;
pub use self::single::SingleBufferDefinition;
pub use self::two::TwoBuffersDefinition;
pub use self::vertex::Vertex;
pub use self::vertex::VertexMemberInfo;
pub use self::vertex::VertexMemberTy;
mod definition;
mod impl_vertex;
mod one_one;
mod single;
mod two;
mod vertex;

View File

@ -0,0 +1,108 @@
// Copyright (c) 2016 The vulkano developers
// Licensed under the Apache License, Version 2.0
// <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT
// license <LICENSE-MIT or http://opensource.org/licenses/MIT>,
// 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::marker::PhantomData;
use std::mem;
use std::sync::Arc;
use std::vec::IntoIter as VecIntoIter;
use buffer::BufferAccess;
use buffer::BufferInner;
use buffer::TypedBufferAccess;
use pipeline::shader::ShaderInterfaceDef;
use pipeline::vertex::AttributeInfo;
use pipeline::vertex::IncompatibleVertexDefinitionError;
use pipeline::vertex::InputRate;
use pipeline::vertex::Vertex;
use pipeline::vertex::VertexDefinition;
use pipeline::vertex::VertexSource;
/// Unstable.
// TODO: bad way to do things
pub struct OneVertexOneInstanceDefinition<T, U>(pub PhantomData<(T, U)>);
impl<T, U> OneVertexOneInstanceDefinition<T, U> {
#[inline]
pub fn new() -> OneVertexOneInstanceDefinition<T, U> { OneVertexOneInstanceDefinition(PhantomData) }
}
unsafe impl<T, U, I> VertexDefinition<I> for OneVertexOneInstanceDefinition<T, U>
where T: Vertex, U: Vertex, I: ShaderInterfaceDef
{
type BuffersIter = VecIntoIter<(u32, usize, InputRate)>;
type AttribsIter = VecIntoIter<(u32, u32, AttributeInfo)>;
fn definition(&self, interface: &I) -> Result<(Self::BuffersIter, Self::AttribsIter),
IncompatibleVertexDefinitionError>
{
let attrib = {
let mut attribs = Vec::with_capacity(interface.elements().len());
for e in interface.elements() {
let name = e.name.as_ref().unwrap();
let (infos, buf_offset) = if let Some(infos) = <T as Vertex>::member(name) {
(infos, 0)
} else if let Some(infos) = <U as Vertex>::member(name) {
(infos, 1)
} else {
return Err(IncompatibleVertexDefinitionError::MissingAttribute {
attribute: name.clone().into_owned()
});
};
if !infos.ty.matches(infos.array_size, e.format,
e.location.end - e.location.start)
{
return Err(IncompatibleVertexDefinitionError::FormatMismatch {
attribute: name.clone().into_owned(),
shader: (e.format, (e.location.end - e.location.start) as usize),
definition: (infos.ty, infos.array_size),
})
}
let mut offset = infos.offset;
for loc in e.location.clone() {
attribs.push((loc, buf_offset, AttributeInfo { offset: offset, format: e.format }));
offset += e.format.size().unwrap();
}
}
attribs
}.into_iter(); // TODO: meh
let buffers = vec![
(0, mem::size_of::<T>(), InputRate::Vertex),
(1, mem::size_of::<U>(), InputRate::Instance)
].into_iter();
Ok((buffers, attrib))
}
}
unsafe impl<T, U> VertexSource<Vec<Arc<BufferAccess + Send + Sync>>> for OneVertexOneInstanceDefinition<T, U>
where T: Vertex, U: Vertex
{
#[inline]
fn decode<'l>(&self, source: &'l Vec<Arc<BufferAccess + Send + Sync>>) -> (Vec<BufferInner<'l>>, usize, usize) {
// FIXME: safety
assert_eq!(source.len(), 2);
let len = source[0].size() / mem::size_of::<T>();
let inst = source[0].size() / mem::size_of::<U>();
(vec![source[0].inner(), source[1].inner()], len, inst)
}
}
unsafe impl<'a, T, U, Bt, Bu> VertexSource<(Bt, Bu)> for OneVertexOneInstanceDefinition<T, U>
where T: Vertex, Bt: TypedBufferAccess<Content = [T]>,
U: Vertex, Bu: TypedBufferAccess<Content = [U]>
{
#[inline]
fn decode<'l>(&self, source: &'l (Bt, Bu)) -> (Vec<BufferInner<'l>>, usize, usize) {
(vec![source.0.inner(), source.1.inner()], source.0.len(), source.1.len())
}
}

View File

@ -0,0 +1,99 @@
// Copyright (c) 2016 The vulkano developers
// Licensed under the Apache License, Version 2.0
// <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT
// license <LICENSE-MIT or http://opensource.org/licenses/MIT>,
// 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::marker::PhantomData;
use std::mem;
use std::option::IntoIter as OptionIntoIter;
use std::sync::Arc;
use std::vec::IntoIter as VecIntoIter;
use buffer::BufferAccess;
use buffer::BufferInner;
use buffer::TypedBufferAccess;
use pipeline::shader::ShaderInterfaceDef;
use pipeline::vertex::AttributeInfo;
use pipeline::vertex::IncompatibleVertexDefinitionError;
use pipeline::vertex::InputRate;
use pipeline::vertex::Vertex;
use pipeline::vertex::VertexDefinition;
use pipeline::vertex::VertexSource;
/// Implementation of `VertexDefinition` for a single vertex buffer.
pub struct SingleBufferDefinition<T>(pub PhantomData<T>);
impl<T> SingleBufferDefinition<T> {
#[inline]
pub fn new() -> SingleBufferDefinition<T> { SingleBufferDefinition(PhantomData) }
}
unsafe impl<T, I> VertexDefinition<I> for SingleBufferDefinition<T>
where T: Vertex, I: ShaderInterfaceDef
{
type BuffersIter = OptionIntoIter<(u32, usize, InputRate)>;
type AttribsIter = VecIntoIter<(u32, u32, AttributeInfo)>;
fn definition(&self, interface: &I) -> Result<(Self::BuffersIter, Self::AttribsIter),
IncompatibleVertexDefinitionError>
{
let attrib = {
let mut attribs = Vec::with_capacity(interface.elements().len());
for e in interface.elements() {
let name = e.name.as_ref().unwrap();
let infos = match <T as Vertex>::member(name) {
Some(m) => m,
None => return Err(IncompatibleVertexDefinitionError::MissingAttribute {
attribute: name.clone().into_owned()
})
};
if !infos.ty.matches(infos.array_size, e.format,
e.location.end - e.location.start)
{
return Err(IncompatibleVertexDefinitionError::FormatMismatch {
attribute: name.clone().into_owned(),
shader: (e.format, (e.location.end - e.location.start) as usize),
definition: (infos.ty, infos.array_size),
})
}
let mut offset = infos.offset;
for loc in e.location.clone() {
attribs.push((loc, 0, AttributeInfo { offset: offset, format: e.format }));
offset += e.format.size().unwrap();
}
}
attribs
}.into_iter(); // TODO: meh
let buffers = Some((0, mem::size_of::<T>(), InputRate::Vertex)).into_iter();
Ok((buffers, attrib))
}
}
unsafe impl<V> VertexSource<Vec<Arc<BufferAccess + Send + Sync>>> for SingleBufferDefinition<V>
where V: Vertex
{
#[inline]
fn decode<'l>(&self, source: &'l Vec<Arc<BufferAccess + Send + Sync>>) -> (Vec<BufferInner<'l>>, usize, usize) {
// FIXME: safety
assert_eq!(source.len(), 1);
let len = source[0].size() / mem::size_of::<V>();
(vec![source[0].inner()], len, 1)
}
}
unsafe impl<'a, B, V> VertexSource<B> for SingleBufferDefinition<V>
where B: TypedBufferAccess<Content = [V]>, V: Vertex
{
#[inline]
fn decode<'l>(&self, source: &'l B) -> (Vec<BufferInner<'l>>, usize, usize) {
(vec![source.inner()], source.len(), 1)
}
}

View File

@ -0,0 +1,105 @@
// Copyright (c) 2016 The vulkano developers
// Licensed under the Apache License, Version 2.0
// <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT
// license <LICENSE-MIT or http://opensource.org/licenses/MIT>,
// 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::marker::PhantomData;
use std::mem;
use std::sync::Arc;
use std::vec::IntoIter as VecIntoIter;
use buffer::BufferAccess;
use buffer::BufferInner;
use buffer::TypedBufferAccess;
use pipeline::shader::ShaderInterfaceDef;
use pipeline::vertex::AttributeInfo;
use pipeline::vertex::IncompatibleVertexDefinitionError;
use pipeline::vertex::InputRate;
use pipeline::vertex::Vertex;
use pipeline::vertex::VertexDefinition;
use pipeline::vertex::VertexSource;
/// Unstable.
// TODO: shouldn't be just `Two` but `Multi`
pub struct TwoBuffersDefinition<T, U>(pub PhantomData<(T, U)>);
impl<T, U> TwoBuffersDefinition<T, U> {
#[inline]
pub fn new() -> TwoBuffersDefinition<T, U> { TwoBuffersDefinition(PhantomData) }
}
unsafe impl<T, U, I> VertexDefinition<I> for TwoBuffersDefinition<T, U>
where T: Vertex, U: Vertex, I: ShaderInterfaceDef
{
type BuffersIter = VecIntoIter<(u32, usize, InputRate)>;
type AttribsIter = VecIntoIter<(u32, u32, AttributeInfo)>;
fn definition(&self, interface: &I) -> Result<(Self::BuffersIter, Self::AttribsIter),
IncompatibleVertexDefinitionError>
{
let attrib = {
let mut attribs = Vec::with_capacity(interface.elements().len());
for e in interface.elements() {
let name = e.name.as_ref().unwrap();
let (infos, buf_offset) = if let Some(infos) = <T as Vertex>::member(name) {
(infos, 0)
} else if let Some(infos) = <U as Vertex>::member(name) {
(infos, 1)
} else {
return Err(IncompatibleVertexDefinitionError::MissingAttribute {
attribute: name.clone().into_owned()
});
};
if !infos.ty.matches(infos.array_size, e.format,
e.location.end - e.location.start)
{
return Err(IncompatibleVertexDefinitionError::FormatMismatch {
attribute: name.clone().into_owned(),
shader: (e.format, (e.location.end - e.location.start) as usize),
definition: (infos.ty, infos.array_size),
})
}
let mut offset = infos.offset;
for loc in e.location.clone() {
attribs.push((loc, buf_offset, AttributeInfo { offset: offset, format: e.format }));
offset += e.format.size().unwrap();
}
}
attribs
}.into_iter(); // TODO: meh
let buffers = vec![
(0, mem::size_of::<T>(), InputRate::Vertex),
(1, mem::size_of::<U>(), InputRate::Vertex)
].into_iter();
Ok((buffers, attrib))
}
}
unsafe impl<T, U> VertexSource<Vec<Arc<BufferAccess + Send + Sync>>> for TwoBuffersDefinition<T, U>
where T: Vertex, U: Vertex
{
#[inline]
fn decode<'l>(&self, source: &'l Vec<Arc<BufferAccess + Send + Sync>>) -> (Vec<BufferInner<'l>>, usize, usize) {
unimplemented!() // FIXME: implement
}
}
unsafe impl<'a, T, U, Bt, Bu> VertexSource<(Bt, Bu)> for TwoBuffersDefinition<T, U>
where T: Vertex, Bt: TypedBufferAccess<Content = [T]>,
U: Vertex, Bu: TypedBufferAccess<Content = [U]>
{
#[inline]
fn decode<'l>(&self, source: &'l (Bt, Bu)) -> (Vec<BufferInner<'l>>, usize, usize) {
let vertices = [source.0.len(), source.1.len()].iter().cloned().min().unwrap();
(vec![source.0.inner(), source.1.inner()], vertices, 1)
}
}

View File

@ -0,0 +1,76 @@
// Copyright (c) 2017 The vulkano developers
// Licensed under the Apache License, Version 2.0
// <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT
// license <LICENSE-MIT or http://opensource.org/licenses/MIT>,
// at your option. All files in the project carrying such
// notice may not be copied, modified, or distributed except
// according to those terms.
use format::Format;
/// 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 binded depends on the shader.
pub unsafe trait Vertex: 'static + Send + Sync {
/// Returns the characteristics of a vertex member by its name.
fn member(name: &str) -> Option<VertexMemberInfo>;
}
unsafe impl Vertex for () {
#[inline]
fn member(_: &str) -> Option<VertexMemberInfo> {
None
}
}
/// Information about a member of a vertex struct.
pub struct VertexMemberInfo {
/// Offset of the member in bytes from the start of the struct.
pub offset: usize,
/// Type of data. This is used to check that the interface is matching.
pub ty: VertexMemberTy,
/// Number of consecutive elements of that type.
pub array_size: usize,
}
/// Type of a member of a vertex struct.
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
#[allow(missing_docs)]
pub enum VertexMemberTy {
I8,
U8,
I16,
U16,
I32,
U32,
F32,
F64,
}
impl VertexMemberTy {
/// Returns true if a combination of `(type, array_size)` matches a format.
#[inline]
pub fn matches(&self, array_size: usize, format: Format, num_locs: u32) -> bool {
// TODO: implement correctly
let my_size = match *self {
VertexMemberTy::I8 => 1,
VertexMemberTy::U8 => 1,
VertexMemberTy::I16 => 2,
VertexMemberTy::U16 => 2,
VertexMemberTy::I32 => 4,
VertexMemberTy::U32 => 4,
VertexMemberTy::F32 => 4,
VertexMemberTy::F64 => 8,
};
let format_size = match format.size() {
None => return false,
Some(s) => s,
};
array_size * my_size == format_size * num_locs as usize
}
}

View File

@ -241,11 +241,11 @@ pub struct OcclusionQueriesPool {
impl OcclusionQueriesPool {
/// See the docs of new().
pub fn raw(device: &Arc<Device>, num_slots: u32)
pub fn raw(device: Arc<Device>, num_slots: u32)
-> Result<OcclusionQueriesPool, OomError>
{
Ok(OcclusionQueriesPool {
inner: match UnsafeQueryPool::new(device.clone(), QueryType::Occlusion, num_slots) {
inner: match UnsafeQueryPool::new(device, QueryType::Occlusion, num_slots) {
Ok(q) => q,
Err(QueryPoolCreationError::OomError(err)) => return Err(err),
Err(QueryPoolCreationError::PipelineStatisticsQueryFeatureNotEnabled) => {
@ -262,7 +262,7 @@ impl OcclusionQueriesPool {
/// - Panics if the device or host ran out of memory.
///
#[inline]
pub fn new(device: &Arc<Device>, num_slots: u32)
pub fn new(device: Arc<Device>, num_slots: u32)
-> Arc<OcclusionQueriesPool>
{
Arc::new(OcclusionQueriesPool::raw(device, num_slots).unwrap())
@ -292,7 +292,7 @@ mod tests {
#[test]
fn occlusion_create() {
let (device, _) = gfx_dev_and_queue!();
let _ = OcclusionQueriesPool::new(&device, 256);
let _ = OcclusionQueriesPool::new(device, 256);
}
#[test]

View File

@ -25,7 +25,7 @@
//! use vulkano::sampler::Sampler;
//!
//! # let device: std::sync::Arc<vulkano::device::Device> = return;
//! let _sampler = Sampler::simple_repeat_linear_no_mipmap(&device);
//! let _sampler = Sampler::simple_repeat_linear_no_mipmap(device.clone());
//! ```
//!
//! More detailed sampler creation:
@ -34,7 +34,8 @@
//! use vulkano::sampler;
//!
//! # let device: std::sync::Arc<vulkano::device::Device> = return;
//! let _sampler = sampler::Sampler::new(&device, sampler::Filter::Linear, sampler::Filter::Linear,
//! let _sampler = sampler::Sampler::new(device.clone(), sampler::Filter::Linear,
//! sampler::Filter::Linear,
//! sampler::MipmapMode::Nearest,
//! sampler::SamplerAddressMode::Repeat,
//! sampler::SamplerAddressMode::Repeat,
@ -98,7 +99,7 @@ impl Sampler {
/// - Panics if out of memory or the maximum number of samplers has exceeded.
///
#[inline]
pub fn simple_repeat_linear(device: &Arc<Device>) -> Arc<Sampler> {
pub fn simple_repeat_linear(device: Arc<Device>) -> Arc<Sampler> {
Sampler::new(device, Filter::Linear, Filter::Linear, MipmapMode::Linear,
SamplerAddressMode::Repeat, SamplerAddressMode::Repeat,
SamplerAddressMode::Repeat, 0.0, 1.0, 0.0, 1_000.0).unwrap()
@ -114,7 +115,7 @@ impl Sampler {
/// - Panics if out of memory or the maximum number of samplers has exceeded.
///
#[inline]
pub fn simple_repeat_linear_no_mipmap(device: &Arc<Device>) -> Arc<Sampler> {
pub fn simple_repeat_linear_no_mipmap(device: Arc<Device>) -> Arc<Sampler> {
Sampler::new(device, Filter::Linear, Filter::Linear, MipmapMode::Nearest,
SamplerAddressMode::Repeat, SamplerAddressMode::Repeat,
SamplerAddressMode::Repeat, 0.0, 1.0, 0.0, 1.0).unwrap()
@ -146,7 +147,7 @@ impl Sampler {
/// - Panics if `min_lod > max_lod`.
///
#[inline(always)]
pub fn new(device: &Arc<Device>, mag_filter: Filter, min_filter: Filter,
pub fn new(device: Arc<Device>, mag_filter: Filter, min_filter: Filter,
mipmap_mode: MipmapMode, address_u: SamplerAddressMode,
address_v: SamplerAddressMode, address_w: SamplerAddressMode, mip_lod_bias: f32,
max_anisotropy: f32, min_lod: f32, max_lod: f32)
@ -173,7 +174,7 @@ impl Sampler {
/// Same panic reasons as `new`.
///
#[inline(always)]
pub fn compare(device: &Arc<Device>, mag_filter: Filter, min_filter: Filter,
pub fn compare(device: Arc<Device>, mag_filter: Filter, min_filter: Filter,
mipmap_mode: MipmapMode, address_u: SamplerAddressMode,
address_v: SamplerAddressMode, address_w: SamplerAddressMode, mip_lod_bias: f32,
max_anisotropy: f32, min_lod: f32, max_lod: f32, compare: Compare)
@ -183,7 +184,7 @@ impl Sampler {
address_w, mip_lod_bias, max_anisotropy, min_lod, max_lod, Some(compare))
}
fn new_impl(device: &Arc<Device>, mag_filter: Filter, min_filter: Filter,
fn new_impl(device: Arc<Device>, mag_filter: Filter, min_filter: Filter,
mipmap_mode: MipmapMode, address_u: SamplerAddressMode,
address_v: SamplerAddressMode, address_w: SamplerAddressMode, mip_lod_bias: f32,
max_anisotropy: f32, min_lod: f32, max_lod: f32, compare: Option<Compare>)
@ -309,7 +310,7 @@ impl Sampler {
///
/// - Panics if multiple `ClampToBorder` values are passed and the border color is different.
///
pub fn unnormalized(device: &Arc<Device>, filter: Filter,
pub fn unnormalized(device: Arc<Device>, filter: Filter,
address_u: UnnormalizedSamplerAddressMode,
address_v: UnnormalizedSamplerAddressMode)
-> Result<Arc<Sampler>, SamplerCreationError>
@ -672,7 +673,7 @@ mod tests {
fn create_regular() {
let (device, queue) = gfx_dev_and_queue!();
let s = sampler::Sampler::new(&device, sampler::Filter::Linear, sampler::Filter::Linear,
let s = sampler::Sampler::new(device, sampler::Filter::Linear, sampler::Filter::Linear,
sampler::MipmapMode::Nearest,
sampler::SamplerAddressMode::Repeat,
sampler::SamplerAddressMode::Repeat,
@ -686,7 +687,7 @@ mod tests {
fn create_compare() {
let (device, queue) = gfx_dev_and_queue!();
let s = sampler::Sampler::compare(&device, sampler::Filter::Linear, sampler::Filter::Linear,
let s = sampler::Sampler::compare(device, sampler::Filter::Linear, sampler::Filter::Linear,
sampler::MipmapMode::Nearest,
sampler::SamplerAddressMode::Repeat,
sampler::SamplerAddressMode::Repeat,
@ -701,7 +702,7 @@ mod tests {
fn create_unnormalized() {
let (device, queue) = gfx_dev_and_queue!();
let s = sampler::Sampler::unnormalized(&device, sampler::Filter::Linear,
let s = sampler::Sampler::unnormalized(device, sampler::Filter::Linear,
sampler::UnnormalizedSamplerAddressMode::ClampToEdge,
sampler::UnnormalizedSamplerAddressMode::ClampToEdge)
.unwrap();
@ -713,13 +714,13 @@ mod tests {
#[test]
fn simple_repeat_linear() {
let (device, queue) = gfx_dev_and_queue!();
let _ = sampler::Sampler::simple_repeat_linear(&device);
let _ = sampler::Sampler::simple_repeat_linear(device);
}
#[test]
fn simple_repeat_linear_no_mipmap() {
let (device, queue) = gfx_dev_and_queue!();
let _ = sampler::Sampler::simple_repeat_linear_no_mipmap(&device);
let _ = sampler::Sampler::simple_repeat_linear_no_mipmap(device);
}
#[test]
@ -727,7 +728,7 @@ mod tests {
fn min_lod_inferior() {
let (device, queue) = gfx_dev_and_queue!();
let _ = sampler::Sampler::new(&device, sampler::Filter::Linear, sampler::Filter::Linear,
let _ = sampler::Sampler::new(device, sampler::Filter::Linear, sampler::Filter::Linear,
sampler::MipmapMode::Nearest,
sampler::SamplerAddressMode::Repeat,
sampler::SamplerAddressMode::Repeat,
@ -739,7 +740,7 @@ mod tests {
fn max_anisotropy() {
let (device, queue) = gfx_dev_and_queue!();
let _ = sampler::Sampler::new(&device, sampler::Filter::Linear, sampler::Filter::Linear,
let _ = sampler::Sampler::new(device, sampler::Filter::Linear, sampler::Filter::Linear,
sampler::MipmapMode::Nearest,
sampler::SamplerAddressMode::Repeat,
sampler::SamplerAddressMode::Repeat,
@ -754,7 +755,7 @@ mod tests {
let b1 = sampler::BorderColor::IntTransparentBlack;
let b2 = sampler::BorderColor::FloatOpaqueWhite;
let _ = sampler::Sampler::new(&device, sampler::Filter::Linear, sampler::Filter::Linear,
let _ = sampler::Sampler::new(device, sampler::Filter::Linear, sampler::Filter::Linear,
sampler::MipmapMode::Nearest,
sampler::SamplerAddressMode::ClampToBorder(b1),
sampler::SamplerAddressMode::ClampToBorder(b2),
@ -765,7 +766,7 @@ mod tests {
fn anisotropy_feature() {
let (device, queue) = gfx_dev_and_queue!();
let r = sampler::Sampler::new(&device, sampler::Filter::Linear, sampler::Filter::Linear,
let r = sampler::Sampler::new(device, sampler::Filter::Linear, sampler::Filter::Linear,
sampler::MipmapMode::Nearest,
sampler::SamplerAddressMode::Repeat,
sampler::SamplerAddressMode::Repeat,
@ -781,7 +782,7 @@ mod tests {
fn anisotropy_limit() {
let (device, queue) = gfx_dev_and_queue!(sampler_anisotropy);
let r = sampler::Sampler::new(&device, sampler::Filter::Linear, sampler::Filter::Linear,
let r = sampler::Sampler::new(device, sampler::Filter::Linear, sampler::Filter::Linear,
sampler::MipmapMode::Nearest,
sampler::SamplerAddressMode::Repeat,
sampler::SamplerAddressMode::Repeat,
@ -798,7 +799,7 @@ mod tests {
fn mip_lod_bias_limit() {
let (device, queue) = gfx_dev_and_queue!();
let r = sampler::Sampler::new(&device, sampler::Filter::Linear, sampler::Filter::Linear,
let r = sampler::Sampler::new(device, sampler::Filter::Linear, sampler::Filter::Linear,
sampler::MipmapMode::Nearest,
sampler::SamplerAddressMode::Repeat,
sampler::SamplerAddressMode::Repeat,
@ -815,7 +816,7 @@ mod tests {
fn sampler_mirror_clamp_to_edge_extension() {
let (device, queue) = gfx_dev_and_queue!();
let r = sampler::Sampler::new(&device, sampler::Filter::Linear, sampler::Filter::Linear,
let r = sampler::Sampler::new(device, sampler::Filter::Linear, sampler::Filter::Linear,
sampler::MipmapMode::Nearest,
sampler::SamplerAddressMode::MirrorClampToEdge,
sampler::SamplerAddressMode::MirrorClampToEdge,

View File

@ -0,0 +1,500 @@
// Copyright (c) 2016 The vulkano developers
// Licensed under the Apache License, Version 2.0
// <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT
// license <LICENSE-MIT or http://opensource.org/licenses/MIT>,
// at your option. All files in the project carrying such
// notice may not be copied, modified, or distributed except
// according to those terms.
use format::Format;
use image::ImageUsage;
use vk;
/// The capabilities of a surface when used by a physical device.
///
/// You have to match these capabilities when you create a swapchain.
#[derive(Clone, Debug)]
pub struct Capabilities {
/// Minimum number of images that must be present in the swapchain.
pub min_image_count: u32,
/// Maximum number of images that must be present in the swapchain, or `None` if there is no
/// maximum value. Note that "no maximum" doesn't mean that you can set a very high value, as
/// you may still get out of memory errors.
pub max_image_count: Option<u32>,
/// The current dimensions of the surface. `None` means that the surface's dimensions will
/// depend on the dimensions of the swapchain that you are going to create.
pub current_extent: Option<[u32; 2]>,
/// Minimum width and height of a swapchain that uses this surface.
pub min_image_extent: [u32; 2],
/// Maximum width and height of a swapchain that uses this surface.
pub max_image_extent: [u32; 2],
/// Maximum number of image layers if you create an image array. The minimum is 1.
pub max_image_array_layers: u32,
/// List of transforms supported for the swapchain.
pub supported_transforms: SupportedSurfaceTransforms,
/// Current transform used by the surface.
pub current_transform: SurfaceTransform,
/// List of composite alpha modes supports for the swapchain.
pub supported_composite_alpha: SupportedCompositeAlpha,
/// List of image usages that are supported for images of the swapchain. Only
/// the `color_attachment` usage is guaranteed to be supported.
pub supported_usage_flags: ImageUsage,
/// List of formats supported for the swapchain.
pub supported_formats: Vec<(Format, ColorSpace)>, // TODO: https://github.com/KhronosGroup/Vulkan-Docs/issues/207
/// List of present modes that are supported. `Fifo` is always guaranteed to be supported.
pub present_modes: SupportedPresentModes,
}
/// The way presenting a swapchain is accomplished.
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
#[repr(u32)]
pub enum PresentMode {
/// Immediately shows the image to the user. May result in visible tearing.
Immediate = vk::PRESENT_MODE_IMMEDIATE_KHR,
/// The action of presenting an image puts it in wait. When the next vertical blanking period
/// happens, the waiting image is effectively shown to the user. If an image is presented while
/// another one is waiting, it is replaced.
Mailbox = vk::PRESENT_MODE_MAILBOX_KHR,
/// The action of presenting an image adds it to a queue of images. At each vertical blanking
/// period, the queue is poped and an image is presented.
///
/// Guaranteed to be always supported.
///
/// This is the equivalent of OpenGL's `SwapInterval` with a value of 1.
Fifo = vk::PRESENT_MODE_FIFO_KHR,
/// Same as `Fifo`, except that if the queue was empty during the previous vertical blanking
/// period then it is equivalent to `Immediate`.
///
/// This is the equivalent of OpenGL's `SwapInterval` with a value of -1.
Relaxed = vk::PRESENT_MODE_FIFO_RELAXED_KHR,
}
/// List of `PresentMode`s that are supported.
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub struct SupportedPresentModes {
pub immediate: bool,
pub mailbox: bool,
pub fifo: bool,
pub relaxed: bool,
}
pub fn supported_present_modes_from_list<I>(elem: I) -> SupportedPresentModes
where I: Iterator<Item = vk::PresentModeKHR>
{
let mut result = SupportedPresentModes::none();
for e in elem {
match e {
vk::PRESENT_MODE_IMMEDIATE_KHR => result.immediate = true,
vk::PRESENT_MODE_MAILBOX_KHR => result.mailbox = true,
vk::PRESENT_MODE_FIFO_KHR => result.fifo = true,
vk::PRESENT_MODE_FIFO_RELAXED_KHR => result.relaxed = true,
_ => panic!("Wrong value for vk::PresentModeKHR")
}
}
result
}
impl SupportedPresentModes {
/// Builds a `SupportedPresentModes` with all fields set to false.
#[inline]
pub fn none() -> SupportedPresentModes {
SupportedPresentModes {
immediate: false,
mailbox: false,
fifo: false,
relaxed: false,
}
}
/// Returns true if the given present mode is in this list of supported modes.
#[inline]
pub fn supports(&self, mode: PresentMode) -> bool {
match mode {
PresentMode::Immediate => self.immediate,
PresentMode::Mailbox => self.mailbox,
PresentMode::Fifo => self.fifo,
PresentMode::Relaxed => self.relaxed,
}
}
/// Returns an iterator to the list of supported present modes.
#[inline]
pub fn iter(&self) -> SupportedPresentModesIter {
SupportedPresentModesIter(self.clone())
}
}
/// Enumeration of the `PresentMode`s that are supported.
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub struct SupportedPresentModesIter(SupportedPresentModes);
impl Iterator for SupportedPresentModesIter {
type Item = PresentMode;
#[inline]
fn next(&mut self) -> Option<PresentMode> {
if self.0.immediate { self.0.immediate = false; return Some(PresentMode::Immediate); }
if self.0.mailbox { self.0.mailbox = false; return Some(PresentMode::Mailbox); }
if self.0.fifo { self.0.fifo = false; return Some(PresentMode::Fifo); }
if self.0.relaxed { self.0.relaxed = false; return Some(PresentMode::Relaxed); }
None
}
}
/// A transformation to apply to the image before showing it on the screen.
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
#[repr(u32)]
pub enum SurfaceTransform {
/// Don't transform the image.
Identity = vk::SURFACE_TRANSFORM_IDENTITY_BIT_KHR,
/// Rotate 90 degrees.
Rotate90 = vk::SURFACE_TRANSFORM_ROTATE_90_BIT_KHR,
/// Rotate 180 degrees.
Rotate180 = vk::SURFACE_TRANSFORM_ROTATE_180_BIT_KHR,
/// Rotate 270 degrees.
Rotate270 = vk::SURFACE_TRANSFORM_ROTATE_270_BIT_KHR,
/// Mirror the image horizontally.
HorizontalMirror = vk::SURFACE_TRANSFORM_HORIZONTAL_MIRROR_BIT_KHR,
/// Mirror the image horizontally and rotate 90 degrees.
HorizontalMirrorRotate90 = vk::SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_90_BIT_KHR,
/// Mirror the image horizontally and rotate 180 degrees.
HorizontalMirrorRotate180 = vk::SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_180_BIT_KHR,
/// Mirror the image horizontally and rotate 270 degrees.
HorizontalMirrorRotate270 = vk::SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_270_BIT_KHR,
/// Let the operating system or driver implementation choose.
Inherit = vk::SURFACE_TRANSFORM_INHERIT_BIT_KHR,
}
/// How the alpha values of the pixels of the window are treated.
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
#[repr(u32)]
pub enum CompositeAlpha {
/// The alpha channel of the image is ignored. All the pixels are considered as if they have a
/// value of 1.0.
Opaque = vk::COMPOSITE_ALPHA_OPAQUE_BIT_KHR,
/// The alpha channel of the image is respected. The color channels are expected to have
/// already been multiplied by the alpha value.
PreMultiplied = vk::COMPOSITE_ALPHA_PRE_MULTIPLIED_BIT_KHR,
/// The alpha channel of the image is respected. The color channels will be multiplied by the
/// alpha value by the compositor before being added to what is behind.
PostMultiplied = vk::COMPOSITE_ALPHA_POST_MULTIPLIED_BIT_KHR,
/// Let the operating system or driver implementation choose.
Inherit = vk::COMPOSITE_ALPHA_INHERIT_BIT_KHR,
}
/// List of supported composite alpha modes.
///
/// See the docs of `CompositeAlpha`.
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
#[allow(missing_docs)]
pub struct SupportedCompositeAlpha {
pub opaque: bool,
pub pre_multiplied: bool,
pub post_multiplied: bool,
pub inherit: bool,
}
pub fn supported_composite_alpha_from_bits(val: u32) -> SupportedCompositeAlpha {
let mut result = SupportedCompositeAlpha::none();
if (val & vk::COMPOSITE_ALPHA_OPAQUE_BIT_KHR) != 0 { result.opaque = true; }
if (val & vk::COMPOSITE_ALPHA_PRE_MULTIPLIED_BIT_KHR) != 0 { result.pre_multiplied = true; }
if (val & vk::COMPOSITE_ALPHA_POST_MULTIPLIED_BIT_KHR) != 0 { result.post_multiplied = true; }
if (val & vk::COMPOSITE_ALPHA_INHERIT_BIT_KHR) != 0 { result.inherit = true; }
result
}
impl SupportedCompositeAlpha {
/// Builds a `SupportedCompositeAlpha` with all fields set to false.
#[inline]
pub fn none() -> SupportedCompositeAlpha {
SupportedCompositeAlpha {
opaque: false,
pre_multiplied: false,
post_multiplied: false,
inherit: false,
}
}
/// Returns true if the given `CompositeAlpha` is in this list.
#[inline]
pub fn supports(&self, value: CompositeAlpha) -> bool {
match value {
CompositeAlpha::Opaque => self.opaque,
CompositeAlpha::PreMultiplied => self.pre_multiplied,
CompositeAlpha::PostMultiplied => self.post_multiplied,
CompositeAlpha::Inherit => self.inherit,
}
}
/// Returns an iterator to the list of supported composite alpha.
#[inline]
pub fn iter(&self) -> SupportedCompositeAlphaIter {
SupportedCompositeAlphaIter(self.clone())
}
}
/// Enumeration of the `CompositeAlpha` that are supported.
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub struct SupportedCompositeAlphaIter(SupportedCompositeAlpha);
impl Iterator for SupportedCompositeAlphaIter {
type Item = CompositeAlpha;
#[inline]
fn next(&mut self) -> Option<CompositeAlpha> {
if self.0.opaque { self.0.opaque = false; return Some(CompositeAlpha::Opaque); }
if self.0.pre_multiplied { self.0.pre_multiplied = false; return Some(CompositeAlpha::PreMultiplied); }
if self.0.post_multiplied { self.0.post_multiplied = false; return Some(CompositeAlpha::PostMultiplied); }
if self.0.inherit { self.0.inherit = false; return Some(CompositeAlpha::Inherit); }
None
}
}
/// List of supported composite alpha modes.
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub struct SupportedSurfaceTransforms {
pub identity: bool,
pub rotate90: bool,
pub rotate180: bool,
pub rotate270: bool,
pub horizontal_mirror: bool,
pub horizontal_mirror_rotate90: bool,
pub horizontal_mirror_rotate180: bool,
pub horizontal_mirror_rotate270: bool,
pub inherit: bool,
}
pub fn surface_transforms_from_bits(val: vk::SurfaceTransformFlagsKHR) -> SupportedSurfaceTransforms {
macro_rules! v {
($val:expr, $out:ident, $e:expr, $f:ident) => (
if ($val & $e) != 0 { $out.$f = true; }
);
}
let mut result = SupportedSurfaceTransforms::none();
v!(val, result, vk::SURFACE_TRANSFORM_IDENTITY_BIT_KHR, identity);
v!(val, result, vk::SURFACE_TRANSFORM_ROTATE_90_BIT_KHR, rotate90);
v!(val, result, vk::SURFACE_TRANSFORM_ROTATE_180_BIT_KHR, rotate180);
v!(val, result, vk::SURFACE_TRANSFORM_ROTATE_270_BIT_KHR, rotate270);
v!(val, result, vk::SURFACE_TRANSFORM_HORIZONTAL_MIRROR_BIT_KHR, horizontal_mirror);
v!(val, result, vk::SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_90_BIT_KHR,
horizontal_mirror_rotate90);
v!(val, result, vk::SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_180_BIT_KHR,
horizontal_mirror_rotate180);
v!(val, result, vk::SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_270_BIT_KHR,
horizontal_mirror_rotate270);
v!(val, result, vk::SURFACE_TRANSFORM_INHERIT_BIT_KHR, inherit);
result
}
impl SupportedSurfaceTransforms {
/// Builds a `SupportedSurfaceTransforms` with all fields set to false.
#[inline]
pub fn none() -> SupportedSurfaceTransforms {
SupportedSurfaceTransforms {
identity: false,
rotate90: false,
rotate180: false,
rotate270: false,
horizontal_mirror: false,
horizontal_mirror_rotate90: false,
horizontal_mirror_rotate180: false,
horizontal_mirror_rotate270: false,
inherit: false,
}
}
/// Returns true if the given `SurfaceTransform` is in this list.
#[inline]
pub fn supports(&self, value: SurfaceTransform) -> bool {
match value {
SurfaceTransform::Identity => self.identity,
SurfaceTransform::Rotate90 => self.rotate90,
SurfaceTransform::Rotate180 => self.rotate180,
SurfaceTransform::Rotate270 => self.rotate270,
SurfaceTransform::HorizontalMirror => self.horizontal_mirror,
SurfaceTransform::HorizontalMirrorRotate90 => self.horizontal_mirror_rotate90,
SurfaceTransform::HorizontalMirrorRotate180 => self.horizontal_mirror_rotate180,
SurfaceTransform::HorizontalMirrorRotate270 => self.horizontal_mirror_rotate270,
SurfaceTransform::Inherit => self.inherit,
}
}
/// Returns an iterator to the list of supported composite alpha.
#[inline]
pub fn iter(&self) -> SupportedSurfaceTransformsIter {
SupportedSurfaceTransformsIter(self.clone())
}
}
/// Enumeration of the `SurfaceTransform` that are supported.
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub struct SupportedSurfaceTransformsIter(SupportedSurfaceTransforms);
impl Iterator for SupportedSurfaceTransformsIter {
type Item = SurfaceTransform;
#[inline]
fn next(&mut self) -> Option<SurfaceTransform> {
if self.0.identity { self.0.identity = false; return Some(SurfaceTransform::Identity); }
if self.0.rotate90 { self.0.rotate90 = false; return Some(SurfaceTransform::Rotate90); }
if self.0.rotate180 { self.0.rotate180 = false; return Some(SurfaceTransform::Rotate180); }
if self.0.rotate270 { self.0.rotate270 = false; return Some(SurfaceTransform::Rotate270); }
if self.0.horizontal_mirror { self.0.horizontal_mirror = false; return Some(SurfaceTransform::HorizontalMirror); }
if self.0.horizontal_mirror_rotate90 { self.0.horizontal_mirror_rotate90 = false; return Some(SurfaceTransform::HorizontalMirrorRotate90); }
if self.0.horizontal_mirror_rotate180 { self.0.horizontal_mirror_rotate180 = false; return Some(SurfaceTransform::HorizontalMirrorRotate180); }
if self.0.horizontal_mirror_rotate270 { self.0.horizontal_mirror_rotate270 = false; return Some(SurfaceTransform::HorizontalMirrorRotate270); }
if self.0.inherit { self.0.inherit = false; return Some(SurfaceTransform::Inherit); }
None
}
}
impl Default for SurfaceTransform {
#[inline]
fn default() -> SurfaceTransform {
SurfaceTransform::Identity
}
}
/// How the presentation engine should interpret the data.
///
/// # A quick lesson about color spaces
///
/// ## What is a color space?
///
/// Each pixel of a monitor is made of three components: one red, one green, and one blue. In the
/// past, computers would simply send to the monitor the intensity of each of the three components.
///
/// This proved to be problematic, because depending on the brand of the monitor the colors would
/// not exactly be the same. For example on some monitors, a value of `[1.0, 0.0, 0.0]` would be a
/// bit more orange than on others.
///
/// In order to standardize this, there exist what are called *color spaces*: sRGB, AdobeRGB,
/// DCI-P3, scRGB, etc. When you manipulate RGB values in a specific color space, these values have
/// a precise absolute meaning in terms of color, that is the same across all systems and monitors.
///
/// > **Note**: Color spaces are orthogonal to concept of RGB. *RGB* only indicates what is the
/// > representation of the data, but not how it is interpreted. You can think of this a bit like
/// > text encoding. An *RGB* value is a like a byte, in other words it is the medium by which
/// > values are communicated, and a *color space* is like a text encoding (eg. UTF-8), in other
/// > words it is the way the value should be interpreted.
///
/// The most commonly used color space today is sRGB. Most monitors today use this color space,
/// and most images files are encoded in this color space.
///
/// ## Pixel formats and linear vs non-linear
///
/// In Vulkan all images have a specific format in which the data is stored. The data of an image
/// consists of pixels in RGB but contains no information about the color space (or lack thereof)
/// of these pixels. You are free to store them in whatever color space you want.
///
/// But one big practical problem with color spaces is that they are sometimes not linear, and in
/// particular the popular sRGB color space is not linear. In a non-linear color space, a value of
/// `[0.6, 0.6, 0.6]` for example is **not** twice as bright as a value of `[0.3, 0.3, 0.3]`. This
/// is problematic, because operations such as taking the average of two colors or calculating the
/// lighting of a texture with a dot product are mathematically incorrect and will produce
/// incorrect colors.
///
/// > **Note**: If the texture format has an alpha component, it is not affected by the color space
/// > and always behaves linearly.
///
/// In order to solve this Vulkan also provides image formats with the `Srgb` suffix, which are
/// expected to contain RGB data in the sRGB color space. When you sample an image with such a
/// format from a shader, the implementation will automatically turn the pixel values into a linear
/// color space that is suitable for linear operations (such as additions or multiplications).
/// When you write to a framebuffer attachment with such a format, the implementation will
/// automatically perform the opposite conversion. These conversions are most of the time performed
/// by the hardware and incur no additional cost.
///
/// ## Color space of the swapchain
///
/// The color space that you specify when you create a swapchain is how the implementation will
/// interpret the raw data inside of the image.
///
/// > **Note**: The implementation can choose to send the data in the swapchain image directly to
/// > the monitor, but it can also choose to write it in an intermediary buffer that is then read
/// > by the operating system or windowing system. Therefore the color space that the
/// > implementation supports is not necessarily the same as the one supported by the monitor.
///
/// It is *your* job to ensure that the data in the swapchain image is in the color space
/// that is specified here, otherwise colors will be incorrect.
/// The implementation will never perform any additional automatic conversion after the colors have
/// been written to the swapchain image.
///
/// # How do I handle this correctly?
///
/// The easiest way to handle color spaces in a cross-platform program is:
///
/// - Always request the `SrgbNonLinear` color space when creating the swapchain.
/// - Make sure that all your image files use the sRGB color space, and load them in images whose
/// format has the `Srgb` suffix. Only use non-sRGB image formats for intermediary computations
/// or to store non-color data.
/// - Swapchain images should have a format with the `Srgb` suffix.
///
/// > **Note**: It is unclear whether the `SrgbNonLinear` color space is always supported by the
/// > the implementation or not. See https://github.com/KhronosGroup/Vulkan-Docs/issues/442.
///
/// > **Note**: Lots of developers are confused by color spaces. You can sometimes find articles
/// > talking about gamma correction and suggestion to put your colors to the power 2.2 for
/// > example. These are all hacks and you should use the sRGB pixel formats intead.
///
/// If you follow these three rules, then everything should render the same way on all platforms.
///
/// Additionally you can try detect whether the implementation supports any additional color space
/// and perform a manual conversion to that color space from inside your shader.
///
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
#[repr(u32)]
pub enum ColorSpace {
SrgbNonLinear = vk::COLOR_SPACE_SRGB_NONLINEAR_KHR,
DisplayP3Linear = vk::COLOR_SPACE_DISPLAY_P3_LINEAR_EXT,
DisplayP3NonLinear = vk::COLOR_SPACE_DISPLAY_P3_NONLINEAR_EXT,
ScrgbLinear = vk::COLOR_SPACE_SCRGB_LINEAR_EXT,
ScrgbNonLinear = vk::COLOR_SPACE_SCRGB_NONLINEAR_EXT,
DciP3Linear = vk::COLOR_SPACE_DCI_P3_LINEAR_EXT,
DciP3NonLinear = vk::COLOR_SPACE_DCI_P3_NONLINEAR_EXT,
Bt709Linear = vk::COLOR_SPACE_BT709_LINEAR_EXT,
Bt709NonLinear = vk::COLOR_SPACE_BT709_NONLINEAR_EXT,
Bt2020Linear = vk::COLOR_SPACE_BT2020_LINEAR_EXT,
Bt2020NonLinear = vk::COLOR_SPACE_BT2020_NONLINEAR_EXT,
AdobeRgbLinear = vk::COLOR_SPACE_ADOBERGB_LINEAR_EXT,
AdobeRgbNonLinear = vk::COLOR_SPACE_ADOBERGB_NONLINEAR_EXT,
}
#[inline]
pub fn color_space_from_num(val: u32) -> ColorSpace {
match val {
vk::COLOR_SPACE_SRGB_NONLINEAR_KHR => ColorSpace::SrgbNonLinear,
vk::COLOR_SPACE_DISPLAY_P3_LINEAR_EXT => ColorSpace::DisplayP3Linear,
vk::COLOR_SPACE_DISPLAY_P3_NONLINEAR_EXT => ColorSpace::DisplayP3NonLinear,
vk::COLOR_SPACE_SCRGB_LINEAR_EXT => ColorSpace::ScrgbLinear,
vk::COLOR_SPACE_SCRGB_NONLINEAR_EXT => ColorSpace::ScrgbNonLinear,
vk::COLOR_SPACE_DCI_P3_LINEAR_EXT => ColorSpace::DciP3Linear,
vk::COLOR_SPACE_DCI_P3_NONLINEAR_EXT => ColorSpace::DciP3NonLinear,
vk::COLOR_SPACE_BT709_LINEAR_EXT => ColorSpace::Bt709Linear,
vk::COLOR_SPACE_BT709_NONLINEAR_EXT => ColorSpace::Bt709NonLinear,
vk::COLOR_SPACE_BT2020_LINEAR_EXT => ColorSpace::Bt2020Linear,
vk::COLOR_SPACE_BT2020_NONLINEAR_EXT => ColorSpace::Bt2020NonLinear,
vk::COLOR_SPACE_ADOBERGB_LINEAR_EXT => ColorSpace::AdobeRgbLinear,
vk::COLOR_SPACE_ADOBERGB_NONLINEAR_EXT => ColorSpace::AdobeRgbNonLinear,
_ => panic!("Wrong value for color space enum")
}
}

View File

@ -35,6 +35,7 @@ use std::vec::IntoIter;
use instance::Instance;
use instance::PhysicalDevice;
use swapchain::capabilities;
use swapchain::SupportedSurfaceTransforms;
use check_errors;
@ -233,7 +234,7 @@ impl Display {
/// Returns the transforms supported by this display.
#[inline]
pub fn supported_transforms(&self) -> SupportedSurfaceTransforms {
SupportedSurfaceTransforms::from_bits(self.properties.supportedTransforms)
capabilities::surface_transforms_from_bits(self.properties.supportedTransforms)
}
/// Returns true if TODO.

View File

@ -72,10 +72,10 @@
//! };
//!
//! # fn build_window() -> *const u32 { ptr::null() }
//! let window = build_window();
//! let window = build_window(); // Third-party function, not provided by vulkano
//! let _surface = unsafe {
//! let hinstance: *const () = ptr::null(); // Windows-specific object
//! Surface::from_hwnd(&instance, hinstance, window).unwrap()
//! Surface::from_hwnd(instance.clone(), hinstance, window).unwrap()
//! };
//! ```
//!
@ -124,7 +124,7 @@
//! Once you created a swapchain and retreived all the images that belong to it (see previous
//! section), you can draw on it. This is done in three steps:
//!
//! - Call `Swapchain::acquire_next_image`. This function will return the index of the image
//! - Call `swapchain::acquire_next_image`. This function will return the index of the image
//! (within the list returned by `Swapchain::new`) that is available to draw, plus a future
//! representing the moment when the GPU will gain access to that image.
//! - Draw on that image just like you would draw to any other image (see the documentation of
@ -136,9 +136,9 @@
//!
//! TODO: add example here
//! loop {
//! let index = swapchain.acquire_next_image(Duration::from_millis(500)).unwrap();
//! let index = swapchain::acquire_next_image(Duration::from_millis(500)).unwrap();
//! draw(images[index]);
//! swapchain.present(queue, index).unwrap();
//! swapchain::present(queue, index).unwrap();
//! }
//!
//! ## Recreating a swapchain
@ -156,6 +156,7 @@
//!
//! ```
//! # use std::time::Duration;
//! use vulkano::swapchain;
//! use vulkano::swapchain::AcquireError;
//! use vulkano::sync::GpuFuture;
//!
@ -172,7 +173,7 @@
//!
//! let (ref swapchain, ref _images) = swapchain;
//!
//! let (index, acq_future) = match swapchain.acquire_next_image(Duration::from_millis(500)) {
//! let (index, acq_future) = match swapchain::acquire_next_image(swapchain.clone(), Duration::from_millis(500)) {
//! Ok(r) => r,
//! Err(AcquireError::OutOfDate) => { recreate_swapchain = true; continue; },
//! Err(err) => panic!("{:?}", err)
@ -191,137 +192,35 @@
//!
use std::sync::atomic::AtomicBool;
use vk;
pub use self::surface::Capabilities;
pub use self::capabilities::Capabilities;
pub use self::capabilities::PresentMode;
pub use self::capabilities::SupportedPresentModes;
pub use self::capabilities::SupportedPresentModesIter;
pub use self::capabilities::SurfaceTransform;
pub use self::capabilities::CompositeAlpha;
pub use self::capabilities::SupportedCompositeAlpha;
pub use self::capabilities::SupportedCompositeAlphaIter;
pub use self::capabilities::ColorSpace;
pub use self::capabilities::SupportedSurfaceTransforms;
pub use self::capabilities::SupportedSurfaceTransformsIter;
pub use self::surface::Surface;
pub use self::surface::PresentMode;
pub use self::surface::SupportedPresentModes;
pub use self::surface::SupportedPresentModesIter;
pub use self::surface::SurfaceTransform;
pub use self::surface::CompositeAlpha;
pub use self::surface::SupportedCompositeAlpha;
pub use self::surface::SupportedCompositeAlphaIter;
pub use self::surface::ColorSpace;
pub use self::surface::SurfaceCreationError;
pub use self::swapchain::AcquireError;
pub use self::swapchain::PresentFuture;
pub use self::swapchain::Swapchain;
pub use self::swapchain::SwapchainAcquireFuture;
pub use self::swapchain::acquire_next_image;
pub use self::swapchain::present;
mod capabilities;
pub mod display;
mod surface;
mod swapchain;
/// List of supported composite alpha modes.
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub struct SupportedSurfaceTransforms {
pub identity: bool,
pub rotate90: bool,
pub rotate180: bool,
pub rotate270: bool,
pub horizontal_mirror: bool,
pub horizontal_mirror_rotate90: bool,
pub horizontal_mirror_rotate180: bool,
pub horizontal_mirror_rotate270: bool,
pub inherit: bool,
}
impl SupportedSurfaceTransforms {
/// Builds a `SupportedSurfaceTransforms` with all fields set to false.
#[inline]
pub fn none() -> SupportedSurfaceTransforms {
SupportedSurfaceTransforms {
identity: false,
rotate90: false,
rotate180: false,
rotate270: false,
horizontal_mirror: false,
horizontal_mirror_rotate90: false,
horizontal_mirror_rotate180: false,
horizontal_mirror_rotate270: false,
inherit: false,
}
}
#[inline]
fn from_bits(val: vk::SurfaceTransformFlagsKHR) -> SupportedSurfaceTransforms {
macro_rules! v {
($val:expr, $out:ident, $e:expr, $f:ident) => (
if ($val & $e) != 0 { $out.$f = true; }
);
}
let mut result = SupportedSurfaceTransforms::none();
v!(val, result, vk::SURFACE_TRANSFORM_IDENTITY_BIT_KHR, identity);
v!(val, result, vk::SURFACE_TRANSFORM_ROTATE_90_BIT_KHR, rotate90);
v!(val, result, vk::SURFACE_TRANSFORM_ROTATE_180_BIT_KHR, rotate180);
v!(val, result, vk::SURFACE_TRANSFORM_ROTATE_270_BIT_KHR, rotate270);
v!(val, result, vk::SURFACE_TRANSFORM_HORIZONTAL_MIRROR_BIT_KHR, horizontal_mirror);
v!(val, result, vk::SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_90_BIT_KHR,
horizontal_mirror_rotate90);
v!(val, result, vk::SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_180_BIT_KHR,
horizontal_mirror_rotate180);
v!(val, result, vk::SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_270_BIT_KHR,
horizontal_mirror_rotate270);
v!(val, result, vk::SURFACE_TRANSFORM_INHERIT_BIT_KHR, inherit);
result
}
/// Returns true if the given `SurfaceTransform` is in this list.
#[inline]
pub fn supports(&self, value: SurfaceTransform) -> bool {
match value {
SurfaceTransform::Identity => self.identity,
SurfaceTransform::Rotate90 => self.rotate90,
SurfaceTransform::Rotate180 => self.rotate180,
SurfaceTransform::Rotate270 => self.rotate270,
SurfaceTransform::HorizontalMirror => self.horizontal_mirror,
SurfaceTransform::HorizontalMirrorRotate90 => self.horizontal_mirror_rotate90,
SurfaceTransform::HorizontalMirrorRotate180 => self.horizontal_mirror_rotate180,
SurfaceTransform::HorizontalMirrorRotate270 => self.horizontal_mirror_rotate270,
SurfaceTransform::Inherit => self.inherit,
}
}
/// Returns an iterator to the list of supported composite alpha.
#[inline]
pub fn iter(&self) -> SupportedSurfaceTransformsIter {
SupportedSurfaceTransformsIter(self.clone())
}
}
/// Enumeration of the `SurfaceTransform` that are supported.
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub struct SupportedSurfaceTransformsIter(SupportedSurfaceTransforms);
impl Iterator for SupportedSurfaceTransformsIter {
type Item = SurfaceTransform;
#[inline]
fn next(&mut self) -> Option<SurfaceTransform> {
if self.0.identity { self.0.identity = false; return Some(SurfaceTransform::Identity); }
if self.0.rotate90 { self.0.rotate90 = false; return Some(SurfaceTransform::Rotate90); }
if self.0.rotate180 { self.0.rotate180 = false; return Some(SurfaceTransform::Rotate180); }
if self.0.rotate270 { self.0.rotate270 = false; return Some(SurfaceTransform::Rotate270); }
if self.0.horizontal_mirror { self.0.horizontal_mirror = false; return Some(SurfaceTransform::HorizontalMirror); }
if self.0.horizontal_mirror_rotate90 { self.0.horizontal_mirror_rotate90 = false; return Some(SurfaceTransform::HorizontalMirrorRotate90); }
if self.0.horizontal_mirror_rotate180 { self.0.horizontal_mirror_rotate180 = false; return Some(SurfaceTransform::HorizontalMirrorRotate180); }
if self.0.horizontal_mirror_rotate270 { self.0.horizontal_mirror_rotate270 = false; return Some(SurfaceTransform::HorizontalMirrorRotate270); }
if self.0.inherit { self.0.inherit = false; return Some(SurfaceTransform::Inherit); }
None
}
}
impl Default for SurfaceTransform {
#[inline]
fn default() -> SurfaceTransform {
SurfaceTransform::Identity
}
}
/// Internal trait so that creating/destroying a swapchain can access the surface's "has_swapchain"
/// flag.
// TODO: use pub(crate) maybe?
unsafe trait SurfaceSwapchainLock {
fn flag(&self) -> &AtomicBool;
}

View File

@ -16,12 +16,13 @@ use std::sync::Arc;
use std::sync::atomic::AtomicBool;
use format::Format;
use image::Usage as ImageUsage;
use image::ImageUsage;
use instance::Instance;
use instance::PhysicalDevice;
use instance::QueueFamily;
use swapchain::capabilities;
use swapchain::Capabilities;
use swapchain::SurfaceSwapchainLock;
use swapchain::SupportedSurfaceTransforms;
use swapchain::display::DisplayMode;
use swapchain::display::DisplayPlane;
@ -104,7 +105,7 @@ impl Surface {
///
/// The caller must ensure that the `hinstance` and the `hwnd` are both correct and stay
/// alive for the entire lifetime of the surface.
pub unsafe fn from_hwnd<T, U>(instance: &Arc<Instance>, hinstance: *const T, hwnd: *const U)
pub unsafe fn from_hwnd<T, U>(instance: Arc<Instance>, hinstance: *const T, hwnd: *const U)
-> Result<Arc<Surface>, SurfaceCreationError>
{
let vk = instance.pointers();
@ -143,7 +144,7 @@ impl Surface {
///
/// The caller must ensure that the `connection` and the `window` are both correct and stay
/// alive for the entire lifetime of the surface.
pub unsafe fn from_xcb<C>(instance: &Arc<Instance>, connection: *const C, window: u32)
pub unsafe fn from_xcb<C>(instance: Arc<Instance>, connection: *const C, window: u32)
-> Result<Arc<Surface>, SurfaceCreationError>
{
let vk = instance.pointers();
@ -182,7 +183,7 @@ impl Surface {
///
/// The caller must ensure that the `display` and the `window` are both correct and stay
/// alive for the entire lifetime of the surface.
pub unsafe fn from_xlib<D>(instance: &Arc<Instance>, display: *const D, window: c_ulong)
pub unsafe fn from_xlib<D>(instance: Arc<Instance>, display: *const D, window: c_ulong)
-> Result<Arc<Surface>, SurfaceCreationError>
{
let vk = instance.pointers();
@ -221,7 +222,7 @@ impl Surface {
///
/// The caller must ensure that the `display` and the `surface` are both correct and stay
/// alive for the entire lifetime of the surface.
pub unsafe fn from_wayland<D, S>(instance: &Arc<Instance>, display: *const D, surface: *const S)
pub unsafe fn from_wayland<D, S>(instance: Arc<Instance>, display: *const D, surface: *const S)
-> Result<Arc<Surface>, SurfaceCreationError>
{
let vk = instance.pointers();
@ -261,7 +262,7 @@ impl Surface {
///
/// The caller must ensure that the `connection` and the `surface` are both correct and stay
/// alive for the entire lifetime of the surface.
pub unsafe fn from_mir<C, S>(instance: &Arc<Instance>, connection: *const C, surface: *const S)
pub unsafe fn from_mir<C, S>(instance: Arc<Instance>, connection: *const C, surface: *const S)
-> Result<Arc<Surface>, SurfaceCreationError>
{
let vk = instance.pointers();
@ -298,7 +299,7 @@ impl Surface {
///
/// The caller must ensure that the `window` is correct and stays alive for the entire
/// lifetime of the surface.
pub unsafe fn from_anativewindow<T>(instance: &Arc<Instance>, window: *const T)
pub unsafe fn from_anativewindow<T>(instance: Arc<Instance>, window: *const T)
-> Result<Arc<Surface>, SurfaceCreationError>
{
let vk = instance.pointers();
@ -408,7 +409,7 @@ impl Surface {
///
/// The caller must ensure that the `window` is correct and stays alive for the entire
/// lifetime of the surface.
pub unsafe fn from_vi_surface<T>(instance: &Arc<Instance>, window: *const T)
pub unsafe fn from_vi_surface<T>(instance: Arc<Instance>, window: *const T)
-> Result<Arc<Surface>, SurfaceCreationError>
{
let vk = instance.pointers();
@ -439,7 +440,8 @@ impl Surface {
}
/// Returns true if the given queue family can draw on this surface.
pub fn is_supported(&self, queue: &QueueFamily) -> Result<bool, OomError> {
// FIXME: vulkano doesn't check this for the moment!
pub fn is_supported(&self, queue: QueueFamily) -> Result<bool, CapabilitiesError> {
unsafe {
let vk = self.instance.pointers();
@ -452,15 +454,22 @@ impl Surface {
}
}
#[deprecated = "Renamed to `capabilities`"]
#[inline]
pub fn get_capabilities(&self, device: &PhysicalDevice) -> Result<Capabilities, OomError> {
Ok(self.capabilities(*device).unwrap())
}
/// Retreives the capabilities of a surface when used by a certain device.
///
/// # Panic
///
/// - Panics if the device and the surface don't belong to the same instance.
///
pub fn get_capabilities(&self, device: &PhysicalDevice) -> Result<Capabilities, OomError> { // TODO: wrong error type
pub fn capabilities(&self, device: PhysicalDevice) -> Result<Capabilities, CapabilitiesError> {
unsafe {
assert_eq!(&*self.instance as *const _, &**device.instance() as *const _);
assert_eq!(&*self.instance as *const _, &**device.instance() as *const _,
"Instance mismatch in Surface::capabilities");
let vk = self.instance.pointers();
@ -510,7 +519,7 @@ impl Surface {
// https://bugs.freedesktop.org/show_bug.cgi?id=97153
// debug_assert!(modes.iter().find(|&&m| m == vk::PRESENT_MODE_FIFO_KHR).is_some());
debug_assert!(modes.iter().count() > 0);
SupportedPresentModes::from_list(modes.into_iter())
capabilities::supported_present_modes_from_list(modes.into_iter())
};
Ok(Capabilities {
@ -527,16 +536,16 @@ impl Surface {
min_image_extent: [caps.minImageExtent.width, caps.minImageExtent.height],
max_image_extent: [caps.maxImageExtent.width, caps.maxImageExtent.height],
max_image_array_layers: caps.maxImageArrayLayers,
supported_transforms: SupportedSurfaceTransforms::from_bits(caps.supportedTransforms),
current_transform: SupportedSurfaceTransforms::from_bits(caps.supportedTransforms).iter().next().unwrap(), // TODO:
supported_composite_alpha: SupportedCompositeAlpha::from_bits(caps.supportedCompositeAlpha),
supported_transforms: capabilities::surface_transforms_from_bits(caps.supportedTransforms),
current_transform: capabilities::surface_transforms_from_bits(caps.currentTransform).iter().next().unwrap(), // TODO:
supported_composite_alpha: capabilities::supported_composite_alpha_from_bits(caps.supportedCompositeAlpha),
supported_usage_flags: {
let usage = ImageUsage::from_bits(caps.supportedUsageFlags);
debug_assert!(usage.color_attachment); // specs say that this must be true
usage
},
supported_formats: formats.into_iter().map(|f| {
(Format::from_num(f.format).unwrap(), ColorSpace::from_num(f.colorSpace))
(Format::from_num(f.format).unwrap(), capabilities::color_space_from_num(f.colorSpace))
}).collect(),
present_modes: modes,
})
@ -634,386 +643,57 @@ impl From<Error> for SurfaceCreationError {
}
}
/// The capabilities of a surface when used by a physical device.
///
/// You have to match these capabilities when you create a swapchain.
#[derive(Clone, Debug)]
pub struct Capabilities {
/// Minimum number of images that must be present in the swapchain.
pub min_image_count: u32,
/// Maximum number of images that must be present in the swapchain, or `None` if there is no
/// maximum value. Note that "no maximum" doesn't mean that you can set a very high value, as
/// you may still get out of memory errors.
pub max_image_count: Option<u32>,
/// The current dimensions of the surface. `None` means that the surface's dimensions will
/// depend on the dimensions of the swapchain that you are going to create.
pub current_extent: Option<[u32; 2]>,
/// Minimum width and height of a swapchain that uses this surface.
pub min_image_extent: [u32; 2],
/// Maximum width and height of a swapchain that uses this surface.
pub max_image_extent: [u32; 2],
/// Maximum number of image layers if you create an image array. The minimum is 1.
pub max_image_array_layers: u32,
/// List of transforms supported for the swapchain.
pub supported_transforms: SupportedSurfaceTransforms,
/// Current transform used by the surface.
pub current_transform: SurfaceTransform,
/// List of composite alpha modes supports for the swapchain.
pub supported_composite_alpha: SupportedCompositeAlpha,
/// List of image usages that are supported for images of the swapchain. Only
/// the `color_attachment` usage is guaranteed to be supported.
pub supported_usage_flags: ImageUsage,
/// List of formats supported for the swapchain.
pub supported_formats: Vec<(Format, ColorSpace)>, // TODO: https://github.com/KhronosGroup/Vulkan-Docs/issues/207
/// List of present modes that are supported. `Fifo` is always guaranteed to be supported.
pub present_modes: SupportedPresentModes,
}
/// The way presenting a swapchain is accomplished.
/// Error that can happen when retreiving a surface's capabilities.
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
#[repr(u32)]
pub enum PresentMode {
/// Immediately shows the image to the user. May result in visible tearing.
Immediate = vk::PRESENT_MODE_IMMEDIATE_KHR,
pub enum CapabilitiesError {
/// Not enough memory.
OomError(OomError),
/// The action of presenting an image puts it in wait. When the next vertical blanking period
/// happens, the waiting image is effectively shown to the user. If an image is presented while
/// another one is waiting, it is replaced.
Mailbox = vk::PRESENT_MODE_MAILBOX_KHR,
/// The action of presenting an image adds it to a queue of images. At each vertical blanking
/// period, the queue is poped and an image is presented.
///
/// Guaranteed to be always supported.
///
/// This is the equivalent of OpenGL's `SwapInterval` with a value of 1.
Fifo = vk::PRESENT_MODE_FIFO_KHR,
/// Same as `Fifo`, except that if the queue was empty during the previous vertical blanking
/// period then it is equivalent to `Immediate`.
///
/// This is the equivalent of OpenGL's `SwapInterval` with a value of -1.
Relaxed = vk::PRESENT_MODE_FIFO_RELAXED_KHR,
/// The surface is no longer accessible and must be recreated.
SurfaceLost,
}
/// List of `PresentMode`s that are supported.
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub struct SupportedPresentModes {
pub immediate: bool,
pub mailbox: bool,
pub fifo: bool,
pub relaxed: bool,
}
impl SupportedPresentModes {
/// Builds a `SupportedPresentModes` with all fields set to false.
impl error::Error for CapabilitiesError {
#[inline]
pub fn none() -> SupportedPresentModes {
SupportedPresentModes {
immediate: false,
mailbox: false,
fifo: false,
relaxed: false,
fn description(&self) -> &str {
match *self {
CapabilitiesError::OomError(_) => "not enough memory",
CapabilitiesError::SurfaceLost => "the surface is no longer valid",
}
}
#[inline]
fn from_list<I>(elem: I) -> SupportedPresentModes where I: Iterator<Item = vk::PresentModeKHR> {
let mut result = SupportedPresentModes::none();
for e in elem {
match e {
vk::PRESENT_MODE_IMMEDIATE_KHR => result.immediate = true,
vk::PRESENT_MODE_MAILBOX_KHR => result.mailbox = true,
vk::PRESENT_MODE_FIFO_KHR => result.fifo = true,
vk::PRESENT_MODE_FIFO_RELAXED_KHR => result.relaxed = true,
_ => panic!("Wrong value for vk::PresentModeKHR")
}
}
result
}
/// Returns true if the given present mode is in this list of supported modes.
#[inline]
pub fn supports(&self, mode: PresentMode) -> bool {
match mode {
PresentMode::Immediate => self.immediate,
PresentMode::Mailbox => self.mailbox,
PresentMode::Fifo => self.fifo,
PresentMode::Relaxed => self.relaxed,
fn cause(&self) -> Option<&error::Error> {
match *self {
CapabilitiesError::OomError(ref err) => Some(err),
_ => None
}
}
}
/// Returns an iterator to the list of supported present modes.
impl fmt::Display for CapabilitiesError {
#[inline]
pub fn iter(&self) -> SupportedPresentModesIter {
SupportedPresentModesIter(self.clone())
fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
write!(fmt, "{}", error::Error::description(self))
}
}
/// Enumeration of the `PresentMode`s that are supported.
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub struct SupportedPresentModesIter(SupportedPresentModes);
impl Iterator for SupportedPresentModesIter {
type Item = PresentMode;
impl From<OomError> for CapabilitiesError {
#[inline]
fn next(&mut self) -> Option<PresentMode> {
if self.0.immediate { self.0.immediate = false; return Some(PresentMode::Immediate); }
if self.0.mailbox { self.0.mailbox = false; return Some(PresentMode::Mailbox); }
if self.0.fifo { self.0.fifo = false; return Some(PresentMode::Fifo); }
if self.0.relaxed { self.0.relaxed = false; return Some(PresentMode::Relaxed); }
None
fn from(err: OomError) -> CapabilitiesError {
CapabilitiesError::OomError(err)
}
}
/// A transformation to apply to the image before showing it on the screen.
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
#[repr(u32)]
pub enum SurfaceTransform {
/// Don't transform the image.
Identity = vk::SURFACE_TRANSFORM_IDENTITY_BIT_KHR,
/// Rotate 90 degrees.
Rotate90 = vk::SURFACE_TRANSFORM_ROTATE_90_BIT_KHR,
/// Rotate 180 degrees.
Rotate180 = vk::SURFACE_TRANSFORM_ROTATE_180_BIT_KHR,
/// Rotate 270 degrees.
Rotate270 = vk::SURFACE_TRANSFORM_ROTATE_270_BIT_KHR,
/// Mirror the image horizontally.
HorizontalMirror = vk::SURFACE_TRANSFORM_HORIZONTAL_MIRROR_BIT_KHR,
/// Mirror the image horizontally and rotate 90 degrees.
HorizontalMirrorRotate90 = vk::SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_90_BIT_KHR,
/// Mirror the image horizontally and rotate 180 degrees.
HorizontalMirrorRotate180 = vk::SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_180_BIT_KHR,
/// Mirror the image horizontally and rotate 270 degrees.
HorizontalMirrorRotate270 = vk::SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_270_BIT_KHR,
/// Let the operating system or driver implementation choose.
Inherit = vk::SURFACE_TRANSFORM_INHERIT_BIT_KHR,
}
/// How the alpha values of the pixels of the window are treated.
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
#[repr(u32)]
pub enum CompositeAlpha {
/// The alpha channel of the image is ignored. All the pixels are considered as if they have a
/// value of 1.0.
Opaque = vk::COMPOSITE_ALPHA_OPAQUE_BIT_KHR,
/// The alpha channel of the image is respected. The color channels are expected to have
/// already been multiplied by the alpha value.
PreMultiplied = vk::COMPOSITE_ALPHA_PRE_MULTIPLIED_BIT_KHR,
/// The alpha channel of the image is respected. The color channels will be multiplied by the
/// alpha value by the compositor before being added to what is behind.
PostMultiplied = vk::COMPOSITE_ALPHA_POST_MULTIPLIED_BIT_KHR,
/// Let the operating system or driver implementation choose.
Inherit = vk::COMPOSITE_ALPHA_INHERIT_BIT_KHR,
}
/// List of supported composite alpha modes.
///
/// See the docs of `CompositeAlpha`.
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
#[allow(missing_docs)]
pub struct SupportedCompositeAlpha {
pub opaque: bool,
pub pre_multiplied: bool,
pub post_multiplied: bool,
pub inherit: bool,
}
impl SupportedCompositeAlpha {
/// Builds a `SupportedCompositeAlpha` with all fields set to false.
impl From<Error> for CapabilitiesError {
#[inline]
pub fn none() -> SupportedCompositeAlpha {
SupportedCompositeAlpha {
opaque: false,
pre_multiplied: false,
post_multiplied: false,
inherit: false,
}
}
#[inline]
fn from_bits(val: u32) -> SupportedCompositeAlpha {
let mut result = SupportedCompositeAlpha::none();
if (val & vk::COMPOSITE_ALPHA_OPAQUE_BIT_KHR) != 0 { result.opaque = true; }
if (val & vk::COMPOSITE_ALPHA_PRE_MULTIPLIED_BIT_KHR) != 0 { result.pre_multiplied = true; }
if (val & vk::COMPOSITE_ALPHA_POST_MULTIPLIED_BIT_KHR) != 0 { result.post_multiplied = true; }
if (val & vk::COMPOSITE_ALPHA_INHERIT_BIT_KHR) != 0 { result.inherit = true; }
result
}
/// Returns true if the given `CompositeAlpha` is in this list.
#[inline]
pub fn supports(&self, value: CompositeAlpha) -> bool {
match value {
CompositeAlpha::Opaque => self.opaque,
CompositeAlpha::PreMultiplied => self.pre_multiplied,
CompositeAlpha::PostMultiplied => self.post_multiplied,
CompositeAlpha::Inherit => self.inherit,
}
}
/// Returns an iterator to the list of supported composite alpha.
#[inline]
pub fn iter(&self) -> SupportedCompositeAlphaIter {
SupportedCompositeAlphaIter(self.clone())
}
}
/// Enumeration of the `CompositeAlpha` that are supported.
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub struct SupportedCompositeAlphaIter(SupportedCompositeAlpha);
impl Iterator for SupportedCompositeAlphaIter {
type Item = CompositeAlpha;
#[inline]
fn next(&mut self) -> Option<CompositeAlpha> {
if self.0.opaque { self.0.opaque = false; return Some(CompositeAlpha::Opaque); }
if self.0.pre_multiplied { self.0.pre_multiplied = false; return Some(CompositeAlpha::PreMultiplied); }
if self.0.post_multiplied { self.0.post_multiplied = false; return Some(CompositeAlpha::PostMultiplied); }
if self.0.inherit { self.0.inherit = false; return Some(CompositeAlpha::Inherit); }
None
}
}
/// How the presentation engine should interpret the data.
///
/// # A quick lesson about color spaces
///
/// ## What is a color space?
///
/// Each pixel of a monitor is made of three components: one red, one green, and one blue. In the
/// past, computers would simply send to the monitor the intensity of each of the three components.
///
/// This proved to be problematic, because depending on the brand of the monitor the colors would
/// not exactly be the same. For example on some monitors, a value of `[1.0, 0.0, 0.0]` would be a
/// bit more orange than on others.
///
/// In order to standardize this, there exist what are called *color spaces*: sRGB, AdobeRGB,
/// DCI-P3, scRGB, etc. When you manipulate RGB values in a specific color space, these values have
/// a precise absolute meaning in terms of color, that is the same across all systems and monitors.
///
/// > **Note**: Color spaces are orthogonal to concept of RGB. *RGB* only indicates what is the
/// > representation of the data, but not how it is interpreted. You can think of this a bit like
/// > text encoding. An *RGB* value is a like a byte, in other words it is the medium by which
/// > values are communicated, and a *color space* is like a text encoding (eg. UTF-8), in other
/// > words it is the way the value should be interpreted.
///
/// The most commonly used color space today is sRGB. Most monitors today use this color space,
/// and most images files are encoded in this color space.
///
/// ## Pixel formats and linear vs non-linear
///
/// In Vulkan all images have a specific format in which the data is stored. The data of an image
/// consists of pixels in RGB but contains no information about the color space (or lack thereof)
/// of these pixels. You are free to store them in whatever color space you want.
///
/// But one big practical problem with color spaces is that they are sometimes not linear, and in
/// particular the popular sRGB color space is not linear. In a non-linear color space, a value of
/// `[0.6, 0.6, 0.6]` for example is **not** twice as bright as a value of `[0.3, 0.3, 0.3]`. This
/// is problematic, because operations such as taking the average of two colors or calculating the
/// lighting of a texture with a dot product are mathematically incorrect and will produce
/// incorrect colors.
///
/// > **Note**: If the texture format has an alpha component, it is not affected by the color space
/// > and always behaves linearly.
///
/// In order to solve this Vulkan also provides image formats with the `Srgb` suffix, which are
/// expected to contain RGB data in the sRGB color space. When you sample an image with such a
/// format from a shader, the implementation will automatically turn the pixel values into a linear
/// color space that is suitable for linear operations (such as additions or multiplications).
/// When you write to a framebuffer attachment with such a format, the implementation will
/// automatically perform the opposite conversion. These conversions are most of the time performed
/// by the hardware and incur no additional cost.
///
/// ## Color space of the swapchain
///
/// The color space that you specify when you create a swapchain is how the implementation will
/// interpret the raw data inside of the image.
///
/// > **Note**: The implementation can choose to send the data in the swapchain image directly to
/// > the monitor, but it can also choose to write it in an intermediary buffer that is then read
/// > by the operating system or windowing system. Therefore the color space that the
/// > implementation supports is not necessarily the same as the one supported by the monitor.
///
/// It is *your* job to ensure that the data in the swapchain image is in the color space
/// that is specified here, otherwise colors will be incorrect.
/// The implementation will never perform any additional automatic conversion after the colors have
/// been written to the swapchain image.
///
/// # How do I handle this correctly?
///
/// The easiest way to handle color spaces in a cross-platform program is:
///
/// - Always request the `SrgbNonLinear` color space when creating the swapchain.
/// - Make sure that all your image files use the sRGB color space, and load them in images whose
/// format has the `Srgb` suffix. Only use non-sRGB image formats for intermediary computations
/// or to store non-color data.
/// - Swapchain images should have a format with the `Srgb` suffix.
///
/// > **Note**: It is unclear whether the `SrgbNonLinear` color space is always supported by the
/// > the implementation or not. See https://github.com/KhronosGroup/Vulkan-Docs/issues/442.
///
/// > **Note**: Lots of developers are confused by color spaces. You can sometimes find articles
/// > talking about gamma correction and suggestion to put your colors to the power 2.2 for
/// > example. These are all hacks and you should use the sRGB pixel formats intead.
///
/// If you follow these three rules, then everything should render the same way on all platforms.
///
/// Additionally you can try detect whether the implementation supports any additional color space
/// and perform a manual conversion to that color space from inside your shader.
///
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
#[repr(u32)]
pub enum ColorSpace {
SrgbNonLinear = vk::COLOR_SPACE_SRGB_NONLINEAR_KHR,
DisplayP3Linear = vk::COLOR_SPACE_DISPLAY_P3_LINEAR_EXT,
DisplayP3NonLinear = vk::COLOR_SPACE_DISPLAY_P3_NONLINEAR_EXT,
ScrgbLinear = vk::COLOR_SPACE_SCRGB_LINEAR_EXT,
ScrgbNonLinear = vk::COLOR_SPACE_SCRGB_NONLINEAR_EXT,
DciP3Linear = vk::COLOR_SPACE_DCI_P3_LINEAR_EXT,
DciP3NonLinear = vk::COLOR_SPACE_DCI_P3_NONLINEAR_EXT,
Bt709Linear = vk::COLOR_SPACE_BT709_LINEAR_EXT,
Bt709NonLinear = vk::COLOR_SPACE_BT709_NONLINEAR_EXT,
Bt2020Linear = vk::COLOR_SPACE_BT2020_LINEAR_EXT,
Bt2020NonLinear = vk::COLOR_SPACE_BT2020_NONLINEAR_EXT,
AdobeRgbLinear = vk::COLOR_SPACE_ADOBERGB_LINEAR_EXT,
AdobeRgbNonLinear = vk::COLOR_SPACE_ADOBERGB_NONLINEAR_EXT,
}
impl ColorSpace {
#[inline]
fn from_num(val: u32) -> ColorSpace {
match val {
vk::COLOR_SPACE_SRGB_NONLINEAR_KHR => ColorSpace::SrgbNonLinear,
vk::COLOR_SPACE_DISPLAY_P3_LINEAR_EXT => ColorSpace::DisplayP3Linear,
vk::COLOR_SPACE_DISPLAY_P3_NONLINEAR_EXT => ColorSpace::DisplayP3NonLinear,
vk::COLOR_SPACE_SCRGB_LINEAR_EXT => ColorSpace::ScrgbLinear,
vk::COLOR_SPACE_SCRGB_NONLINEAR_EXT => ColorSpace::ScrgbNonLinear,
vk::COLOR_SPACE_DCI_P3_LINEAR_EXT => ColorSpace::DciP3Linear,
vk::COLOR_SPACE_DCI_P3_NONLINEAR_EXT => ColorSpace::DciP3NonLinear,
vk::COLOR_SPACE_BT709_LINEAR_EXT => ColorSpace::Bt709Linear,
vk::COLOR_SPACE_BT709_NONLINEAR_EXT => ColorSpace::Bt709NonLinear,
vk::COLOR_SPACE_BT2020_LINEAR_EXT => ColorSpace::Bt2020Linear,
vk::COLOR_SPACE_BT2020_NONLINEAR_EXT => ColorSpace::Bt2020NonLinear,
vk::COLOR_SPACE_ADOBERGB_LINEAR_EXT => ColorSpace::AdobeRgbLinear,
vk::COLOR_SPACE_ADOBERGB_NONLINEAR_EXT => ColorSpace::AdobeRgbNonLinear,
_ => panic!("Wrong value for color space enum")
fn from(err: Error) -> CapabilitiesError {
match err {
err @ Error::OutOfHostMemory => CapabilitiesError::OomError(OomError::from(err)),
err @ Error::OutOfDeviceMemory => CapabilitiesError::OomError(OomError::from(err)),
Error::SurfaceLost => CapabilitiesError::SurfaceLost,
_ => panic!("unexpected error: {:?}", err)
}
}
}
@ -1027,7 +707,7 @@ mod tests {
#[test]
fn khr_win32_surface_ext_missing() {
let instance = instance!();
match unsafe { Surface::from_hwnd(&instance, ptr::null::<u8>(), ptr::null::<u8>()) } {
match unsafe { Surface::from_hwnd(instance, ptr::null::<u8>(), ptr::null::<u8>()) } {
Err(SurfaceCreationError::MissingExtension { .. }) => (),
_ => panic!()
}
@ -1036,7 +716,7 @@ mod tests {
#[test]
fn khr_xcb_surface_ext_missing() {
let instance = instance!();
match unsafe { Surface::from_xcb(&instance, ptr::null::<u8>(), 0) } {
match unsafe { Surface::from_xcb(instance, ptr::null::<u8>(), 0) } {
Err(SurfaceCreationError::MissingExtension { .. }) => (),
_ => panic!()
}
@ -1045,7 +725,7 @@ mod tests {
#[test]
fn khr_xlib_surface_ext_missing() {
let instance = instance!();
match unsafe { Surface::from_xlib(&instance, ptr::null::<u8>(), 0) } {
match unsafe { Surface::from_xlib(instance, ptr::null::<u8>(), 0) } {
Err(SurfaceCreationError::MissingExtension { .. }) => (),
_ => panic!()
}
@ -1054,7 +734,7 @@ mod tests {
#[test]
fn khr_wayland_surface_ext_missing() {
let instance = instance!();
match unsafe { Surface::from_wayland(&instance, ptr::null::<u8>(), ptr::null::<u8>()) } {
match unsafe { Surface::from_wayland(instance, ptr::null::<u8>(), ptr::null::<u8>()) } {
Err(SurfaceCreationError::MissingExtension { .. }) => (),
_ => panic!()
}
@ -1063,7 +743,7 @@ mod tests {
#[test]
fn khr_mir_surface_ext_missing() {
let instance = instance!();
match unsafe { Surface::from_mir(&instance, ptr::null::<u8>(), ptr::null::<u8>()) } {
match unsafe { Surface::from_mir(instance, ptr::null::<u8>(), ptr::null::<u8>()) } {
Err(SurfaceCreationError::MissingExtension { .. }) => (),
_ => panic!()
}
@ -1072,7 +752,7 @@ mod tests {
#[test]
fn khr_android_surface_ext_missing() {
let instance = instance!();
match unsafe { Surface::from_anativewindow(&instance, ptr::null::<u8>()) } {
match unsafe { Surface::from_anativewindow(instance, ptr::null::<u8>()) } {
Err(SurfaceCreationError::MissingExtension { .. }) => (),
_ => panic!()
}

View File

@ -13,7 +13,6 @@ use std::mem;
use std::ptr;
use std::sync::Arc;
use std::sync::Mutex;
use std::sync::Weak;
use std::sync::atomic::AtomicBool;
use std::sync::atomic::Ordering;
use std::time::Duration;
@ -29,9 +28,9 @@ use format::Format;
use format::FormatDesc;
use image::ImageAccess;
use image::ImageDimensions;
use image::Layout;
use image::ImageLayout;
use image::ImageUsage;
use image::sys::UnsafeImage;
use image::sys::Usage as ImageUsage;
use image::swapchain::SwapchainImage;
use swapchain::ColorSpace;
use swapchain::CompositeAlpha;
@ -56,13 +55,101 @@ use VulkanObject;
use VulkanPointers;
use vk;
/// Tries to take ownership of an image in order to draw on it.
///
/// The function returns the index of the image in the array of images that was returned
/// when creating the swapchain, plus a future that represents the moment when the image will
/// become available from the GPU (which may not be *immediately*).
///
/// If you try to draw on an image without acquiring it first, the execution will block. (TODO
/// behavior may change).
// TODO: has to make sure vkQueuePresent is called, because calling acquire_next_image many
// times in a row is an error
// TODO: change timeout to `Option<Duration>`.
pub fn acquire_next_image(swapchain: Arc<Swapchain>, timeout: Duration)
-> Result<(usize, SwapchainAcquireFuture), AcquireError>
{
unsafe {
// Check that this is not an old swapchain. From specs:
// > swapchain must not have been replaced by being passed as the
// > VkSwapchainCreateInfoKHR::oldSwapchain value to vkCreateSwapchainKHR
let stale = swapchain.stale.lock().unwrap();
if *stale {
return Err(AcquireError::OutOfDate);
}
let vk = swapchain.device.pointers();
let semaphore = try!(Semaphore::new(swapchain.device.clone()));
let timeout_ns = timeout.as_secs().saturating_mul(1_000_000_000)
.saturating_add(timeout.subsec_nanos() as u64);
let mut out = mem::uninitialized();
let r = try!(check_errors(vk.AcquireNextImageKHR(swapchain.device.internal_object(),
swapchain.swapchain, timeout_ns,
semaphore.internal_object(), 0,
&mut out)));
let id = match r {
Success::Success => out as usize,
Success::Suboptimal => out as usize, // TODO: give that info to the user
Success::NotReady => return Err(AcquireError::Timeout),
Success::Timeout => return Err(AcquireError::Timeout),
s => panic!("unexpected success value: {:?}", s)
};
Ok((id, SwapchainAcquireFuture {
swapchain: swapchain.clone(), // TODO: don't clone
semaphore: semaphore,
image_id: id,
finished: AtomicBool::new(false),
}))
}
}
/// Presents an image on the screen.
///
/// The parameter is the same index as what `acquire_next_image` returned. The image must
/// have been acquired first.
///
/// The actual behavior depends on the present mode that you passed when creating the
/// swapchain.
pub fn present<F>(swapchain: Arc<Swapchain>, before: F, queue: Arc<Queue>, index: usize)
-> PresentFuture<F>
where F: GpuFuture
{
assert!(index < swapchain.images.len());
// TODO: restore this check with a dummy ImageAccess implementation
/*let swapchain_image = me.images.lock().unwrap().get(index).unwrap().0.upgrade().unwrap(); // TODO: return error instead
// Normally if `check_image_access` returns false we're supposed to call the `gpu_access`
// function on the image instead. But since we know that this method on `SwapchainImage`
// always returns false anyway (by design), we don't need to do it.
assert!(before.check_image_access(&swapchain_image, ImageLayout::PresentSrc, true, &queue).is_ok()); // TODO: return error instead*/
PresentFuture {
previous: before,
queue: queue,
swapchain: swapchain,
image_id: index,
flushed: AtomicBool::new(false),
finished: AtomicBool::new(false),
}
}
/// Contains the swapping system and the images that can be shown on a surface.
// TODO: #[derive(Debug)] (waiting on https://github.com/aturon/crossbeam/issues/62)
pub struct Swapchain {
// The Vulkan device this swapchain was created with.
device: Arc<Device>,
// The surface, which we need to keep alive.
surface: Arc<Surface>,
// The swapchain object.
swapchain: vk::SwapchainKHR,
// The images of this swapchain.
images: Vec<ImageEntry>,
// If true, that means we have used this swapchain to recreate a new swapchain. The current
// swapchain can no longer be used for anything except presenting already-acquired images.
//
@ -82,9 +169,12 @@ pub struct Swapchain {
alpha: CompositeAlpha,
mode: PresentMode,
clipped: bool,
}
// TODO: meh for Mutex
images: Mutex<Vec<(Weak<SwapchainImage>, bool)>>,
struct ImageEntry {
image: UnsafeImage,
// If true, then the image is still in the undefined layout and must be transitionned.
undefined_layout: AtomicBool,
}
impl Swapchain {
@ -110,9 +200,10 @@ impl Swapchain {
///
// TODO: remove `old_swapchain` parameter and add another function `with_old_swapchain`.
// TODO: add `ColorSpace` parameter
// TODO: isn't it unsafe to take the surface through an Arc when it comes to vulkano-win?
#[inline]
pub fn new<F, S>(device: &Arc<Device>, surface: &Arc<Surface>, num_images: u32, format: F,
dimensions: [u32; 2], layers: u32, usage: &ImageUsage, sharing: S,
pub fn new<F, S>(device: Arc<Device>, surface: Arc<Surface>, num_images: u32, format: F,
dimensions: [u32; 2], layers: u32, usage: ImageUsage, sharing: S,
transform: SurfaceTransform, alpha: CompositeAlpha, mode: PresentMode,
clipped: bool, old_swapchain: Option<&Arc<Swapchain>>)
-> Result<(Arc<Swapchain>, Vec<Arc<SwapchainImage>>), OomError>
@ -127,16 +218,14 @@ impl Swapchain {
pub fn recreate_with_dimension(&self, dimensions: [u32; 2])
-> Result<(Arc<Swapchain>, Vec<Arc<SwapchainImage>>), OomError>
{
Swapchain::new_inner(&self.device, &self.surface, self.num_images, self.format,
self.color_space, dimensions, self.layers, &self.usage,
Swapchain::new_inner(self.device.clone(), self.surface.clone(), self.num_images,
self.format, self.color_space, dimensions, self.layers, self.usage,
self.sharing.clone(), self.transform, self.alpha, self.mode,
self.clipped, Some(self))
}
// TODO: images layouts should always be set to "PRESENT", since we have no way to switch the
// layout at present time
fn new_inner(device: &Arc<Device>, surface: &Arc<Surface>, num_images: u32, format: Format,
color_space: ColorSpace, dimensions: [u32; 2], layers: u32, usage: &ImageUsage,
fn new_inner(device: Arc<Device>, surface: Arc<Surface>, num_images: u32, format: Format,
color_space: ColorSpace, dimensions: [u32; 2], layers: u32, usage: ImageUsage,
sharing: SharingMode, transform: SurfaceTransform, alpha: CompositeAlpha,
mode: PresentMode, clipped: bool, old_swapchain: Option<&Swapchain>)
-> Result<(Arc<Swapchain>, Vec<Arc<SwapchainImage>>), OomError>
@ -159,13 +248,13 @@ impl Swapchain {
// If we recreate a swapchain, make sure that the surface is the same.
if let Some(sc) = old_swapchain {
// TODO: return proper error instead of panicing?
assert_eq!(surface.internal_object(), sc.surface.internal_object());
assert_eq!(surface.internal_object(), sc.surface.internal_object(),
"Surface mismatch between old and new swapchain");
}
// Checking that the surface doesn't already have a swapchain.
if old_swapchain.is_none() {
// TODO: return proper error instead of panicing?
// TODO: return proper error instead of panicking
let has_already = surface.flag().swap(true, Ordering::AcqRel);
if has_already { panic!("The surface already has a swapchain alive"); }
}
@ -218,10 +307,42 @@ impl Swapchain {
output
};
let image_handles = unsafe {
let mut num = 0;
try!(check_errors(vk.GetSwapchainImagesKHR(device.internal_object(),
swapchain, &mut num,
ptr::null_mut())));
let mut images = Vec::with_capacity(num as usize);
try!(check_errors(vk.GetSwapchainImagesKHR(device.internal_object(),
swapchain, &mut num,
images.as_mut_ptr())));
images.set_len(num as usize);
images
};
let images = image_handles.into_iter().enumerate().map(|(id, image)| unsafe {
let dims = ImageDimensions::Dim2d {
width: dimensions[0],
height: dimensions[1],
array_layers: layers,
cubemap_compatible: false,
};
let img = UnsafeImage::from_raw(device.clone(), image, usage.to_usage_bits(), format,
dims, 1, 1);
ImageEntry {
image: img,
undefined_layout: AtomicBool::new(true)
}
}).collect::<Vec<_>>();
let swapchain = Arc::new(Swapchain {
device: device.clone(),
surface: surface.clone(),
swapchain: swapchain,
images: images,
stale: Mutex::new(false),
num_images: num_images,
format: format,
@ -234,113 +355,21 @@ impl Swapchain {
alpha: alpha,
mode: mode,
clipped: clipped,
images: Mutex::new(Vec::new()), // Filled below.
});
let images = unsafe {
let mut num = 0;
try!(check_errors(vk.GetSwapchainImagesKHR(device.internal_object(),
swapchain.swapchain, &mut num,
ptr::null_mut())));
let mut images = Vec::with_capacity(num as usize);
try!(check_errors(vk.GetSwapchainImagesKHR(device.internal_object(),
swapchain.swapchain, &mut num,
images.as_mut_ptr())));
images.set_len(num as usize);
images
};
let images = images.into_iter().enumerate().map(|(id, image)| unsafe {
let unsafe_image = UnsafeImage::from_raw(device, image, usage.to_usage_bits(), format,
ImageDimensions::Dim2d { width: dimensions[0], height: dimensions[1], array_layers: 1, cubemap_compatible: false }, 1, 1);
SwapchainImage::from_raw(unsafe_image, format, &swapchain, id as u32).unwrap() // TODO: propagate error
}).collect::<Vec<_>>();
*swapchain.images.lock().unwrap() = images.iter().map(|i| (Arc::downgrade(i), true)).collect();
Ok((swapchain, images))
}
/// Tries to take ownership of an image in order to draw on it.
///
/// The function returns the index of the image in the array of images that was returned
/// when creating the swapchain, plus a future that represents the moment when the image will
/// become available from the GPU (which may not be *immediately*).
///
/// If you try to draw on an image without acquiring it first, the execution will block. (TODO
/// behavior may change).
// TODO: has to make sure vkQueuePresent is called, because calling acquire_next_image many
// times in a row is an error
// TODO: swapchain must not have been replaced by being passed as the VkSwapchainCreateInfoKHR::oldSwapchain value to vkCreateSwapchainKHR
// TODO: change timeout to `Option<Duration>`.
pub fn acquire_next_image(&self, timeout: Duration) -> Result<(usize, SwapchainAcquireFuture), AcquireError> {
unsafe {
let stale = self.stale.lock().unwrap();
if *stale {
return Err(AcquireError::OutOfDate);
let swapchain_images = (0 .. swapchain.images.len()).map(|n| {
unsafe {
SwapchainImage::from_raw(swapchain.clone(), n).unwrap() // TODO: propagate error
}
}).collect();
let vk = self.device.pointers();
let semaphore = try!(Semaphore::new(self.device.clone()));
let timeout_ns = timeout.as_secs().saturating_mul(1_000_000_000)
.saturating_add(timeout.subsec_nanos() as u64);
let mut out = mem::uninitialized();
let r = try!(check_errors(vk.AcquireNextImageKHR(self.device.internal_object(),
self.swapchain, timeout_ns,
semaphore.internal_object(), 0,
&mut out)));
let id = match r {
Success::Success => out as usize,
Success::Suboptimal => out as usize, // TODO: give that info to the user
Success::NotReady => return Err(AcquireError::Timeout),
Success::Timeout => return Err(AcquireError::Timeout),
s => panic!("unexpected success value: {:?}", s)
};
let mut images = self.images.lock().unwrap();
let undefined_layout = mem::replace(&mut images.get_mut(id).unwrap().1, false);
Ok((id, SwapchainAcquireFuture {
semaphore: semaphore,
id: id,
image: images.get(id).unwrap().0.clone(),
finished: AtomicBool::new(false),
undefined_layout: undefined_layout,
}))
}
Ok((swapchain, swapchain_images))
}
/// Presents an image on the screen.
///
/// The parameter is the same index as what `acquire_next_image` returned. The image must
/// have been acquired first.
///
/// The actual behavior depends on the present mode that you passed when creating the
/// swapchain.
// TODO: use another API, since taking by Arc is meh
pub fn present<F>(me: Arc<Self>, before: F, queue: Arc<Queue>, index: usize)
-> PresentFuture<F>
where F: GpuFuture
{
assert!(index < me.num_images as usize);
let swapchain_image = me.images.lock().unwrap().get(index).unwrap().0.upgrade().unwrap(); // TODO: return error instead
// Normally if `check_image_access` returns false we're supposed to call the `gpu_access`
// function on the image instead. But since we know that this method on `SwapchainImage`
// always returns false anyway (by design), we don't need to do it.
assert!(before.check_image_access(&swapchain_image, Layout::PresentSrc, true, &queue).is_ok()); // TODO: return error instead
PresentFuture {
previous: before,
queue: queue,
swapchain: me,
image_id: index as u32,
finished: AtomicBool::new(false),
}
/// Returns of the images that belong to this swapchain.
#[inline]
pub fn raw_image(&self, offset: usize) -> Option<&UnsafeImage> {
self.images.get(offset).map(|i| &i.image)
}
/// Returns the number of images of the swapchain.
@ -348,7 +377,7 @@ impl Swapchain {
/// See the documentation of `Swapchain::new`.
#[inline]
pub fn num_images(&self) -> u32 {
self.num_images
self.images.len() as u32
}
/// Returns the format of the images of the swapchain.
@ -438,25 +467,23 @@ impl Drop for Swapchain {
/// Represents the moment when the GPU will have access to a swapchain image.
#[must_use]
pub struct SwapchainAcquireFuture {
swapchain: Arc<Swapchain>,
image_id: usize,
semaphore: Semaphore,
id: usize,
image: Weak<SwapchainImage>,
finished: AtomicBool,
// If true, then the acquired image is still in the undefined layout and must be transitionned.
undefined_layout: bool,
}
impl SwapchainAcquireFuture {
/// Returns the index of the image in the list of images returned when creating the swapchain.
#[inline]
pub fn image_id(&self) -> usize {
self.id
self.image_id
}
/// Returns the acquired image.
/// Returns the corresponding swapchain.
#[inline]
pub fn image(&self) -> Option<Arc<SwapchainImage>> {
self.image.upgrade()
pub fn swapchain(&self) -> &Arc<Swapchain> {
&self.swapchain
}
}
@ -500,34 +527,30 @@ unsafe impl GpuFuture for SwapchainAcquireFuture {
}
#[inline]
fn check_image_access(&self, image: &ImageAccess, layout: Layout, exclusive: bool, queue: &Queue)
fn check_image_access(&self, image: &ImageAccess, layout: ImageLayout, exclusive: bool, queue: &Queue)
-> Result<Option<(PipelineStages, AccessFlagBits)>, AccessCheckError>
{
if let Some(sc_img) = self.image.upgrade() {
if sc_img.inner().internal_object() != image.inner().internal_object() {
return Err(AccessCheckError::Unknown);
}
if self.undefined_layout && layout != Layout::Undefined {
return Err(AccessCheckError::Denied(AccessError::ImageNotInitialized {
requested: layout
}));
}
if layout != Layout::Undefined && layout != Layout::PresentSrc {
return Err(AccessCheckError::Denied(AccessError::UnexpectedImageLayout {
allowed: Layout::PresentSrc,
requested: layout,
}));
}
Ok(None)
} else {
// The swapchain image no longer exists, therefore the `image` parameter received by
// this function cannot possibly be the swapchain image.
Err(AccessCheckError::Unknown)
let swapchain_image = self.swapchain.raw_image(self.image_id).unwrap();
if swapchain_image.internal_object() != image.inner().internal_object() {
return Err(AccessCheckError::Unknown);
}
if self.swapchain.images[self.image_id].undefined_layout.load(Ordering::Relaxed) &&
layout != ImageLayout::Undefined
{
return Err(AccessCheckError::Denied(AccessError::ImageNotInitialized {
requested: layout
}));
}
if layout != ImageLayout::Undefined && layout != ImageLayout::PresentSrc {
return Err(AccessCheckError::Denied(AccessError::UnexpectedImageLayout {
allowed: ImageLayout::PresentSrc,
requested: layout,
}));
}
Ok(None)
}
}
@ -629,10 +652,29 @@ pub struct PresentFuture<P> where P: GpuFuture {
previous: P,
queue: Arc<Queue>,
swapchain: Arc<Swapchain>,
image_id: u32,
image_id: usize,
// True if `flush()` has been called on the future, which means that the present command has
// been submitted.
flushed: AtomicBool,
// True if `signal_finished()` has been called on the future, which means that the future has
// been submitted and has already been processed by the GPU.
finished: AtomicBool,
}
impl<P> PresentFuture<P> where P: GpuFuture {
/// Returns the index of the image in the list of images returned when creating the swapchain.
#[inline]
pub fn image_id(&self) -> usize {
self.image_id
}
/// Returns the corresponding swapchain.
#[inline]
pub fn swapchain(&self) -> &Arc<Swapchain> {
&self.swapchain
}
}
unsafe impl<P> GpuFuture for PresentFuture<P> where P: GpuFuture {
#[inline]
fn cleanup_finished(&mut self) {
@ -641,6 +683,10 @@ unsafe impl<P> GpuFuture for PresentFuture<P> where P: GpuFuture {
#[inline]
unsafe fn build_submission(&self) -> Result<SubmitAnyBuilder, FlushError> {
if self.flushed.load(Ordering::SeqCst) {
return Ok(SubmitAnyBuilder::Empty);
}
let queue = self.previous.queue().map(|q| q.clone());
// TODO: if the swapchain image layout is not PRESENT, should add a transition command
@ -649,18 +695,18 @@ unsafe impl<P> GpuFuture for PresentFuture<P> where P: GpuFuture {
Ok(match try!(self.previous.build_submission()) {
SubmitAnyBuilder::Empty => {
let mut builder = SubmitPresentBuilder::new();
builder.add_swapchain(&self.swapchain, self.image_id);
builder.add_swapchain(&self.swapchain, self.image_id as u32);
SubmitAnyBuilder::QueuePresent(builder)
},
SubmitAnyBuilder::SemaphoresWait(sem) => {
let mut builder: SubmitPresentBuilder = sem.into();
builder.add_swapchain(&self.swapchain, self.image_id);
builder.add_swapchain(&self.swapchain, self.image_id as u32);
SubmitAnyBuilder::QueuePresent(builder)
},
SubmitAnyBuilder::CommandBuffer(cb) => {
try!(cb.submit(&queue.unwrap())); // FIXME: wrong because build_submission can be called multiple times
let mut builder = SubmitPresentBuilder::new();
builder.add_swapchain(&self.swapchain, self.image_id);
builder.add_swapchain(&self.swapchain, self.image_id as u32);
SubmitAnyBuilder::QueuePresent(builder)
},
SubmitAnyBuilder::QueuePresent(present) => {
@ -675,11 +721,25 @@ unsafe impl<P> GpuFuture for PresentFuture<P> where P: GpuFuture {
#[inline]
fn flush(&self) -> Result<(), FlushError> {
unimplemented!()
unsafe {
// If `flushed` already contains `true`, then `build_submission` will return `Empty`.
match self.build_submission()? {
SubmitAnyBuilder::Empty => {}
SubmitAnyBuilder::QueuePresent(present) => {
present.submit(&self.queue)?;
}
_ => unreachable!()
}
self.flushed.store(true, Ordering::SeqCst);
Ok(())
}
}
#[inline]
unsafe fn signal_finished(&self) {
self.flushed.store(true, Ordering::SeqCst);
self.finished.store(true, Ordering::SeqCst);
self.previous.signal_finished();
}
@ -703,14 +763,23 @@ unsafe impl<P> GpuFuture for PresentFuture<P> where P: GpuFuture {
fn check_buffer_access(&self, buffer: &BufferAccess, exclusive: bool, queue: &Queue)
-> Result<Option<(PipelineStages, AccessFlagBits)>, AccessCheckError>
{
unimplemented!() // TODO: VK specs don't say whether it is legal to do that
self.previous.check_buffer_access(buffer, exclusive, queue)
}
#[inline]
fn check_image_access(&self, image: &ImageAccess, layout: Layout, exclusive: bool, queue: &Queue)
fn check_image_access(&self, image: &ImageAccess, layout: ImageLayout, exclusive: bool, queue: &Queue)
-> Result<Option<(PipelineStages, AccessFlagBits)>, AccessCheckError>
{
unimplemented!() // TODO: VK specs don't say whether it is legal to do that
let swapchain_image = self.swapchain.raw_image(self.image_id).unwrap();
if swapchain_image.internal_object() == image.inner().internal_object() {
// This future presents the swapchain image, which "unlocks" it. Therefore any attempt
// to use this swapchain image afterwards shouldn't get granted automatic access.
// Instead any attempt to access the image afterwards should get an authorization from
// a later swapchain acquire future. Hence why we return `Unknown` here.
Err(AccessCheckError::Unknown)
} else {
self.previous.check_image_access(image, layout, exclusive, queue)
}
}
}

View File

@ -37,9 +37,7 @@ pub struct Event {
impl Event {
/// See the docs of new().
#[inline]
pub fn raw(device: &Arc<Device>) -> Result<Event, OomError> {
let vk = device.pointers();
pub fn raw(device: Arc<Device>) -> Result<Event, OomError> {
let event = unsafe {
// since the creation is constant, we use a `static` instead of a struct on the stack
static mut INFOS: vk::EventCreateInfo = vk::EventCreateInfo {
@ -49,13 +47,14 @@ impl Event {
};
let mut output = mem::uninitialized();
let vk = device.pointers();
try!(check_errors(vk.CreateEvent(device.internal_object(), &INFOS,
ptr::null(), &mut output)));
output
};
Ok(Event {
device: device.clone(),
device: device,
event: event,
})
}
@ -67,7 +66,7 @@ impl Event {
/// - Panics if the device or host ran out of memory.
///
#[inline]
pub fn new(device: &Arc<Device>) -> Arc<Event> {
pub fn new(device: Arc<Device>) -> Arc<Event> {
Arc::new(Event::raw(device).unwrap())
}
@ -165,14 +164,14 @@ mod tests {
#[test]
fn event_create() {
let (device, _) = gfx_dev_and_queue!();
let event = Event::new(&device);
let event = Event::new(device);
assert!(!event.signaled().unwrap());
}
#[test]
fn event_set() {
let (device, _) = gfx_dev_and_queue!();
let mut event = Event::new(&device);
let mut event = Event::new(device);
assert!(!event.signaled().unwrap());
Arc::get_mut(&mut event).unwrap().set();
@ -183,7 +182,7 @@ mod tests {
fn event_reset() {
let (device, _) = gfx_dev_and_queue!();
let mut event = Event::new(&device);
let mut event = Event::new(device);
Arc::get_mut(&mut event).unwrap().set();
assert!(event.signaled().unwrap());

View File

@ -20,7 +20,7 @@ use device::Device;
use device::DeviceOwned;
use device::Queue;
use image::ImageAccess;
use image::Layout;
use image::ImageLayout;
use sync::AccessCheckError;
use sync::AccessFlagBits;
use sync::FlushError;
@ -58,6 +58,35 @@ pub enum FenceSignalFutureBehavior {
}
/// Represents a fence being signaled after a previous event.
///
/// Contrary to most other future types, it is possible to block the current thread until the event
/// happens. This is done by calling the `wait()` function.
///
/// Also note that the `GpuFuture` trait is implemented on `Arc<FenceSignalFuture<_>>`.
/// This means that you can put this future in an `Arc` and keep a copy of it somewhere in order
/// to know when the execution reached that point.
///
/// ```
/// use std::sync::Arc;
/// use vulkano::sync::GpuFuture;
///
/// # let future: Box<GpuFuture> = return;
/// // Assuming you have a chain of operations, like this:
/// // let future = ...
/// // .then_execute(foo)
/// // .then_execute(bar)
///
/// // You can signal a fence at this point of the chain, and put the future in an `Arc`.
/// let fence_signal = Arc::new(future.then_signal_fence());
///
/// // And then continue the chain:
/// // fence_signal.clone()
/// // .then_execute(baz)
/// // .then_execute(qux)
///
/// // Later you can wait until you reach the point of `fence_signal`:
/// fence_signal.wait(None).unwrap();
/// ```
#[must_use = "Dropping this object will immediately block the thread until the GPU has finished processing the submission"]
pub struct FenceSignalFuture<F> where F: GpuFuture {
// Current state. See the docs of `FenceSignalFutureState`.
@ -91,6 +120,32 @@ enum FenceSignalFutureState<F> {
Poisonned,
}
impl<F> FenceSignalFuture<F> where F: GpuFuture {
/// Blocks the current thread until the fence is signaled by the GPU. Performs a flush if
/// necessary.
///
/// If `timeout` is `None`, then the wait is infinite. Otherwise the thread will unblock after
/// the specified timeout has elapsed and an error will be returned.
///
/// If the wait is successful, this function also cleans any resource locked by previous
/// submissions.
pub fn wait(&self, timeout: Option<Duration>) -> Result<(), FlushError> {
let mut state = self.state.lock().unwrap();
self.flush_impl(&mut state)?;
match mem::replace(&mut *state, FenceSignalFutureState::Cleaned) {
FenceSignalFutureState::Flushed(previous, fence) => {
fence.wait(timeout)?;
unsafe { previous.signal_finished(); }
Ok(())
},
FenceSignalFutureState::Cleaned => Ok(()),
_ => unreachable!()
}
}
}
impl<F> FenceSignalFuture<F> where F: GpuFuture {
// Implementation of `cleanup_finished`, but takes a `&self` instead of a `&mut self`.
// This is an external function so that we can also call it from an `Arc<FenceSignalFuture>`.
@ -99,12 +154,25 @@ impl<F> FenceSignalFuture<F> where F: GpuFuture {
let mut state = self.state.lock().unwrap();
match *state {
FenceSignalFutureState::Flushed(_, ref fence) => {
FenceSignalFutureState::Flushed(ref mut prev, ref fence) => {
match fence.wait(Some(Duration::from_secs(0))) {
Ok(()) => (),
Err(_) => return,
Ok(()) => unsafe {
prev.signal_finished()
},
Err(_) => {
prev.cleanup_finished();
return
},
}
},
FenceSignalFutureState::Pending(ref mut prev, _) => {
prev.cleanup_finished();
return;
},
FenceSignalFutureState::PartiallyFlushed(ref mut prev, _) => {
prev.cleanup_finished();
return;
},
_ => return,
};
@ -305,7 +373,7 @@ unsafe impl<F> GpuFuture for FenceSignalFuture<F> where F: GpuFuture {
}
#[inline]
fn check_image_access(&self, image: &ImageAccess, layout: Layout, exclusive: bool, queue: &Queue)
fn check_image_access(&self, image: &ImageAccess, layout: ImageLayout, exclusive: bool, queue: &Queue)
-> Result<Option<(PipelineStages, AccessFlagBits)>, AccessCheckError> {
let state = self.state.lock().unwrap();
if let Some(previous) = state.get_prev() {
@ -393,7 +461,7 @@ unsafe impl<F> GpuFuture for Arc<FenceSignalFuture<F>> where F: GpuFuture {
}
#[inline]
fn check_image_access(&self, image: &ImageAccess, layout: Layout, exclusive: bool, queue: &Queue)
fn check_image_access(&self, image: &ImageAccess, layout: ImageLayout, exclusive: bool, queue: &Queue)
-> Result<Option<(PipelineStages, AccessFlagBits)>, AccessCheckError>
{
(**self).check_image_access(image, layout, exclusive, queue)

View File

@ -15,7 +15,7 @@ use device::Device;
use device::DeviceOwned;
use device::Queue;
use image::ImageAccess;
use image::Layout;
use image::ImageLayout;
use sync::AccessCheckError;
use sync::AccessFlagBits;
use sync::FlushError;
@ -173,7 +173,7 @@ unsafe impl<A, B> GpuFuture for JoinFuture<A, B> where A: GpuFuture, B: GpuFutur
}
#[inline]
fn check_image_access(&self, image: &ImageAccess, layout: Layout, exclusive: bool, queue: &Queue)
fn check_image_access(&self, image: &ImageAccess, layout: ImageLayout, exclusive: bool, queue: &Queue)
-> Result<Option<(PipelineStages, AccessFlagBits)>, AccessCheckError>
{
let first = self.first.check_image_access(image, layout, exclusive, queue);

View File

@ -21,7 +21,8 @@ use command_buffer::submit::SubmitCommandBufferError;
use device::DeviceOwned;
use device::Queue;
use image::ImageAccess;
use image::Layout;
use image::ImageLayout;
use swapchain;
use swapchain::Swapchain;
use swapchain::PresentFuture;
use sync::AccessFlagBits;
@ -59,6 +60,8 @@ pub unsafe trait GpuFuture: DeviceOwned {
/// It is the responsibility of the caller to ensure that the submission is going to be
/// submitted only once. However keep in mind that this function can perfectly be called
/// multiple times (as long as the returned object is only submitted once).
/// Also note that calling `flush()` on the future may change the value returned by
/// `build_submission()`.
///
/// It is however the responsibility of the implementation to not return the same submission
/// from multiple different future objects. For example if you implement `GpuFuture` on
@ -124,7 +127,7 @@ pub unsafe trait GpuFuture: DeviceOwned {
///
/// > **Note**: Keep in mind that changing the layout of an image also requires exclusive
/// > access.
fn check_image_access(&self, image: &ImageAccess, layout: Layout, exclusive: bool,
fn check_image_access(&self, image: &ImageAccess, layout: ImageLayout, exclusive: bool,
queue: &Queue) -> Result<Option<(PipelineStages, AccessFlagBits)>, AccessCheckError>;
/// Joins this future with another one, representing the moment when both events have happened.
@ -197,9 +200,7 @@ pub unsafe trait GpuFuture: DeviceOwned {
/// > function. If so, consider using `then_signal_fence_and_flush`.
#[inline]
fn then_signal_fence(self) -> FenceSignalFuture<Self> where Self: Sized {
fence_signal::then_signal_fence(self, FenceSignalFutureBehavior::Block {
timeout: None
})
fence_signal::then_signal_fence(self, FenceSignalFutureBehavior::Continue)
}
/// Signals a fence after this future. Returns another future that represents the signal.
@ -225,7 +226,7 @@ pub unsafe trait GpuFuture: DeviceOwned {
image_index: usize) -> PresentFuture<Self>
where Self: Sized
{
Swapchain::present(swapchain, self, queue, image_index)
swapchain::present(swapchain, self, queue, image_index)
}
}
@ -268,7 +269,7 @@ unsafe impl<F: ?Sized> GpuFuture for Box<F> where F: GpuFuture {
}
#[inline]
fn check_image_access(&self, image: &ImageAccess, layout: Layout, exclusive: bool, queue: &Queue)
fn check_image_access(&self, image: &ImageAccess, layout: ImageLayout, exclusive: bool, queue: &Queue)
-> Result<Option<(PipelineStages, AccessFlagBits)>, AccessCheckError>
{
(**self).check_image_access(image, layout, exclusive, queue)
@ -281,17 +282,26 @@ pub enum AccessError {
/// Exclusive access is denied.
ExclusiveDenied,
/// The resource is already in use, and there is no tracking of concurrent usages.
AlreadyInUse,
UnexpectedImageLayout {
allowed: Layout,
requested: Layout,
allowed: ImageLayout,
requested: ImageLayout,
},
/// Trying to use an image without transitionning it from the "undefined" or "preinitialized"
/// layouts first.
ImageNotInitialized {
/// The layout that was requested for the image.
requested: Layout,
requested: ImageLayout,
},
/// Trying to use a buffer that still contains garbage data.
BufferNotInitialized,
/// Trying to use a swapchain image without depending on a corresponding acquire image future.
SwapchainImageAcquireOnly,
}
impl error::Error for AccessError {
@ -301,6 +311,9 @@ impl error::Error for AccessError {
AccessError::ExclusiveDenied => {
"only shared access is allowed for this resource"
},
AccessError::AlreadyInUse => {
"the resource is already in use, and there is no tracking of concurrent usages"
},
AccessError::UnexpectedImageLayout { .. } => {
unimplemented!() // TODO: find a description
},
@ -308,6 +321,13 @@ impl error::Error for AccessError {
"trying to use an image without transitionning it from the undefined or \
preinitialized layouts first"
},
AccessError::BufferNotInitialized => {
"trying to use a buffer that still contains garbage data"
},
AccessError::SwapchainImageAcquireOnly => {
"trying to use a swapchain image without depending on a corresponding acquire \
image future"
},
}
}
}

View File

@ -15,7 +15,7 @@ use device::Device;
use device::DeviceOwned;
use device::Queue;
use image::ImageAccess;
use image::Layout;
use image::ImageLayout;
use sync::AccessCheckError;
use sync::AccessFlagBits;
use sync::FlushError;
@ -72,7 +72,7 @@ unsafe impl GpuFuture for NowFuture {
}
#[inline]
fn check_image_access(&self, image: &ImageAccess, layout: Layout, exclusive: bool, queue: &Queue)
fn check_image_access(&self, image: &ImageAccess, layout: ImageLayout, exclusive: bool, queue: &Queue)
-> Result<Option<(PipelineStages, AccessFlagBits)>, AccessCheckError>
{
Err(AccessCheckError::Unknown)

View File

@ -20,7 +20,7 @@ use device::Device;
use device::DeviceOwned;
use device::Queue;
use image::ImageAccess;
use image::Layout;
use image::ImageLayout;
use sync::AccessCheckError;
use sync::AccessFlagBits;
use sync::FlushError;
@ -136,7 +136,7 @@ unsafe impl<F> GpuFuture for SemaphoreSignalFuture<F> where F: GpuFuture {
}
#[inline]
fn check_image_access(&self, image: &ImageAccess, layout: Layout, exclusive: bool, queue: &Queue)
fn check_image_access(&self, image: &ImageAccess, layout: ImageLayout, exclusive: bool, queue: &Queue)
-> Result<Option<(PipelineStages, AccessFlagBits)>, AccessCheckError>
{
self.previous.check_image_access(image, layout, exclusive, queue).map(|_| None)