mirror of
https://github.com/vulkano-rs/vulkano.git
synced 2024-11-25 00:04:15 +00:00
Merge branch 'custom-derives' into incoming
This commit is contained in:
commit
1216461211
2
.gitignore
vendored
2
.gitignore
vendored
@ -1,3 +1,3 @@
|
||||
target
|
||||
Cargo.lock
|
||||
.cargo
|
||||
.cargo
|
@ -5,5 +5,6 @@ members = [
|
||||
"vk-sys",
|
||||
"vulkano",
|
||||
"vulkano-shaders",
|
||||
"vulkano-shader-derive",
|
||||
"vulkano-win"
|
||||
]
|
||||
|
@ -13,7 +13,7 @@ What does vulkano do?
|
||||
|
||||
- Provides a low-levelish API around Vulkan. It doesn't hide what it does, but provides some
|
||||
comfort types.
|
||||
- Plans to prevents all invalid API usages, even the most obscure ones. The purpose of vulkano
|
||||
- Plans to prevent all invalid API usages, even the most obscure ones. The purpose of vulkano
|
||||
is not to draw a teapot, but to cover all possible usages of Vulkan and detect all the
|
||||
possible problems. Invalid API usage is prevented thanks to both compile-time checks and
|
||||
runtime checks.
|
||||
|
BIN
apispec.pdf
Normal file
BIN
apispec.pdf
Normal file
Binary file not shown.
@ -7,7 +7,7 @@ build = "build.rs"
|
||||
[dependencies]
|
||||
vulkano = { path = "../vulkano" }
|
||||
vulkano-win = { path = "../vulkano-win" }
|
||||
cgmath = "0.7.0"
|
||||
cgmath = "0.12.0"
|
||||
image = "0.6.1"
|
||||
winit = "0.5.2"
|
||||
time = "0.1.35"
|
||||
|
@ -52,7 +52,7 @@ fn main() {
|
||||
let present = caps.present_modes.iter().next().unwrap();
|
||||
let usage = caps.supported_usage_flags;
|
||||
|
||||
vulkano::swapchain::Swapchain::new(&device, &window.surface(), 3,
|
||||
vulkano::swapchain::Swapchain::new(&device, &window.surface(), caps.min_image_count,
|
||||
vulkano::format::B8G8R8A8Srgb, dimensions, 1,
|
||||
&usage, &queue, vulkano::swapchain::SurfaceTransform::Identity,
|
||||
vulkano::swapchain::CompositeAlpha::Opaque,
|
||||
@ -60,27 +60,18 @@ fn main() {
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
let vertex_buffer = vulkano::buffer::cpu_access::CpuAccessibleBuffer::<[Vertex]>
|
||||
::array(&device, 4, &vulkano::buffer::BufferUsage::all(),
|
||||
Some(queue.family())).expect("failed to create buffer");
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
struct Vertex { position: [f32; 2] }
|
||||
impl_vertex!(Vertex, position);
|
||||
|
||||
// The buffer that we created contains uninitialized data.
|
||||
// In order to fill it with data, we have to *map* it.
|
||||
{
|
||||
// The `write` function would return `Err` if the buffer was in use by the GPU. This
|
||||
// obviously can't happen here, since we haven't ask the GPU to do anything yet.
|
||||
let mut mapping = vertex_buffer.write(Duration::new(0, 0)).unwrap();
|
||||
mapping[0].position = [-0.5, -0.5];
|
||||
mapping[1].position = [-0.5, 0.5];
|
||||
mapping[2].position = [ 0.5, -0.5];
|
||||
mapping[3].position = [ 0.5, 0.5];
|
||||
}
|
||||
|
||||
let vertex_buffer = vulkano::buffer::cpu_access::CpuAccessibleBuffer::<[Vertex]>
|
||||
::from_iter(&device, &vulkano::buffer::BufferUsage::all(),
|
||||
Some(queue.family()), [
|
||||
Vertex { position: [-0.5, -0.5 ] },
|
||||
Vertex { position: [-0.5, 0.5 ] },
|
||||
Vertex { position: [ 0.5, -0.5 ] },
|
||||
Vertex { position: [ 0.5, 0.5 ] },
|
||||
].iter().cloned()).expect("failed to create buffer");
|
||||
|
||||
mod vs { include!{concat!(env!("OUT_DIR"), "/shaders/src/bin/image_vs.glsl")} }
|
||||
let vs = vs::Shader::load(&device).expect("failed to create shader module");
|
||||
@ -116,22 +107,13 @@ fn main() {
|
||||
image::ImageFormat::PNG).unwrap().to_rgba();
|
||||
let image_data = image.into_raw().clone();
|
||||
|
||||
let image_data_chunks = image_data.chunks(4).map(|c| [c[0], c[1], c[2], c[3]]);
|
||||
|
||||
// TODO: staging buffer instead
|
||||
let pixel_buffer = vulkano::buffer::cpu_access::CpuAccessibleBuffer::<[[u8; 4]]>
|
||||
::array(&device, image_data.len(), &vulkano::buffer::BufferUsage::all(),
|
||||
Some(queue.family())).expect("failed to create buffer");
|
||||
|
||||
{
|
||||
let mut mapping = pixel_buffer.write(Duration::new(0, 0)).unwrap();
|
||||
for (o, i) in mapping.iter_mut().zip(image_data.chunks(4)) {
|
||||
o[0] = i[0];
|
||||
o[1] = i[1];
|
||||
o[2] = i[2];
|
||||
o[3] = i[3];
|
||||
}
|
||||
}
|
||||
|
||||
pixel_buffer
|
||||
vulkano::buffer::cpu_access::CpuAccessibleBuffer::<[[u8; 4]]>
|
||||
::from_iter(&device, &vulkano::buffer::BufferUsage::all(),
|
||||
Some(queue.family()), image_data_chunks)
|
||||
.expect("failed to create buffer")
|
||||
};
|
||||
|
||||
|
||||
|
@ -10,7 +10,7 @@
|
||||
#version 450
|
||||
|
||||
#extension GL_ARB_separate_shader_objects : enable
|
||||
#extension GL_ARB_shading_language_420pack : enable
|
||||
#extension GL_ARB_shading_language_450pack : enable
|
||||
|
||||
layout(location = 0) in vec2 tex_coords;
|
||||
layout(location = 0) out vec4 f_color;
|
||||
|
@ -10,7 +10,7 @@
|
||||
#version 450
|
||||
|
||||
#extension GL_ARB_separate_shader_objects : enable
|
||||
#extension GL_ARB_shading_language_420pack : enable
|
||||
#extension GL_ARB_shading_language_450pack : enable
|
||||
|
||||
layout(location = 0) in vec2 position;
|
||||
layout(location = 0) out vec2 tex_coords;
|
||||
|
@ -61,7 +61,7 @@ fn main() {
|
||||
let usage = caps.supported_usage_flags;
|
||||
let format = caps.supported_formats[0].0;
|
||||
|
||||
vulkano::swapchain::Swapchain::new(&device, &window.surface(), 3, format, dimensions, 1,
|
||||
vulkano::swapchain::Swapchain::new(&device, &window.surface(), 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")
|
||||
@ -84,7 +84,7 @@ fn main() {
|
||||
|
||||
// note: this teapot was meant for OpenGL where the origin is at the lower left
|
||||
// instead the origin is at the upper left in vulkan, so we reverse the Y axis
|
||||
let proj = cgmath::perspective(cgmath::rad(3.141592 / 2.0), { let d = images[0].dimensions(); d[0] as f32 / d[1] as f32 }, 0.01, 100.0);
|
||||
let proj = cgmath::perspective(cgmath::Rad(std::f32::consts::FRAC_PI_2), { let d = images[0].dimensions(); d[0] as f32 / d[1] as f32 }, 0.01, 100.0);
|
||||
let view = cgmath::Matrix4::look_at(cgmath::Point3::new(0.3, 0.3, 1.0), cgmath::Point3::new(0.0, 0.0, 0.0), cgmath::Vector3::new(0.0, -1.0, 0.0));
|
||||
let scale = cgmath::Matrix4::from_scale(0.01);
|
||||
|
||||
@ -186,7 +186,7 @@ fn main() {
|
||||
// aquiring write lock for the uniform buffer
|
||||
let mut buffer_content = uniform_buffer.write(Duration::new(1, 0)).unwrap();
|
||||
|
||||
let rotation = cgmath::Matrix3::from_angle_y(cgmath::rad(time::precise_time_ns() as f32 * 0.000000001));
|
||||
let rotation = cgmath::Matrix3::from_angle_y(cgmath::Rad(time::precise_time_ns() as f32 * 0.000000001));
|
||||
|
||||
// since write lock implementd Deref and DerefMut traits,
|
||||
// we can update content directly
|
||||
|
@ -10,7 +10,7 @@
|
||||
#version 450
|
||||
|
||||
#extension GL_ARB_separate_shader_objects : enable
|
||||
#extension GL_ARB_shading_language_420pack : enable
|
||||
#extension GL_ARB_shading_language_450pack : enable
|
||||
|
||||
layout(location = 0) in vec3 v_normal;
|
||||
layout(location = 0) out vec4 f_color;
|
||||
|
@ -10,7 +10,7 @@
|
||||
#version 450
|
||||
|
||||
#extension GL_ARB_separate_shader_objects : enable
|
||||
#extension GL_ARB_shading_language_420pack : enable
|
||||
#extension GL_ARB_shading_language_450pack : enable
|
||||
|
||||
layout(location = 0) in vec3 position;
|
||||
layout(location = 1) in vec3 normal;
|
||||
|
@ -181,7 +181,7 @@ 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(), 2, format, dimensions, 1,
|
||||
Swapchain::new(&device, &window.surface(), caps.min_image_count, format, dimensions, 1,
|
||||
&caps.supported_usage_flags, &queue, SurfaceTransform::Identity, alpha,
|
||||
present, true, None).expect("failed to create swapchain")
|
||||
};
|
||||
|
@ -10,7 +10,7 @@
|
||||
#version 450
|
||||
|
||||
#extension GL_ARB_separate_shader_objects : enable
|
||||
#extension GL_ARB_shading_language_420pack : enable
|
||||
#extension GL_ARB_shading_language_450pack : enable
|
||||
|
||||
layout(location = 0) out vec4 f_color;
|
||||
|
||||
|
@ -10,7 +10,7 @@
|
||||
#version 450
|
||||
|
||||
#extension GL_ARB_separate_shader_objects : enable
|
||||
#extension GL_ARB_shading_language_420pack : enable
|
||||
#extension GL_ARB_shading_language_450pack : enable
|
||||
|
||||
layout(location = 0) in vec2 position;
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "glsl-to-spirv"
|
||||
version = "0.1.1"
|
||||
version = "0.1.2"
|
||||
authors = ["Pierre Krieger <pierre.krieger1708@gmail.com>"]
|
||||
repository = "https://github.com/tomaka/vulkano"
|
||||
description = "Wrapper around the official GLSL to SPIR-V compiler"
|
||||
@ -8,7 +8,7 @@ license = "MIT/Apache-2.0"
|
||||
build = "build/build.rs"
|
||||
|
||||
[dependencies]
|
||||
tempdir = "0.3.4"
|
||||
tempdir = "0.3.5"
|
||||
|
||||
[build-dependencies]
|
||||
cmake = "0.1.13"
|
||||
cmake = "0.1.19"
|
||||
|
@ -6,4 +6,4 @@ repository = "https://github.com/tomaka/vulkano"
|
||||
description = "Bindings for the Vulkan graphics API"
|
||||
license = "MIT/Apache-2.0"
|
||||
documentation = "https://docs.rs/vk-sys"
|
||||
keywords = ["vulkan", "bindings", "graphics", "gpu"]
|
||||
keywords = ["vulkan", "bindings", "graphics", "gpu"]
|
||||
|
BIN
vkspec.pdf
BIN
vkspec.pdf
Binary file not shown.
13
vulkano-shader-derive/Cargo.toml
Normal file
13
vulkano-shader-derive/Cargo.toml
Normal file
@ -0,0 +1,13 @@
|
||||
[package]
|
||||
name = "vulkano-shader-derive"
|
||||
version = "0.1.0"
|
||||
authors = ["Pierre Krieger <pierre.krieger1708@gmail.com>"]
|
||||
|
||||
[lib]
|
||||
name = "vulkano_shader_derive"
|
||||
proc-macro = true
|
||||
|
||||
[dependencies]
|
||||
glsl-to-spirv = { version = "0.1.2", path = "../glsl-to-spirv" }
|
||||
syn = { version = "0.10", features = ["aster", "visit"] }
|
||||
vulkano-shaders = { version = "0.3", path = "../vulkano-shaders" }
|
27
vulkano-shader-derive/README.md
Normal file
27
vulkano-shader-derive/README.md
Normal file
@ -0,0 +1,27 @@
|
||||
# Usage
|
||||
|
||||
This replaces `vulkano-shaders`.
|
||||
|
||||
```rust
|
||||
#[macro_use]
|
||||
extern crate vulkano_shader_derive;
|
||||
|
||||
mod fs {
|
||||
#[derive(VulkanoShader)]
|
||||
#[ty = "fragment"]
|
||||
#[src = "
|
||||
#version 450
|
||||
|
||||
#extension GL_ARB_separate_shader_objects : enable
|
||||
#extension GL_ARB_shading_language_450pack : enable
|
||||
|
||||
layout(location = 0) out vec4 f_color;
|
||||
|
||||
void main() {
|
||||
f_color = vec4(1.0, 0.0, 0.0, 1.0);
|
||||
}"]
|
||||
struct Dummy;
|
||||
}
|
||||
|
||||
let fs = fs::Shader::load(&device).expect("failed to create shader module");
|
||||
```
|
46
vulkano-shader-derive/src/lib.rs
Normal file
46
vulkano-shader-derive/src/lib.rs
Normal file
@ -0,0 +1,46 @@
|
||||
extern crate glsl_to_spirv;
|
||||
extern crate proc_macro;
|
||||
extern crate syn;
|
||||
extern crate vulkano_shaders;
|
||||
|
||||
use proc_macro::TokenStream;
|
||||
|
||||
#[proc_macro_derive(VulkanoShader, attributes(src, ty))]
|
||||
pub fn derive(input: TokenStream) -> TokenStream {
|
||||
let syn_item = syn::parse_macro_input(&input.to_string()).unwrap();
|
||||
|
||||
let src = syn_item.attrs.iter().filter_map(|attr| {
|
||||
match attr.value {
|
||||
syn::MetaItem::NameValue(ref i, syn::Lit::Str(ref val, _)) if i == "src" => {
|
||||
Some(val.clone())
|
||||
},
|
||||
_ => None
|
||||
}
|
||||
}).next().expect("Can't find `src` attribute ; put #[src = \"...\"] for example.");
|
||||
|
||||
let ty_str = syn_item.attrs.iter().filter_map(|attr| {
|
||||
match attr.value {
|
||||
syn::MetaItem::NameValue(ref i, syn::Lit::Str(ref val, _)) if i == "ty" => {
|
||||
Some(val.clone())
|
||||
},
|
||||
_ => None
|
||||
}
|
||||
}).next().expect("Can't find `ty` attribute ; put #[ty = \"vertex\"] for example.");
|
||||
|
||||
let ty = match &ty_str[..] {
|
||||
"vertex" => glsl_to_spirv::ShaderType::Vertex,
|
||||
"fragment" => glsl_to_spirv::ShaderType::Fragment,
|
||||
"geometry" => glsl_to_spirv::ShaderType::Geometry,
|
||||
"tess_ctrl" => glsl_to_spirv::ShaderType::TessellationControl,
|
||||
"tess_eval" => glsl_to_spirv::ShaderType::TessellationEvaluation,
|
||||
"compute" => glsl_to_spirv::ShaderType::Compute,
|
||||
_ => panic!("Unexpected shader type ; valid values: vertex, fragment, geometry, tess_ctrl, tess_eval, compute")
|
||||
};
|
||||
|
||||
let spirv_data = match glsl_to_spirv::compile(&src, ty) {
|
||||
Ok(compiled) => compiled,
|
||||
Err(message) => panic!("{}\nfailed to compile shader", message),
|
||||
};
|
||||
|
||||
vulkano_shaders::reflect("Shader", spirv_data).unwrap().parse().unwrap()
|
||||
}
|
@ -8,4 +8,4 @@ license = "MIT/Apache-2.0"
|
||||
documentation = "http://tomaka.github.io/vulkano/vulkano/index.html"
|
||||
|
||||
[dependencies]
|
||||
glsl-to-spirv = { version = "0.1.0", path = "../glsl-to-spirv" }
|
||||
glsl-to-spirv = { version = "0.1.2", path = "../glsl-to-spirv" }
|
||||
|
@ -29,12 +29,33 @@ pub fn write_structs(doc: &parse::Spirv) -> String {
|
||||
result
|
||||
}
|
||||
|
||||
/// Represents a rust struct member
|
||||
struct Member {
|
||||
name: String,
|
||||
value: String,
|
||||
offset: Option<usize>
|
||||
}
|
||||
|
||||
impl Member {
|
||||
fn declaration_text(&self) -> String {
|
||||
let offset = match self.offset {
|
||||
Some(o) => format!("/* offset: {} */", o),
|
||||
_ => "".to_owned(),
|
||||
};
|
||||
format!(" pub {}: {} {}", self.name, self.value, offset)
|
||||
}
|
||||
fn copy_text(&self) -> String {
|
||||
format!(" {name}: self.{name}", name = self.name)
|
||||
}
|
||||
}
|
||||
|
||||
/// Writes a single struct.
|
||||
fn write_struct(doc: &parse::Spirv, struct_id: u32, members: &[u32]) -> String {
|
||||
let name = ::name_from_id(doc, struct_id);
|
||||
|
||||
// Strings of each member definition.
|
||||
let mut members_defs = Vec::with_capacity(members.len());
|
||||
// The members of this struct.
|
||||
let mut rust_members = Vec::with_capacity(members.len());
|
||||
|
||||
// Padding structs will be named `_paddingN` where `N` is determined by this variable.
|
||||
let mut next_padding_num = 0;
|
||||
|
||||
@ -90,7 +111,11 @@ fn write_struct(doc: &parse::Spirv, struct_id: u32, members: &[u32]) -> String {
|
||||
if spirv_offset != *current_rust_offset {
|
||||
let diff = spirv_offset.checked_sub(*current_rust_offset).unwrap();
|
||||
let padding_num = next_padding_num; next_padding_num += 1;
|
||||
members_defs.push(format!("pub _dummy{}: [u8; {}]", padding_num, diff));
|
||||
rust_members.push(Member {
|
||||
name: format!("_dummy{}", padding_num),
|
||||
value: format!("[u8; {}]", diff),
|
||||
offset: None,
|
||||
});
|
||||
*current_rust_offset += diff;
|
||||
}
|
||||
}
|
||||
@ -102,8 +127,11 @@ fn write_struct(doc: &parse::Spirv, struct_id: u32, members: &[u32]) -> String {
|
||||
current_rust_offset = None;
|
||||
}
|
||||
|
||||
members_defs.push(format!("pub {name}: {ty} /* offset: {offset} */",
|
||||
name = member_name, ty = ty, offset = spirv_offset));
|
||||
rust_members.push(Member {
|
||||
name: member_name.to_owned(),
|
||||
value: ty,
|
||||
offset: Some(spirv_offset),
|
||||
});
|
||||
}
|
||||
|
||||
// Try determine the total size of the struct in order to add padding at the end of the struct.
|
||||
@ -139,20 +167,27 @@ fn write_struct(doc: &parse::Spirv, struct_id: u32, members: &[u32]) -> String {
|
||||
if let (Some(cur_size), Some(req_size)) = (current_rust_offset, spirv_req_total_size) {
|
||||
let diff = req_size.checked_sub(cur_size as u32).unwrap();
|
||||
if diff >= 1 {
|
||||
members_defs.push(format!("pub _dummy{}: [u8; {}]", next_padding_num, diff));
|
||||
rust_members.push(Member {
|
||||
name: format!("_dummy{}", next_padding_num),
|
||||
value: format!("[u8; {}]", diff),
|
||||
offset: None,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// We can only derive common traits if there's no unsized member in the struct.
|
||||
let derive = if current_rust_offset.is_some() {
|
||||
"#[derive(Copy, Clone, Debug, Default)]\n"
|
||||
|
||||
// We can only implement Clone if there's no unsized member in the struct.
|
||||
let impl_text = if current_rust_offset.is_some() {
|
||||
format!("\nimpl Clone for {name} {{\n fn clone(&self) -> Self {{\n \
|
||||
{name} {{\n{copies}\n }}\n }}\n}}\n", name = name,
|
||||
copies = rust_members.iter().map(Member::copy_text).collect::<Vec<_>>().join(",\n"))
|
||||
} else {
|
||||
""
|
||||
"".to_owned()
|
||||
};
|
||||
|
||||
format!("#[repr(C)]\n{derive}\
|
||||
pub struct {name} {{\n\t{members}\n}} /* total_size: {t:?} */\n",
|
||||
derive = derive, name = name, members = members_defs.join(",\n\t"), t = spirv_req_total_size)
|
||||
format!("#[repr(C)]\npub struct {name} {{\n{members}\n}} /* total_size: {t:?} */\n{impl_text}",
|
||||
name = name,
|
||||
members = rust_members.iter().map(Member::declaration_text).collect::<Vec<_>>().join(",\n"),
|
||||
t = spirv_req_total_size, impl_text=impl_text)
|
||||
}
|
||||
|
||||
/// Returns true if a `BuiltIn` decorator is applied on a struct member.
|
||||
|
@ -8,4 +8,4 @@ license = "MIT/Apache-2.0"
|
||||
|
||||
[dependencies]
|
||||
vulkano = { version = "0.3.0", path = "../vulkano" }
|
||||
winit = "0.5.2"
|
||||
winit = "0.5.6"
|
||||
|
@ -8,9 +8,9 @@ license = "MIT/Apache-2.0"
|
||||
documentation = "https://docs.rs/vulkano"
|
||||
|
||||
[dependencies]
|
||||
crossbeam = "0.2.5"
|
||||
fnv = "1.0.2"
|
||||
shared_library = "0.1.4"
|
||||
smallvec = "0.2.0"
|
||||
lazy_static = "0.1.15"
|
||||
vk-sys = { version = "0.2.0", path = "../vk-sys" }
|
||||
crossbeam = "0.2.10"
|
||||
fnv = "1.0.5"
|
||||
shared_library = "0.1.5"
|
||||
smallvec = "0.3.1"
|
||||
lazy_static = "0.2.2"
|
||||
vk-sys = { version = "0.2.1", path = "../vk-sys" }
|
||||
|
@ -212,7 +212,7 @@ impl Device {
|
||||
if let Some(q) = queues.iter_mut().find(|q| q.0 == queue_family.id()) {
|
||||
output_queues.push((queue_family.id(), q.1.len() as u32));
|
||||
q.1.push(priority);
|
||||
if q.1.len() >= queue_family.queues_count() {
|
||||
if q.1.len() > queue_family.queues_count() {
|
||||
return Err(DeviceCreationError::TooManyQueuesForFamily);
|
||||
}
|
||||
continue;
|
||||
|
@ -7,11 +7,12 @@
|
||||
// notice may not be copied, modified, or distributed except
|
||||
// according to those terms.
|
||||
|
||||
//! Debug callback called by validation layers.
|
||||
//! Debug callback called by intermediate layers or by the driver.
|
||||
//!
|
||||
//! When working on an application, it is recommended to register a debug callback. This callback
|
||||
//! will be called by validation layers whenever necessary to warn you about invalid API usages
|
||||
//! or performance problems.
|
||||
//! When working on an application, it is recommended to register a debug callback. For example if
|
||||
//! you enable the validation layers provided by the official Vulkan SDK, they will warn you about
|
||||
//! invalid API usages or performance problems by calling this callback. The callback can also
|
||||
//! be called by the driver or by whatever intermediate layer is activated.
|
||||
//!
|
||||
//! Note that the vulkano library can also emit messages to warn you about performance issues.
|
||||
//! TODO: ^ that's not the case yet, need to choose whether we keep this idea
|
||||
@ -29,6 +30,8 @@
|
||||
//! }).ok();
|
||||
//! ```
|
||||
//!
|
||||
//! The type of `msg` in the callback is [`Message`](struct.Message.html).
|
||||
//!
|
||||
//! Note that you must keep the `_callback` object alive for as long as you want your callback to
|
||||
//! be callable. If you don't store the return value of `DebugCallback`'s constructor in a
|
||||
//! variable, it will be immediately destroyed and your callback will not work.
|
||||
@ -68,7 +71,7 @@ impl DebugCallback {
|
||||
/// Panics generated by calling `user_callback` are ignored.
|
||||
pub fn new<F>(instance: &Arc<Instance>, messages: MessageTypes, user_callback: F)
|
||||
-> Result<DebugCallback, DebugCallbackCreationError>
|
||||
where F: Fn(&Message) + 'static + panic::RefUnwindSafe
|
||||
where F: Fn(&Message) + 'static + Send + panic::RefUnwindSafe
|
||||
{
|
||||
if !instance.loaded_extensions().ext_debug_report {
|
||||
return Err(DebugCallbackCreationError::MissingExtension);
|
||||
@ -156,7 +159,7 @@ impl DebugCallback {
|
||||
#[inline]
|
||||
pub fn errors_and_warnings<F>(instance: &Arc<Instance>, user_callback: F)
|
||||
-> Result<DebugCallback, DebugCallbackCreationError>
|
||||
where F: Fn(&Message) + 'static + panic::RefUnwindSafe
|
||||
where F: Fn(&Message) + Send + 'static + panic::RefUnwindSafe
|
||||
{
|
||||
DebugCallback::new(instance, MessageTypes::errors_and_warnings(), user_callback)
|
||||
}
|
||||
|
@ -9,8 +9,21 @@
|
||||
|
||||
//! Allows you to create surfaces that fill a whole display, outside of the windowing system.
|
||||
//!
|
||||
//! As far as the author knows, no existing device supports these features. Therefore the code here
|
||||
//! is mostly a draft and needs rework in both the API and the implementation.
|
||||
//! **As far as the author knows, no existing device supports these features. Therefore the code
|
||||
//! here is mostly a draft and needs rework in both the API and the implementation.**
|
||||
//!
|
||||
//! The purpose of the objects in this module is to let you create a `Surface` object that
|
||||
//! represents a location on the screen. This is done in four steps:
|
||||
//!
|
||||
//! - Choose a `Display` where the surface will be located. A `Display` represents a display
|
||||
//! display, usually a monitor. The available displays can be enumerated with
|
||||
//! `Display::enumerate`.
|
||||
//! - Choose a `DisplayMode`, which is the combination of a display, a resolution and a refresh
|
||||
//! rate. You can enumerate the modes available on a display with `Display::display_modes`, or
|
||||
//! attempt to create your own mode with `TODO`.
|
||||
//! - Choose a `DisplayPlane`. A display can show multiple planes in a stacking fashion.
|
||||
//! - Create a `Surface` object with `Surface::from_display_mode` and pass the chosen `DisplayMode`
|
||||
//! and `DisplayPlane`.
|
||||
|
||||
#![allow(dead_code)] // TODO: this module isn't finished
|
||||
#![allow(unused_variables)] // TODO: this module isn't finished
|
||||
@ -22,6 +35,7 @@ use std::vec::IntoIter;
|
||||
|
||||
use instance::Instance;
|
||||
use instance::PhysicalDevice;
|
||||
use swapchain::SupportedSurfaceTransforms;
|
||||
|
||||
use check_errors;
|
||||
use OomError;
|
||||
@ -33,6 +47,7 @@ use vk;
|
||||
|
||||
/// ?
|
||||
// TODO: plane capabilities
|
||||
// TODO: store properties in the instance?
|
||||
pub struct DisplayPlane {
|
||||
instance: Arc<Instance>,
|
||||
physical_device: usize,
|
||||
@ -111,6 +126,12 @@ impl DisplayPlane {
|
||||
PhysicalDevice::from_index(&self.instance, self.physical_device).unwrap()
|
||||
}
|
||||
|
||||
/// Returns the index of the plane.
|
||||
#[inline]
|
||||
pub fn index(&self) -> u32 {
|
||||
self.index
|
||||
}
|
||||
|
||||
/// Returns true if this plane supports the given display.
|
||||
#[inline]
|
||||
pub fn supports(&self, display: &Display) -> bool {
|
||||
@ -124,6 +145,7 @@ impl DisplayPlane {
|
||||
}
|
||||
|
||||
/// Represents a monitor connected to a physical device.
|
||||
// TODO: store properties in the instance?
|
||||
#[derive(Clone)]
|
||||
pub struct Display {
|
||||
instance: Arc<Instance>,
|
||||
@ -179,8 +201,9 @@ impl Display {
|
||||
#[inline]
|
||||
pub fn name(&self) -> &str {
|
||||
unsafe {
|
||||
CStr::from_ptr(self.properties.displayName).to_str()
|
||||
.expect("non UTF-8 characters in display name")
|
||||
CStr::from_ptr(self.properties.displayName)
|
||||
.to_str()
|
||||
.expect("non UTF-8 characters in display name")
|
||||
}
|
||||
}
|
||||
|
||||
@ -190,13 +213,41 @@ impl Display {
|
||||
PhysicalDevice::from_index(&self.instance, self.physical_device).unwrap()
|
||||
}
|
||||
|
||||
/// Returns the physical resolution of the display.
|
||||
/// Returns the physical dimensions of the display in millimeters.
|
||||
#[inline]
|
||||
pub fn physical_dimensions(&self) -> [u32; 2] {
|
||||
let ref r = self.properties.physicalDimensions;
|
||||
[r.width, r.height]
|
||||
}
|
||||
|
||||
/// Returns the physical, native, or preferred resolution of the display.
|
||||
///
|
||||
/// > **Note**: The display is usually still capable of displaying other resolutions. This is
|
||||
/// > only the "best" resolution.
|
||||
#[inline]
|
||||
pub fn physical_resolution(&self) -> [u32; 2] {
|
||||
let ref r = self.properties.physicalResolution;
|
||||
[r.width, r.height]
|
||||
}
|
||||
|
||||
/// Returns the transforms supported by this display.
|
||||
#[inline]
|
||||
pub fn supported_transforms(&self) -> SupportedSurfaceTransforms {
|
||||
SupportedSurfaceTransforms::from_bits(self.properties.supportedTransforms)
|
||||
}
|
||||
|
||||
/// Returns true if TODO.
|
||||
#[inline]
|
||||
pub fn plane_reorder_possible(&self) -> bool {
|
||||
self.properties.planeReorderPossible != 0
|
||||
}
|
||||
|
||||
/// Returns true if TODO.
|
||||
#[inline]
|
||||
pub fn persistent_content(&self) -> bool {
|
||||
self.properties.persistentContent != 0
|
||||
}
|
||||
|
||||
/// See the docs of display_modes().
|
||||
pub fn display_modes_raw(&self) -> Result<IntoIter<DisplayMode>, OomError> {
|
||||
let vk = self.instance.pointers();
|
||||
|
@ -188,6 +188,7 @@
|
||||
//!
|
||||
|
||||
use std::sync::atomic::AtomicBool;
|
||||
use vk;
|
||||
|
||||
pub use self::surface::Capabilities;
|
||||
pub use self::surface::Surface;
|
||||
@ -204,6 +205,113 @@ 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.
|
||||
unsafe trait SurfaceSwapchainLock {
|
||||
|
@ -21,6 +21,7 @@ use instance::Instance;
|
||||
use instance::PhysicalDevice;
|
||||
use instance::QueueFamily;
|
||||
use swapchain::SurfaceSwapchainLock;
|
||||
use swapchain::SupportedSurfaceTransforms;
|
||||
use swapchain::display::DisplayMode;
|
||||
use swapchain::display::DisplayPlane;
|
||||
|
||||
@ -55,8 +56,7 @@ impl Surface {
|
||||
pub fn from_display_mode(display_mode: &DisplayMode, plane: &DisplayPlane)
|
||||
-> Result<Arc<Surface>, SurfaceCreationError>
|
||||
{
|
||||
unimplemented!() // TODO:
|
||||
/*if !display_mode.display().physical_device().instance().loaded_extensions().khr_display {
|
||||
if !display_mode.display().physical_device().instance().loaded_extensions().khr_display {
|
||||
return Err(SurfaceCreationError::MissingExtension { name: "VK_KHR_display" });
|
||||
}
|
||||
|
||||
@ -73,14 +73,14 @@ impl Surface {
|
||||
pNext: ptr::null(),
|
||||
flags: 0, // reserved
|
||||
displayMode: display_mode.internal_object(),
|
||||
planeIndex: plane.index,
|
||||
planeStackIndex: plane.properties.currentStackIndex,
|
||||
planeIndex: plane.index(),
|
||||
planeStackIndex: 0, // FIXME: plane.properties.currentStackIndex,
|
||||
transform: vk::SURFACE_TRANSFORM_IDENTITY_BIT_KHR, // TODO: let user choose
|
||||
globalAlpha: 0.0, // TODO: let user choose
|
||||
alphaMode: vk::DISPLAY_PLANE_ALPHA_OPAQUE_BIT_KHR, // TODO: let user choose
|
||||
imageExtent: vk::Extent2D { // TODO: let user choose
|
||||
width: display_mode.parameters.visibleRegion.width,
|
||||
height: display_mode.parameters.visibleRegion.height,
|
||||
width: display_mode.visible_region()[0],
|
||||
height: display_mode.visible_region()[1],
|
||||
},
|
||||
};
|
||||
|
||||
@ -93,7 +93,8 @@ impl Surface {
|
||||
Ok(Arc::new(Surface {
|
||||
instance: instance.clone(),
|
||||
surface: surface,
|
||||
}))*/
|
||||
has_swapchain: AtomicBool::new(false),
|
||||
}))
|
||||
}
|
||||
|
||||
/// Creates a `Surface` from a Win32 window.
|
||||
@ -685,113 +686,6 @@ pub enum SurfaceTransform {
|
||||
Inherit = vk::SURFACE_TRANSFORM_INHERIT_BIT_KHR,
|
||||
}
|
||||
|
||||
/// 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: u32) -> 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
|
||||
}
|
||||
}
|
||||
|
||||
/// How the alpha values of the pixels of the window are treated.
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
||||
#[repr(u32)]
|
||||
|
@ -10,9 +10,10 @@
|
||||
// The `Version` object is reexported from the `instance` module.
|
||||
|
||||
use std::cmp::Ordering;
|
||||
use std::fmt;
|
||||
|
||||
/// Represents an API version of Vulkan.
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
|
||||
#[derive(Copy, Clone, PartialEq, Eq)]
|
||||
pub struct Version {
|
||||
/// Major version number.
|
||||
pub major: u16,
|
||||
@ -22,6 +23,18 @@ pub struct Version {
|
||||
pub patch: u16,
|
||||
}
|
||||
|
||||
impl fmt::Debug for Version {
|
||||
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(formatter, "{}.{}.{}", self.major, self.minor, self.patch)
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for Version {
|
||||
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
||||
fmt::Debug::fmt(self, formatter)
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialOrd for Version {
|
||||
#[inline]
|
||||
fn partial_cmp(&self, other: &Version) -> Option<Ordering> {
|
||||
|
Loading…
Reference in New Issue
Block a user