diff --git a/.travis.yml b/.travis.yml index 2a33bb8ed84..8cbd2895f07 100644 --- a/.travis.yml +++ b/.travis.yml @@ -32,13 +32,15 @@ addons: - libxcursor1 - libsdl2-dev script: - - travis-cargo build + - travis-cargo build -- --features vulkan - travis-cargo test -- -p gfx_core - travis-cargo test -- -p gfx - travis-cargo test -- -p gfx_device_gl - travis-cargo test -- -p gfx_window_glutin - travis-cargo test -- -p gfx_window_glfw - travis-cargo test -- -p gfx_window_sdl +# - travis-cargo test -- -p gfx_device_vulkan +# - travis-cargo test -- -p gfx_window_vulkan - travis-cargo test after_success: - travis-cargo doc -- -j 1 diff --git a/Cargo.toml b/Cargo.toml index 4cf118c6908..275645aed6a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,8 +8,11 @@ license = "Apache-2.0" authors = ["The Gfx-rs Developers"] [features] +default = [] +vulkan = ["gfx_device_vulkan", "gfx_window_vulkan"] unstable = [] + [lib] name = "gfx_app" @@ -17,18 +20,28 @@ name = "gfx_app" env_logger = "0.3" glutin = "0.6" winit = "0.5.1" -gfx_core = { path = "src/core", version = "0.4" } -gfx_device_gl = { path = "src/backend/gl", version = "0.11" } -gfx_window_glutin = { path = "src/window/glutin", version = "0.12" } -gfx = { path = "src/render", version = "0.12" } +gfx_core = { path = "src/core", version = "0.5" } +gfx = { path = "src/render", version = "0.13" } +gfx_device_gl = { path = "src/backend/gl", version = "0.12" } +gfx_window_glutin = { path = "src/window/glutin", version = "0.13" } + +[dependencies.gfx_device_vulkan] +path = "src/backend/vulkan" +version = "0.1" +optional = true + +[dependencies.gfx_window_vulkan] +path = "src/window/vulkan" +version = "0.1" +optional = true [target.'cfg(unix)'.dependencies] -gfx_window_glfw = { path = "src/window/glfw", version = "0.11" } -gfx_window_sdl = { path = "src/window/sdl", version = "0.3" } +gfx_window_glfw = { path = "src/window/glfw", version = "0.12" } +gfx_window_sdl = { path = "src/window/sdl", version = "0.4" } [target.'cfg(windows)'.dependencies] -gfx_device_dx11 = { path = "src/backend/dx11", version = "0.3" } -gfx_window_dxgi = { path = "src/window/dxgi", version = "0.3" } +gfx_device_dx11 = { path = "src/backend/dx11", version = "0.4" } +gfx_window_dxgi = { path = "src/window/dxgi", version = "0.4" } [target.x86_64-apple-darwin.dependencies] gfx_device_metal = { path = "src/backend/metal", version = "0.1" } @@ -90,6 +103,7 @@ rand = "0.3" genmesh = "0.4" noise = "0.1" image = "0.6" +winit = "0.5" [target.x86_64-unknown-linux-gnu.dev_dependencies] glfw = "0.5" diff --git a/appveyor.yml b/appveyor.yml index 6eecc0146c8..2c1be3bb197 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -7,7 +7,7 @@ environment: - TARGET: nightly-x86_64-pc-windows COMPILER: msvc install: - - if %COMPILER%==gnu choco install mingw + - if %COMPILER%==gnu choco install -y mingw - ps: Start-FileDownload "https://static.rust-lang.org/dist/rust-${env:TARGET}-${env:COMPILER}.exe" -FileName "rust-install.exe" - ps: .\rust-install.exe /VERYSILENT /NORESTART /DIR="C:\rust" | Out-Null - ps: $env:PATH="$env:PATH;C:\rust\bin;C:\tools\mingw64\bin" diff --git a/examples/cube/data/frag.spv b/examples/cube/data/frag.spv new file mode 100644 index 00000000000..088196b57a6 Binary files /dev/null and b/examples/cube/data/frag.spv differ diff --git a/examples/cube/data/vert.spv b/examples/cube/data/vert.spv new file mode 100644 index 00000000000..45be2099713 Binary files /dev/null and b/examples/cube/data/vert.spv differ diff --git a/examples/cube/main.rs b/examples/cube/main.rs index ae2517e2190..aa5d58c702b 100644 --- a/examples/cube/main.rs +++ b/examples/cube/main.rs @@ -72,6 +72,7 @@ impl gfx_app::Application for App { glsl_es_100: include_bytes!("shader/cube_100_es.glslv"), hlsl_40: include_bytes!("data/vertex.fx"), msl_11: include_bytes!("shader/cube_vertex.metal"), + vulkan: include_bytes!("data/vert.spv"), .. gfx_app::shade::Source::empty() }; let ps = gfx_app::shade::Source { @@ -80,6 +81,7 @@ impl gfx_app::Application for App { glsl_es_100: include_bytes!("shader/cube_100_es.glslf"), hlsl_40: include_bytes!("data/pixel.fx"), msl_11: include_bytes!("shader/cube_frag.metal"), + vulkan: include_bytes!("data/frag.spv"), .. gfx_app::shade::Source::empty() }; diff --git a/examples/cube/shader/cube_150.glslv b/examples/cube/shader/cube_150.glslv index 36f71abbac8..f8567c42b75 100644 --- a/examples/cube/shader/cube_150.glslv +++ b/examples/cube/shader/cube_150.glslv @@ -4,9 +4,12 @@ in vec4 a_Pos; in vec2 a_TexCoord; out vec2 v_TexCoord; -uniform mat4 u_Transform; +uniform Locals { + mat4 u_Transform; +}; void main() { v_TexCoord = a_TexCoord; gl_Position = u_Transform * a_Pos; + gl_ClipDistance[0] = 1.0; } diff --git a/examples/cube/shader/make_vulkan.sh b/examples/cube/shader/make_vulkan.sh new file mode 100755 index 00000000000..adac1f551c5 --- /dev/null +++ b/examples/cube/shader/make_vulkan.sh @@ -0,0 +1,11 @@ +#!/bin/sh + +echo Compiling... +ln -s cube_150.glslv out.vert +ln -s cube_150.glslf out.frag +glslangValidator -V -o ../data/vert.spv out.vert +glslangValidator -V -o ../data/frag.spv out.frag +rm out.vert out.frag +echo Validating... +spirv-val ../data/vert.spv +spirv-val ../data/frag.spv diff --git a/examples/deferred/shader/light.glslf b/examples/deferred/shader/light.glslf index ef498266143..fb5c60591e0 100644 --- a/examples/deferred/shader/light.glslf +++ b/examples/deferred/shader/light.glslf @@ -2,7 +2,7 @@ layout(std140) uniform LightLocals { - vec4 u_CameraPosAndRadius; + vec4 u_CamPosAndRadius; }; uniform sampler2D t_Position; uniform sampler2D t_Normal; @@ -18,14 +18,14 @@ void main() { vec3 light = v_LightPos; vec3 to_light = normalize(light - pos); - vec3 to_cam = normalize(u_CameraPosAndRadius.xyz - pos); + vec3 to_cam = normalize(u_CamPosAndRadius.xyz - pos); vec3 n = normalize(normal); float s = pow(max(0.0, dot(to_cam, reflect(-to_light, n))), 20.0); float d = max(0.0, dot(n, to_light)); float dist_sq = dot(light - pos, light - pos); - float scale = max(0.0, 1.0 - dist_sq * u_CameraPosAndRadius.w); + float scale = max(0.0, 1.0 - dist_sq * u_CamPosAndRadius.w); vec3 res_color = d * diffuse + vec3(s); diff --git a/examples/performance/main.rs b/examples/performance/main.rs index 2a39dec472e..c741a29aae3 100644 --- a/examples/performance/main.rs +++ b/examples/performance/main.rs @@ -150,10 +150,6 @@ impl GFX { } } -fn duration_to_f64(dur: Duration) -> f64 { - dur.as_secs() as f64 + dur.subsec_nanos() as f64 / 1000_000_000.0 -} - impl Renderer for GFX { fn render(&mut self, proj_view: &Matrix4) { let start = Instant::now(); diff --git a/examples/shadow/main.rs b/examples/shadow/main.rs index ba91c09b545..37b92b30506 100644 --- a/examples/shadow/main.rs +++ b/examples/shadow/main.rs @@ -194,14 +194,13 @@ struct Scene> { // Section-4: scene construction routines /// Create a full scene -fn create_scene(factory: &mut F, encoder: &gfx::Encoder, +fn create_scene(factory: &mut F, out_color: gfx::handle::RenderTargetView, out_depth: gfx::handle::DepthStencilView, shadow_pso: gfx::PipelineState) - -> Scene where + -> Scene where R: gfx::Resources, - F: gfx::Factory, - C: gfx::CommandBuffer, + F: gfx_app::Factory, { use cgmath::{SquareMatrix, Matrix4, deg}; use gfx::traits::FactoryExt; @@ -264,7 +263,7 @@ fn create_scene(factory: &mut F, encoder: &gfx::Encoder, shadow: factory.view_texture_as_depth_stencil( &shadow_tex, 0, Some(i as gfx::Layer), gfx::tex::DepthStencilFlags::empty(), ).unwrap(), - encoder: encoder.clone_empty(), + encoder: factory.create_encoder(), }).collect(); let light_buf = factory.create_constant_buffer(MAX_LIGHTS); @@ -424,8 +423,8 @@ impl gfx_app::ApplicationBase for App where R: gfx::Resources + 'static, C: gfx::CommandBuffer + Send + 'static, { - fn new(mut factory: F, encoder: gfx::Encoder, init: gfx_app::Init) -> Self where - F: gfx::Factory + fn new(mut factory: F, init: gfx_app::Init) -> Self where + F: gfx_app::Factory, { use std::env; use gfx::traits::FactoryExt; @@ -487,7 +486,7 @@ impl gfx_app::ApplicationBase for App where ).unwrap() }; - let scene = create_scene(&mut factory, &encoder, + let scene = create_scene(&mut factory, init.color.clone(), init.depth.clone(), shadow_pso); @@ -495,7 +494,7 @@ impl gfx_app::ApplicationBase for App where init: init, is_parallel: is_parallel, forward_pso: forward_pso, - encoder: encoder, + encoder: factory.create_encoder(), scene: scene, } } diff --git a/examples/terrain/data/frag.spv b/examples/terrain/data/frag.spv new file mode 100644 index 00000000000..26fd8b75965 Binary files /dev/null and b/examples/terrain/data/frag.spv differ diff --git a/examples/terrain/data/vert.spv b/examples/terrain/data/vert.spv new file mode 100644 index 00000000000..18a8a3b01c6 Binary files /dev/null and b/examples/terrain/data/vert.spv differ diff --git a/examples/terrain/main.rs b/examples/terrain/main.rs index 641b2485eee..f469f03c506 100644 --- a/examples/terrain/main.rs +++ b/examples/terrain/main.rs @@ -82,6 +82,7 @@ impl gfx_app::Application for App { glsl_150: include_bytes!("shader/terrain_150.glslv"), hlsl_40: include_bytes!("data/vertex.fx"), msl_11: include_bytes!("shader/terrain_vertex.metal"), + vulkan: include_bytes!("data/vert.spv"), .. gfx_app::shade::Source::empty() }; let ps = gfx_app::shade::Source { @@ -89,6 +90,7 @@ impl gfx_app::Application for App { glsl_150: include_bytes!("shader/terrain_150.glslf"), hlsl_40: include_bytes!("data/pixel.fx"), msl_11: include_bytes!("shader/terrain_frag.metal"), + vulkan: include_bytes!("data/frag.spv"), .. gfx_app::shade::Source::empty() }; diff --git a/examples/terrain/shader/make_vulkan.sh b/examples/terrain/shader/make_vulkan.sh new file mode 100755 index 00000000000..311add726d1 --- /dev/null +++ b/examples/terrain/shader/make_vulkan.sh @@ -0,0 +1,11 @@ +#!/bin/sh + +echo Compiling... +ln -s terrain_150.glslv out.vert +ln -s terrain_150.glslf out.frag +glslangValidator -V -o ../data/vert.spv out.vert +glslangValidator -V -o ../data/frag.spv out.frag +rm out.vert out.frag +echo Validating... +spirv-val ../data/vert.spv +spirv-val ../data/frag.spv diff --git a/examples/terrain/shader/terrain_150.glslv b/examples/terrain/shader/terrain_150.glslv index b8927d6041d..4e122ccfd99 100644 --- a/examples/terrain/shader/terrain_150.glslv +++ b/examples/terrain/shader/terrain_150.glslv @@ -13,4 +13,5 @@ uniform Locals { void main() { v_Color = a_Color; gl_Position = u_Proj * u_View * u_Model * vec4(a_Pos, 1.0); + gl_ClipDistance[0] = 1.0; } diff --git a/examples/triangle/main.rs b/examples/triangle/main.rs index c334f12566d..7cbaf1ea51f 100644 --- a/examples/triangle/main.rs +++ b/examples/triangle/main.rs @@ -15,7 +15,6 @@ #[macro_use] extern crate gfx; extern crate gfx_window_glutin; -extern crate gfx_device_gl; extern crate glutin; use gfx::traits::FactoryExt; diff --git a/src/backend/dx11/Cargo.toml b/src/backend/dx11/Cargo.toml index 1d9b3e6ffae..256e3cd8a4d 100644 --- a/src/backend/dx11/Cargo.toml +++ b/src/backend/dx11/Cargo.toml @@ -14,7 +14,7 @@ [package] name = "gfx_device_dx11" -version = "0.3.0" +version = "0.4.0" description = "DirectX-11 backend for gfx-rs" homepage = "https://github.com/gfx-rs/gfx" repository = "https://github.com/gfx-rs/gfx" @@ -27,7 +27,7 @@ name = "gfx_device_dx11" [dependencies] log = "0.3" -gfx_core = { path = "../../core", version = "0.4" } +gfx_core = { path = "../../core", version = "0.5" } d3d11-sys = "0.2" d3dcompiler-sys = "0.2" dxguid-sys = "0.2" diff --git a/src/backend/dx11/src/command.rs b/src/backend/dx11/src/command.rs index 90ef6d276ae..7047d7d63c3 100644 --- a/src/backend/dx11/src/command.rs +++ b/src/backend/dx11/src/command.rs @@ -91,7 +91,7 @@ pub enum Command { unsafe impl Send for Command {} struct Cache { - attributes: [Option; MAX_VERTEX_ATTRIBUTES], + attrib_strides: [Option; MAX_VERTEX_ATTRIBUTES], rasterizer: *const ID3D11RasterizerState, depth_stencil: *const ID3D11DepthStencilState, stencil_ref: UINT, @@ -103,7 +103,7 @@ unsafe impl Send for Cache {} impl Cache { fn new() -> Cache { Cache { - attributes: [None; MAX_VERTEX_ATTRIBUTES], + attrib_strides: [None; MAX_VERTEX_ATTRIBUTES], rasterizer: ptr::null(), depth_stencil: ptr::null(), stencil_ref: 0, @@ -119,7 +119,6 @@ pub struct CommandBuffer

{ } pub trait Parser: Sized { - fn clone_empty(&self) -> Self; fn reset(&mut self); fn parse(&mut self, Command); fn update_buffer(&mut self, Buffer, &[u8], usize); @@ -144,10 +143,6 @@ impl CommandBuffer

{ } impl draw::CommandBuffer for CommandBuffer

{ - fn clone_empty(&self) -> CommandBuffer

{ - self.parser.clone_empty().into() - } - fn reset(&mut self) { self.parser.reset(); self.cache = Cache::new(); @@ -155,7 +150,15 @@ impl draw::CommandBuffer for CommandBuffer

{ fn bind_pipeline_state(&mut self, pso: Pipeline) { self.parser.parse(Command::SetPrimitive(pso.topology)); - self.cache.attributes = pso.attributes; + for (stride, ad_option) in self.cache.attrib_strides.iter_mut().zip(pso.attributes.iter()) { + *stride = ad_option.map(|(buf_id, _)| match pso.vertex_buffers[buf_id as usize] { + Some(ref bdesc) => bdesc.stride, + None => { + error!("Unexpected use of buffer id {}", buf_id); + 0 + }, + }); + } if self.cache.rasterizer != pso.rasterizer { self.cache.rasterizer = pso.rasterizer; self.parser.parse(Command::SetRasterizer(pso.rasterizer)); @@ -167,17 +170,18 @@ impl draw::CommandBuffer for CommandBuffer

{ } fn bind_vertex_buffers(&mut self, vbs: pso::VertexBufferSet) { + //Note: assumes `bind_pipeline_state` is called prior let mut buffers = [native::Buffer(ptr::null_mut()); MAX_VERTEX_ATTRIBUTES]; let mut strides = [0; MAX_VERTEX_ATTRIBUTES]; let mut offsets = [0; MAX_VERTEX_ATTRIBUTES]; for i in 0 .. MAX_VERTEX_ATTRIBUTES { - match (vbs.0[i], self.cache.attributes[i]) { - (None, Some(fm)) => { - error!("No vertex input provided for slot {} of format {:?}", i, fm) + match (vbs.0[i], self.cache.attrib_strides[i]) { + (None, Some(stride)) => { + error!("No vertex input provided for slot {} with stride {}", i, stride) }, - (Some((buffer, offset)), Some(ref format)) => { + (Some((buffer, offset)), Some(stride)) => { buffers[i] = buffer.0; - strides[i] = format.0.stride as UINT; + strides[i] = stride as UINT; offsets[i] = offset as UINT; }, (_, None) => (), diff --git a/src/backend/dx11/src/factory.rs b/src/backend/dx11/src/factory.rs index 13888516b49..8f4a035aac6 100644 --- a/src/backend/dx11/src/factory.rs +++ b/src/backend/dx11/src/factory.rs @@ -446,8 +446,11 @@ impl core::Factory for Factory { let mut charpos = 0; for (attrib, at_desc) in program.get_info().vertex_attributes.iter().zip(desc.attributes.iter()) { use winapi::UINT; - let (elem, irate) = match at_desc { - &Some((ref el, ir)) => (el, ir), + let (bdesc, elem) = match at_desc { + &Some((buf_id, ref el)) => match desc.vertex_buffers[buf_id as usize] { + Some(ref bd) => (bd, el), + None => return Err(core::pso::CreationError), + }, &None => continue, }; if elem.offset & 1 != 0 { @@ -467,12 +470,12 @@ impl core::Factory for Factory { }, InputSlot: attrib.slot as UINT, AlignedByteOffset: elem.offset as UINT, - InputSlotClass: if irate == 0 { + InputSlotClass: if bdesc.rate == 0 { winapi::D3D11_INPUT_PER_VERTEX_DATA }else { winapi::D3D11_INPUT_PER_INSTANCE_DATA }, - InstanceDataStepRate: irate as UINT, + InstanceDataStepRate: bdesc.rate as UINT, }); for (out, inp) in charbuf[charpos..].iter_mut().zip(attrib.name.as_bytes().iter()) { *out = *inp as i8; @@ -513,6 +516,7 @@ impl core::Factory for Factory { TriangleStrip => D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP, }, layout: vertex_layout, + vertex_buffers: desc.vertex_buffers, attributes: desc.attributes, program: prog, rasterizer: state::make_rasterizer(dev, &desc.rasterizer, desc.scissor), @@ -610,6 +614,7 @@ impl core::Factory for Factory { use winapi::UINT; use gfx_core::tex::{AaMode, Kind}; use data::map_format; + //TODO: support desc.layer parsing let (dim, layers, has_levels) = match htex.get_info().kind { Kind::D1(_) => @@ -703,8 +708,8 @@ impl core::Factory for Factory { (winapi::D3D11_RTV_DIMENSION_TEXTURE2DARRAY, [level, 0, 6 * nlayers as UINT]), (Kind::CubeArray(_, nlayers), Some(lid)) if lid < nlayers => (winapi::D3D11_RTV_DIMENSION_TEXTURE2DARRAY, [level, 6 * lid as UINT, 6 * (1+lid) as UINT]), - (_, None) => return Err(f::TargetViewError::BadLevel(desc.level)), - (_, Some(lid)) => return Err(f::TargetViewError::BadLayer(lid)), + (_, None) => return Err(f::TargetViewError::Level(desc.level)), + (_, Some(lid)) => return Err(f::TargetViewError::Layer(f::LayerError::OutOfBounds(lid, 0))), //TODO }; let format = core::format::Format(htex.get_info().format, desc.channel); let native_desc = winapi::D3D11_RENDER_TARGET_VIEW_DESC { @@ -764,8 +769,8 @@ impl core::Factory for Factory { (winapi::D3D11_DSV_DIMENSION_TEXTURE2DARRAY, [level, 0, 6 * nlayers as UINT]), (Kind::CubeArray(_, nlayers), Some(lid)) if lid < nlayers => (winapi::D3D11_DSV_DIMENSION_TEXTURE2DARRAY, [level, 6 * lid as UINT, 6 * (1+lid) as UINT]), - (_, None) => return Err(f::TargetViewError::BadLevel(desc.level)), - (_, Some(lid)) => return Err(f::TargetViewError::BadLayer(lid)), + (_, None) => return Err(f::TargetViewError::Level(desc.level)), + (_, Some(lid)) => return Err(f::TargetViewError::Layer(f::LayerError::OutOfBounds(lid, 0))), //TODO }; let channel = core::format::ChannelType::Uint; //doesn't matter diff --git a/src/backend/dx11/src/lib.rs b/src/backend/dx11/src/lib.rs index 27a3c32eaaf..874f0f20c3c 100644 --- a/src/backend/dx11/src/lib.rs +++ b/src/backend/dx11/src/lib.rs @@ -123,6 +123,7 @@ pub type InputLayout = *mut winapi::ID3D11InputLayout; pub struct Pipeline { topology: winapi::D3D11_PRIMITIVE_TOPOLOGY, layout: InputLayout, + vertex_buffers: [Option; gfx_core::pso::MAX_VERTEX_BUFFERS], attributes: [Option; gfx_core::MAX_VERTEX_ATTRIBUTES], program: Program, rasterizer: *const winapi::ID3D11RasterizerState, @@ -268,9 +269,6 @@ impl CommandList { } } impl command::Parser for CommandList { - fn clone_empty(&self) -> CommandList { - CommandList(Vec::with_capacity(self.0.capacity()), command::DataBuffer::new()) - } fn reset(&mut self) { self.0.clear(); self.1.reset(); @@ -300,10 +298,6 @@ impl Drop for DeferredContext { } } impl command::Parser for DeferredContext { - fn clone_empty(&self) -> DeferredContext { - unsafe { (*self.0).AddRef() }; - DeferredContext(self.0, None) - } fn reset(&mut self) { if let Some(cl) = self.1 { unsafe { (*cl).Release() }; diff --git a/src/backend/gl/Cargo.toml b/src/backend/gl/Cargo.toml index 8ccf2038835..0cbd94db13b 100644 --- a/src/backend/gl/Cargo.toml +++ b/src/backend/gl/Cargo.toml @@ -14,7 +14,7 @@ [package] name = "gfx_device_gl" -version = "0.11.2" +version = "0.12.0" description = "OpenGL backend for gfx-rs" homepage = "https://github.com/gfx-rs/gfx" repository = "https://github.com/gfx-rs/gfx" @@ -28,4 +28,4 @@ name = "gfx_device_gl" [dependencies] log = "0.3" gfx_gl = "0.3.1" -gfx_core = { path = "../../core", version = "0.4" } +gfx_core = { path = "../../core", version = "0.5" } diff --git a/src/backend/gl/src/command.rs b/src/backend/gl/src/command.rs index b2ff468b6fe..c19216a4f15 100644 --- a/src/backend/gl/src/command.rs +++ b/src/backend/gl/src/command.rs @@ -19,7 +19,7 @@ use gfx_core as c; use gfx_core::draw; use gfx_core::state as s; use gfx_core::target::{ColorValue, Depth, Mirror, Rect, Stencil}; -use {Buffer, Program, FrameBuffer, Texture, +use {Buffer, BufferElement, Program, FrameBuffer, Texture, NewTexture, Resources, PipelineState, ResourceView, TargetView}; @@ -68,6 +68,7 @@ impl DataBuffer { } } + ///Serialized device command. #[derive(Clone, Copy, Debug)] pub enum Command { @@ -78,7 +79,7 @@ pub enum Command { BindUnorderedView(c::pso::UnorderedViewParam), BindSampler(c::pso::SamplerParam, Option), BindPixelTargets(c::pso::PixelTargetSet), - BindAttribute(c::AttributeSlot, Buffer, c::pso::AttributeDesc), + BindAttribute(c::AttributeSlot, Buffer, BufferElement), BindIndex(Buffer), BindFrameBuffer(Access, FrameBuffer), BindUniform(c::shade::Location, c::shade::UniformValue), @@ -134,7 +135,7 @@ pub const RESET: [Command; 13] = [ struct Cache { primitive: gl::types::GLenum, index_type: c::IndexType, - attributes: [Option; c::MAX_VERTEX_ATTRIBUTES], + attributes: [Option; c::MAX_VERTEX_ATTRIBUTES], resource_binds: [Option; c::MAX_RESOURCE_VIEWS], scissor: bool, stencil: Option, @@ -184,10 +185,6 @@ impl CommandBuffer { } impl c::draw::CommandBuffer for CommandBuffer { - fn clone_empty(&self) -> CommandBuffer { - CommandBuffer::new(self.fbo) - } - fn reset(&mut self) { self.buf.clear(); self.data.0.clear(); @@ -219,9 +216,9 @@ impl c::draw::CommandBuffer for CommandBuffer { (None, Some(fm)) => { error!("No vertex input provided for slot {} of format {:?}", i, fm) }, - (Some((buffer, offset)), Some(mut format)) => { - format.0.offset += offset as gl::types::GLuint; - self.buf.push(Command::BindAttribute(i as c::AttributeSlot, buffer, format)); + (Some((buffer, offset)), Some(mut bel)) => { + bel.elem.offset += offset as gl::types::GLuint; + self.buf.push(Command::BindAttribute(i as c::AttributeSlot, buffer, bel)); }, (_, None) => (), } diff --git a/src/backend/gl/src/factory.rs b/src/backend/gl/src/factory.rs index 29630908b5b..2b1c44159fc 100644 --- a/src/backend/gl/src/factory.rs +++ b/src/backend/gl/src/factory.rs @@ -28,7 +28,8 @@ use gfx_core::tex as t; use command::{CommandBuffer, COLOR_DEFAULT}; use {Resources as R, Share, OutputMerger}; -use {Buffer, FatSampler, NewTexture, PipelineState, ResourceView, TargetView}; +use {Buffer, BufferElement, FatSampler, NewTexture, + PipelineState, ResourceView, TargetView}; fn role_to_target(role: f::BufferRole) -> gl::types::GLenum { @@ -261,10 +262,17 @@ impl d::Factory for Factory { } } } + let mut inputs = [None; d::MAX_VERTEX_ATTRIBUTES]; + for i in 0 .. d::MAX_VERTEX_ATTRIBUTES { + inputs[i] = desc.attributes[i].map(|at| BufferElement { + desc: desc.vertex_buffers[at.0 as usize].unwrap(), + elem: at.1, + }); + } let pso = PipelineState { program: *self.frame_handles.ref_program(program), primitive: desc.primitive, - input: desc.attributes, + input: inputs, scissor: desc.scissor, rasterizer: desc.rasterizer, output: output, diff --git a/src/backend/gl/src/lib.rs b/src/backend/gl/src/lib.rs index d2edac45b2e..5dfad509ce0 100644 --- a/src/backend/gl/src/lib.rs +++ b/src/backend/gl/src/lib.rs @@ -75,6 +75,12 @@ impl d::Resources for Resources { type Fence = Fence; } +#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] +pub struct BufferElement { + pub desc: d::pso::VertexBufferDesc, + pub elem: d::pso::Element, +} + #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] pub struct OutputMerger { pub draw_mask: u32, @@ -87,7 +93,7 @@ pub struct OutputMerger { pub struct PipelineState { program: Program, primitive: d::Primitive, - input: [Option; d::MAX_VERTEX_ATTRIBUTES], + input: [Option; d::MAX_VERTEX_ATTRIBUTES], scissor: bool, rasterizer: s::Rasterizer, output: OutputMerger, @@ -294,11 +300,10 @@ impl Device { &self.info } - fn bind_attribute(&mut self, slot: d::AttributeSlot, buffer: Buffer, - (elem, instance_rate): d::pso::AttributeDesc) { + fn bind_attribute(&mut self, slot: d::AttributeSlot, buffer: Buffer, bel: BufferElement) { use gfx_core::format::SurfaceType as S; use gfx_core::format::ChannelType as C; - let (fm8, fm16, fm32) = match elem.format.1 { + let (fm8, fm16, fm32) = match bel.elem.format.1 { C::Int | C::Inorm => (gl::BYTE, gl::SHORT, gl::INT), C::Uint | C::Unorm => @@ -309,7 +314,7 @@ impl Device { return } }; - let (count, gl_type) = match elem.format.0 { + let (count, gl_type) = match bel.elem.format.0 { S::R8 => (1, fm8), S::R8_G8 => (2, fm8), S::R8_G8_B8_A8 => (4, fm8), @@ -322,15 +327,15 @@ impl Device { S::R32_G32_B32 => (3, fm32), S::R32_G32_B32_A32 => (4, fm32), _ => { - error!("Unsupported element type: {:?}", elem.format.0); + error!("Unsupported element type: {:?}", bel.elem.format.0); return } }; let gl = &self.share.context; unsafe { gl.BindBuffer(gl::ARRAY_BUFFER, buffer) }; - let offset = elem.offset as *const gl::types::GLvoid; - let stride = elem.stride as gl::types::GLint; - match elem.format.1 { + let offset = bel.elem.offset as *const gl::types::GLvoid; + let stride = bel.desc.stride as gl::types::GLint; + match bel.elem.format.1 { C::Int | C::Uint => unsafe { gl.VertexAttribIPointer(slot as gl::types::GLuint, count, gl_type, stride, offset); @@ -352,8 +357,8 @@ impl Device { unsafe { gl.EnableVertexAttribArray(slot as gl::types::GLuint) }; if self.share.capabilities.instance_rate_supported { unsafe { gl.VertexAttribDivisor(slot as gl::types::GLuint, - instance_rate as gl::types::GLuint) }; - }else if instance_rate != 0 { + bel.desc.rate as gl::types::GLuint) }; + }else if bel.desc.rate != 0 { error!("Instanced arrays are not supported"); } } @@ -490,8 +495,8 @@ impl Device { self.bind_target(point, gl::STENCIL_ATTACHMENT, stencil); } }, - Command::BindAttribute(slot, buffer, desc) => { - self.bind_attribute(slot, buffer, desc); + Command::BindAttribute(slot, buffer, bel) => { + self.bind_attribute(slot, buffer, bel); }, Command::BindIndex(buffer) => { let gl = &self.share.context; diff --git a/src/backend/metal/Cargo.toml b/src/backend/metal/Cargo.toml index 75c860cd09b..2991a10a7f6 100644 --- a/src/backend/metal/Cargo.toml +++ b/src/backend/metal/Cargo.toml @@ -27,7 +27,7 @@ name = "gfx_device_metal" [dependencies] log = "0.3" -gfx_core = { path = "../../core", version = "0.4" } +gfx_core = { path = "../../core", version = "0.5" } cocoa = "0.3" libc = "0.2" objc = "0.1.8" diff --git a/src/backend/vulkan/Cargo.toml b/src/backend/vulkan/Cargo.toml new file mode 100644 index 00000000000..14aac66182b --- /dev/null +++ b/src/backend/vulkan/Cargo.toml @@ -0,0 +1,20 @@ +[package] +name = "gfx_device_vulkan" +version = "0.1.0" +description = "Vulkan API backend for gfx-rs" +homepage = "https://github.com/gfx-rs/gfx" +repository = "https://github.com/gfx-rs/gfx" +keywords = ["graphics", "gamedev"] +license = "Apache-2.0" +authors = ["The Gfx-rs Developers"] + +[lib] +name = "gfx_device_vulkan" + +[dependencies] +log = "0.3" +vk = "0.0" +vk-sys = { git = "https://github.com/sectopod/vulkano", branch = "bind" } +shared_library = "0.1" +winit = "0.5" +gfx_core = { path = "../../core", version = "0.5" } diff --git a/src/backend/vulkan/src/command.rs b/src/backend/vulkan/src/command.rs new file mode 100644 index 00000000000..88664d89529 --- /dev/null +++ b/src/backend/vulkan/src/command.rs @@ -0,0 +1,373 @@ +// Copyright 2016 The Gfx-rs Developers. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use std::{mem, ptr}; +use std::collections::hash_map::{HashMap, Entry}; +use vk; +use gfx_core::{self as core, draw, pso, shade, target, tex}; +use gfx_core::state::RefValues; +use gfx_core::{IndexType, VertexCount}; +use native; +use {Resources, Share, SharePointer}; + + +pub struct Buffer { + inner: vk::CommandBuffer, + parent_pool: vk::CommandPool, + family: u32, + share: SharePointer, + last_render_pass: vk::RenderPass, + fbo_cache: HashMap, vk::Framebuffer>, + temp_attachments: Vec, +} + +impl Buffer { + #[doc(hidden)] + pub fn new(pool: vk::CommandPool, family: u32, share: SharePointer) -> Buffer { + let alloc_info = vk::CommandBufferAllocateInfo { + sType: vk::STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO, + pNext: ptr::null(), + commandPool: pool, + level: vk::COMMAND_BUFFER_LEVEL_PRIMARY, + commandBufferCount: 1, + }; + let begin_info = vk::CommandBufferBeginInfo { + sType: vk::STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO, + pNext: ptr::null(), + flags: 0, + pInheritanceInfo: ptr::null(), + }; + Buffer { + inner: { + let (dev, vk) = share.get_device(); + let mut buf = 0; + assert_eq!(vk::SUCCESS, unsafe { + vk.AllocateCommandBuffers(dev, &alloc_info, &mut buf) + }); + assert_eq!(vk::SUCCESS, unsafe { + vk.BeginCommandBuffer(buf, &begin_info) + }); + buf + }, + parent_pool: pool, + family: family, + share: share, + last_render_pass: 0, + fbo_cache: HashMap::new(), + temp_attachments: Vec::new(), + } + } +} + +impl Drop for Buffer { + fn drop(&mut self) { + let (dev, vk) = self.share.get_device(); + unsafe { + vk.FreeCommandBuffers(dev, self.parent_pool, 1, &self.inner); + } + for &fbo in self.fbo_cache.values() { + unsafe { + vk.DestroyFramebuffer(dev, fbo, ptr::null()); + } + } + } +} + +impl Buffer { + pub fn image_barrier(&mut self, image: vk::Image, aspect: vk::ImageAspectFlags, + old_layout: vk::ImageLayout, new_layout: vk::ImageLayout) { + let barrier = vk::ImageMemoryBarrier { + sType: vk::STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, + pNext: ptr::null(), + srcAccessMask: if old_layout == vk::IMAGE_LAYOUT_PREINITIALIZED || new_layout == vk::IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL { + vk::ACCESS_HOST_WRITE_BIT | vk::ACCESS_TRANSFER_WRITE_BIT + } else {0}, + dstAccessMask: match new_layout { + vk::IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL | vk::IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL => + vk::ACCESS_TRANSFER_READ_BIT | vk::ACCESS_HOST_WRITE_BIT | vk::ACCESS_TRANSFER_WRITE_BIT, + vk::IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL => vk::ACCESS_SHADER_READ_BIT, + _ => 0, + }, + oldLayout: old_layout, + newLayout: new_layout, + srcQueueFamilyIndex: self.family, + dstQueueFamilyIndex: self.family, + image: image, + subresourceRange: vk::ImageSubresourceRange { + aspectMask: aspect, + baseMipLevel: 0, + levelCount: 1, + baseArrayLayer: 0, + layerCount: 1, + }, + }; + let (_dev, vk) = self.share.get_device(); + unsafe { + vk.CmdPipelineBarrier(self.inner, + vk::PIPELINE_STAGE_TOP_OF_PIPE_BIT, vk::PIPELINE_STAGE_TOP_OF_PIPE_BIT, 0, + 0, ptr::null(), 0, ptr::null(), 1, &barrier); + } + } +} + +impl draw::CommandBuffer for Buffer { + fn reset(&mut self) { + let (_, vk) = self.share.get_device(); + assert_eq!(vk::SUCCESS, unsafe { + vk.ResetCommandBuffer(self.inner, 0) + }); + } + + fn bind_pipeline_state(&mut self, pso: native::Pipeline) { + let (_, vk) = self.share.get_device(); + self.last_render_pass = pso.render_pass; + unsafe { + vk.CmdBindPipeline(self.inner, vk::PIPELINE_BIND_POINT_GRAPHICS, pso.pipeline); + } + } + + fn bind_vertex_buffers(&mut self, _: pso::VertexBufferSet) {} + fn bind_constant_buffers(&mut self, _: &[pso::ConstantBufferParam]) {} + fn bind_global_constant(&mut self, _: shade::Location, _: shade::UniformValue) {} + fn bind_resource_views(&mut self, _: &[pso::ResourceViewParam]) {} + fn bind_unordered_views(&mut self, _: &[pso::UnorderedViewParam]) {} + fn bind_samplers(&mut self, _: &[pso::SamplerParam]) {} + + fn bind_pixel_targets(&mut self, pts: pso::PixelTargetSet) { + let (dev, vk) = self.share.get_device(); + let vp = vk::Viewport { + x: 0.0, + y: 0.0, + width: pts.size.0 as f32, + height: pts.size.1 as f32, + minDepth: 0.0, + maxDepth: 1.0, + }; + let fbo = match self.fbo_cache.entry(pts) { + Entry::Occupied(oe) => *oe.get(), + Entry::Vacant(ve) => { + let mut ats = &mut self.temp_attachments; + ats.clear(); + for color in pts.colors.iter() { + if let &Some(ref tv) = color { + ats.push(tv.view); + } + } + match (pts.depth, pts.stencil) { + (None, None) => (), + (Some(vd), Some(vs)) => { + if vd != vs { + error!("Different depth and stencil are not supported") + } + ats.push(vd.view); + }, + (Some(vd), None) => ats.push(vd.view), + (None, Some(vs)) => ats.push(vs.view), + } + let info = vk::FramebufferCreateInfo { + sType: vk::STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO, + pNext: ptr::null(), + flags: 0, + renderPass: self.last_render_pass, + attachmentCount: ats.len() as u32, + pAttachments: ats.as_ptr(), + width: pts.size.0 as u32, + height: pts.size.1 as u32, + layers: pts.size.2 as u32, + }; + let mut out = 0; + assert_eq!(vk::SUCCESS, unsafe { + vk.CreateFramebuffer(dev, &info, ptr::null(), &mut out) + }); + *ve.insert(out) + }, + }; + let rp_info = vk::RenderPassBeginInfo { + sType: vk::STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO, + pNext: ptr::null(), + renderPass: self.last_render_pass, + framebuffer: fbo, + renderArea: vk::Rect2D { + offset: vk::Offset2D { + x: 0, + y: 0, + }, + extent: vk::Extent2D { + width: pts.size.0 as u32, + height: pts.size.1 as u32, + }, + }, + clearValueCount: 0, + pClearValues: ptr::null(), + }; + unsafe { + vk.CmdSetViewport(self.inner, 0, 1, &vp); + vk.CmdBeginRenderPass(self.inner, &rp_info, vk::SUBPASS_CONTENTS_INLINE); + } + //TODO: EndRenderPass + } + + fn bind_index(&mut self, _: native::Buffer, _: IndexType) {} + fn set_scissor(&mut self, _: target::Rect) {} + fn set_ref_values(&mut self, _: RefValues) {} + fn update_buffer(&mut self, _: native::Buffer, _: &[u8], _: usize) {} + fn update_texture(&mut self, _: native::Texture, _: tex::Kind, _: Option, + _: &[u8], _: tex::RawImageInfo) {} + fn generate_mipmap(&mut self, _: native::TextureView) {} + + fn clear_color(&mut self, tv: native::TextureView, color: draw::ClearColor) { + let (_, vk) = self.share.get_device(); + let value = match color { + draw::ClearColor::Float(v) => vk::ClearColorValue::float32(v), + draw::ClearColor::Int(v) => vk::ClearColorValue::int32(v), + draw::ClearColor::Uint(v) => vk::ClearColorValue::uint32(v), + }; + unsafe { + vk.CmdClearColorImage(self.inner, tv.image, tv.layout, &value, 1, &tv.sub_range); + } + } + + fn clear_depth_stencil(&mut self, tv: native::TextureView, depth: Option, + stencil: Option) { + let (_, vk) = self.share.get_device(); + let value = vk::ClearDepthStencilValue { + depth: depth.unwrap_or(1.0), //TODO + stencil: stencil.unwrap_or(0) as u32, //TODO + }; + unsafe { + vk.CmdClearDepthStencilImage(self.inner, tv.image, tv.layout, &value, 1, &tv.sub_range); + } + } + + fn call_draw(&mut self, _: VertexCount, _: VertexCount, _: draw::InstanceOption) {} + fn call_draw_indexed(&mut self, _: VertexCount, _: VertexCount, + _: VertexCount, _: draw::InstanceOption) {} +} + + +pub struct GraphicsQueue { + share: SharePointer, + family: u32, + queue: vk::Queue, + capabilities: core::Capabilities, +} + +impl GraphicsQueue { + #[doc(hidden)] + pub fn new(share: SharePointer, q: vk::Queue, qf_id: u32) -> GraphicsQueue { + let caps = core::Capabilities { + max_vertex_count: 0, + max_index_count: 0, + max_texture_size: 0, + instance_base_supported: false, + instance_call_supported: false, + instance_rate_supported: false, + vertex_base_supported: false, + srgb_color_supported: false, + constant_buffer_supported: false, + unordered_access_view_supported: false, + separate_blending_slots_supported: false, + }; + GraphicsQueue { + share: share, + family: qf_id, + queue: q, + capabilities: caps, + } + } + #[doc(hidden)] + pub fn get_share(&self) -> &Share { + &self.share + } + #[doc(hidden)] + pub fn get_queue(&self) -> vk::Queue { + self.queue + } +} + +impl core::Device for GraphicsQueue { + type Resources = Resources; + type CommandBuffer = Buffer; + + fn get_capabilities(&self) -> &core::Capabilities { + &self.capabilities + } + + fn pin_submitted_resources(&mut self, _: &core::handle::Manager) {} + + fn submit(&mut self, com: &mut Buffer) { + assert_eq!(self.family, com.family); + let (_, vk) = self.share.get_device(); + assert_eq!(vk::SUCCESS, unsafe { + vk.EndCommandBuffer(com.inner) + }); + let submit_info = vk::SubmitInfo { + sType: vk::STRUCTURE_TYPE_SUBMIT_INFO, + commandBufferCount: 1, + pCommandBuffers: &com.inner, + .. unsafe { mem::zeroed() } + }; + assert_eq!(vk::SUCCESS, unsafe { + vk.QueueSubmit(self.queue, 1, &submit_info, 0) + }); + let begin_info = vk::CommandBufferBeginInfo { + sType: vk::STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO, + pNext: ptr::null(), + flags: 0, + pInheritanceInfo: ptr::null(), + }; + assert_eq!(vk::SUCCESS, unsafe { + vk.BeginCommandBuffer(com.inner, &begin_info) + }); + } + + //note: this should really live elsewhere (Factory?) + fn cleanup(&mut self) { + let (dev, mut functions) = self.share.get_device(); + use gfx_core::handle::Producer; + //self.frame_handles.clear(); + self.share.handles.borrow_mut().clean_with(&mut functions, + |vk, b| unsafe { //buffer + vk.DestroyBuffer(dev, b.buffer, ptr::null()); + vk.FreeMemory(dev, b.memory, ptr::null()); + }, + |vk, s| unsafe { //shader + vk.DestroyShaderModule(dev, *s, ptr::null()); + }, + |_, _p| (), //program + |vk, p| unsafe { //PSO + vk.DestroyPipeline(dev, p.pipeline, ptr::null()); + vk.DestroyPipelineLayout(dev, p.pipe_layout, ptr::null()); + vk.DestroyDescriptorSetLayout(dev, p.desc_layout, ptr::null()); + vk.DestroyDescriptorPool(dev, p.desc_pool, ptr::null()); + }, + |vk, t| if t.memory != 0 {unsafe { //texture + vk.DestroyImage(dev, t.image, ptr::null()); + vk.FreeMemory(dev, t.memory, ptr::null()); + }}, + |vk, v| unsafe { //SRV + vk.DestroyImageView(dev, v.view, ptr::null()); + }, + |_, _| (), //UAV + |vk, v| unsafe { //RTV + vk.DestroyImageView(dev, v.view, ptr::null()); + }, + |vk, v| unsafe { //DSV + vk.DestroyImageView(dev, v.view, ptr::null()); + }, + |_, _v| (), //sampler + |_, _| (), //fence + ); + } +} diff --git a/src/backend/vulkan/src/data.rs b/src/backend/vulkan/src/data.rs new file mode 100644 index 00000000000..6bf60003b48 --- /dev/null +++ b/src/backend/vulkan/src/data.rs @@ -0,0 +1,418 @@ +// Copyright 2016 The Gfx-rs Developers. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use gfx_core::factory::{Bind, MapAccess, Usage, LayerError}; +use gfx_core::format::{SurfaceType, ChannelType, Swizzle, ChannelSource}; +use gfx_core::pso::ColorInfo; +use gfx_core::tex::{FilterMethod, Kind, Layer, PackedColor, WrapMode}; +use gfx_core::{shade, state, Primitive}; +use vk; + + +pub fn map_image_type(kind: Kind) -> vk::ImageType { + match kind { + Kind::D1(..) | Kind::D1Array(..) => vk::IMAGE_TYPE_1D, + Kind::D2(..) | Kind::D2Array(..) => vk::IMAGE_TYPE_2D, + Kind::D3(..) => vk::IMAGE_TYPE_3D, + Kind::Cube(..) | Kind::CubeArray(..) => vk::IMAGE_TYPE_2D, + } +} + +pub fn map_image_view_type(kind: Kind, layer: Option) -> Result { + match (kind, layer) { + (Kind::D1(..), Some(_)) | (Kind::D2(..), Some(_)) | (Kind::D3(..), Some(_)) | + (Kind::Cube(..), Some(_)) => Err(LayerError::NotExpected(kind)), + (Kind::D1Array(_, n), Some(l)) if n<=l => Err(LayerError::OutOfBounds(l, n)), + (Kind::D2Array(_, _, n, _), Some(l)) if n<=l => Err(LayerError::OutOfBounds(l, n)), + (Kind::CubeArray(_, n), Some(l)) if n<=l => Err(LayerError::OutOfBounds(l, n)), + (Kind::D1(..), None) | (Kind::D1Array(..), Some(_)) => Ok(vk::IMAGE_VIEW_TYPE_1D), + (Kind::D1Array(..), None) => Ok(vk::IMAGE_VIEW_TYPE_1D_ARRAY), + (Kind::D2(..), None) | (Kind::D2Array(..), Some(_)) => Ok(vk::IMAGE_VIEW_TYPE_2D), + (Kind::D2Array(..), None) => Ok(vk::IMAGE_VIEW_TYPE_2D_ARRAY), + (Kind::D3(..), None) => Ok(vk::IMAGE_VIEW_TYPE_3D), + (Kind::Cube(..), None) | (Kind::CubeArray(..), Some(_)) => Ok(vk::IMAGE_VIEW_TYPE_CUBE), + (Kind::CubeArray(..), None) => Ok(vk::IMAGE_VIEW_TYPE_CUBE_ARRAY), + } +} + +pub fn map_image_aspect(surface: SurfaceType, channel: ChannelType, is_target: bool) -> vk::ImageAspectFlags { + match surface { + SurfaceType::D16 | SurfaceType::D24 | SurfaceType::D24_S8 | SurfaceType::D32 => match (is_target, channel) { + (true, _) => vk::IMAGE_ASPECT_DEPTH_BIT | vk::IMAGE_ASPECT_STENCIL_BIT, + (false, ChannelType::Float) | (false, ChannelType::Unorm) => vk::IMAGE_ASPECT_DEPTH_BIT, + (false, ChannelType::Uint) => vk::IMAGE_ASPECT_STENCIL_BIT, + _ => { + error!("Unexpected depth/stencil channel {:?}", channel); + vk::IMAGE_ASPECT_DEPTH_BIT + } + }, + _ => vk::IMAGE_ASPECT_COLOR_BIT, + } +} + +pub fn map_channel_source(source: ChannelSource) -> vk::ComponentSwizzle { + match source { + ChannelSource::Zero => vk::COMPONENT_SWIZZLE_ZERO, + ChannelSource::One => vk::COMPONENT_SWIZZLE_ONE, + ChannelSource::X => vk::COMPONENT_SWIZZLE_R, + ChannelSource::Y => vk::COMPONENT_SWIZZLE_G, + ChannelSource::Z => vk::COMPONENT_SWIZZLE_B, + ChannelSource::W => vk::COMPONENT_SWIZZLE_A, + } +} + +pub fn map_swizzle(swizzle: Swizzle) -> vk::ComponentMapping { + vk::ComponentMapping { + r: map_channel_source(swizzle.0), + g: map_channel_source(swizzle.1), + b: map_channel_source(swizzle.2), + a: map_channel_source(swizzle.3), + } +} + +pub fn map_usage_tiling(gfx_usage: Usage, bind: Bind) -> (vk::ImageUsageFlags, vk::ImageTiling) { + use gfx_core::factory as f; + let mut usage = 0; + if bind.contains(f::RENDER_TARGET) { + usage |= vk::IMAGE_USAGE_COLOR_ATTACHMENT_BIT; + } + if bind.contains(f::DEPTH_STENCIL) { + usage |= vk::IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT; + } + if bind.contains(f::SHADER_RESOURCE) { + usage |= vk::IMAGE_USAGE_SAMPLED_BIT; + } + if bind.contains(f::UNORDERED_ACCESS) { + usage |= vk::IMAGE_USAGE_STORAGE_BIT; + } + let tiling = match gfx_usage { + Usage::Const => vk::IMAGE_TILING_OPTIMAL, + Usage::GpuOnly => { + //TODO: not always needed + usage |= vk::IMAGE_USAGE_TRANSFER_SRC_BIT | vk::IMAGE_USAGE_TRANSFER_DST_BIT; + vk::IMAGE_TILING_OPTIMAL + }, + Usage::Dynamic => { + usage |= vk::IMAGE_USAGE_TRANSFER_DST_BIT; + vk::IMAGE_TILING_LINEAR + }, + Usage::CpuOnly(map) => { + usage |= match map { + MapAccess::Readable => vk::IMAGE_USAGE_TRANSFER_DST_BIT, + MapAccess::Writable => vk::IMAGE_USAGE_TRANSFER_SRC_BIT, + MapAccess::RW => vk::IMAGE_USAGE_TRANSFER_SRC_BIT | vk::IMAGE_USAGE_TRANSFER_DST_BIT, + }; + vk::IMAGE_TILING_LINEAR + }, + }; + (usage, tiling) +} + +pub fn map_image_layout(bind: Bind) -> vk::ImageLayout { + //use gfx_core::factory as f; + // can't use optimal layouts for the fact PSO descriptor doesn't know about them + match bind { + //f::RENDER_TARGET => vk::IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, + //f::DEPTH_STENCIL => vk::IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, + //f::SHADER_RESOURCE => vk::IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, + _ => vk::IMAGE_LAYOUT_GENERAL, + } +} + +pub fn map_format(surface: SurfaceType, chan: ChannelType) -> Option { + use gfx_core::format::SurfaceType::*; + use gfx_core::format::ChannelType::*; + Some(match surface { + R4_G4 => match chan { + Unorm => vk::FORMAT_R4G4_UNORM_PACK8, + _ => return None, + }, + R4_G4_B4_A4 => match chan { + Unorm => vk::FORMAT_R4G4B4A4_UNORM_PACK16, + _ => return None, + }, + R5_G5_B5_A1 => match chan { + Unorm => vk::FORMAT_R5G5B5A1_UNORM_PACK16, + _ => return None, + }, + R5_G6_B5 => match chan { + Unorm => vk::FORMAT_R5G6B5_UNORM_PACK16, + _ => return None, + }, + R8 => match chan { + Int => vk::FORMAT_R8_SINT, + Uint => vk::FORMAT_R8_UINT, + Inorm => vk::FORMAT_R8_SNORM, + Unorm => vk::FORMAT_R8_UNORM, + Srgb => vk::FORMAT_R8_SRGB, + _ => return None, + }, + R8_G8 => match chan { + Int => vk::FORMAT_R8G8_SINT, + Uint => vk::FORMAT_R8G8_UINT, + Inorm => vk::FORMAT_R8G8_SNORM, + Unorm => vk::FORMAT_R8G8_UNORM, + Srgb => vk::FORMAT_R8G8_SRGB, + _ => return None, + }, + R8_G8_B8_A8 => match chan { + Int => vk::FORMAT_R8G8B8A8_SINT, + Uint => vk::FORMAT_R8G8B8A8_UINT, + Inorm => vk::FORMAT_R8G8B8A8_SNORM, + Unorm => vk::FORMAT_R8G8B8A8_UNORM, + Srgb => vk::FORMAT_R8G8B8A8_SRGB, + _ => return None, + }, + R10_G10_B10_A2 => match chan { + Int => vk::FORMAT_A2R10G10B10_SINT_PACK32, + Uint => vk::FORMAT_A2R10G10B10_UINT_PACK32, + Inorm => vk::FORMAT_A2R10G10B10_SNORM_PACK32, + Unorm => vk::FORMAT_A2R10G10B10_UNORM_PACK32, + _ => return None, + }, + R11_G11_B10 => match chan { + Float => vk::FORMAT_B10G11R11_UFLOAT_PACK32, + _ => return None, + }, + R16 => match chan { + Int => vk::FORMAT_R16_SINT, + Uint => vk::FORMAT_R16_UINT, + Inorm => vk::FORMAT_R16_SNORM, + Unorm => vk::FORMAT_R16_UNORM, + Float => vk::FORMAT_R16_SFLOAT, + _ => return None, + }, + R16_G16 => match chan { + Int => vk::FORMAT_R16G16_SINT, + Uint => vk::FORMAT_R16G16_UINT, + Inorm => vk::FORMAT_R16G16_SNORM, + Unorm => vk::FORMAT_R16G16_UNORM, + Float => vk::FORMAT_R16G16_SFLOAT, + _ => return None, + }, + R16_G16_B16 => match chan { + Int => vk::FORMAT_R16G16B16_SINT, + Uint => vk::FORMAT_R16G16B16_UINT, + Inorm => vk::FORMAT_R16G16B16_SNORM, + Unorm => vk::FORMAT_R16G16B16_UNORM, + Float => vk::FORMAT_R16G16B16_SFLOAT, + _ => return None, + }, + R16_G16_B16_A16 => match chan { + Int => vk::FORMAT_R16G16B16A16_SINT, + Uint => vk::FORMAT_R16G16B16A16_UINT, + Inorm => vk::FORMAT_R16G16B16A16_SNORM, + Unorm => vk::FORMAT_R16G16B16A16_UNORM, + Float => vk::FORMAT_R16G16B16A16_SFLOAT, + _ => return None, + }, + R32 => match chan { + Int => vk::FORMAT_R32_SINT, + Uint => vk::FORMAT_R32_UINT, + Float => vk::FORMAT_R32_SFLOAT, + _ => return None, + }, + R32_G32 => match chan { + Int => vk::FORMAT_R32G32_SINT, + Uint => vk::FORMAT_R32G32_UINT, + Float => vk::FORMAT_R32G32_SFLOAT, + _ => return None, + }, + R32_G32_B32 => match chan { + Int => vk::FORMAT_R32G32B32_SINT, + Uint => vk::FORMAT_R32G32B32_UINT, + Float => vk::FORMAT_R32G32B32_SFLOAT, + _ => return None, + }, + R32_G32_B32_A32 => match chan { + Int => vk::FORMAT_R32G32B32A32_SINT, + Uint => vk::FORMAT_R32G32B32A32_UINT, + Float => vk::FORMAT_R32G32B32A32_SFLOAT, + _ => return None, + }, + D16 => match chan { + Unorm => vk::FORMAT_D16_UNORM, + _ => return None, + }, + D24 => match chan { + Unorm => vk::FORMAT_X8_D24_UNORM_PACK32, + _ => return None, + }, + D24_S8 => match chan { + Unorm => vk::FORMAT_D24_UNORM_S8_UINT, + _ => return None, + }, + D32 => match chan { + Float => vk::FORMAT_D32_SFLOAT, + _ => return None, + }, + }) +} + +pub fn map_filter(filter: FilterMethod) -> (vk::Filter, vk::Filter, vk::SamplerMipmapMode, f32) { + match filter { + FilterMethod::Scale => (vk::FILTER_NEAREST, vk::FILTER_NEAREST, vk::SAMPLER_MIPMAP_MODE_NEAREST, 0.0), + FilterMethod::Mipmap => (vk::FILTER_NEAREST, vk::FILTER_NEAREST, vk::SAMPLER_MIPMAP_MODE_LINEAR, 0.0), + FilterMethod::Bilinear => (vk::FILTER_LINEAR, vk::FILTER_LINEAR, vk::SAMPLER_MIPMAP_MODE_NEAREST, 0.0), + FilterMethod::Trilinear => (vk::FILTER_LINEAR, vk::FILTER_LINEAR, vk::SAMPLER_MIPMAP_MODE_LINEAR, 0.0), + FilterMethod::Anisotropic(a) => (vk::FILTER_LINEAR, vk::FILTER_LINEAR, vk::SAMPLER_MIPMAP_MODE_LINEAR, a as f32), + } +} + +pub fn map_wrap(wrap: WrapMode) -> vk::SamplerAddressMode { + match wrap { + WrapMode::Tile => vk::SAMPLER_ADDRESS_MODE_REPEAT, + WrapMode::Mirror => vk::SAMPLER_ADDRESS_MODE_MIRRORED_REPEAT, + WrapMode::Clamp => vk::SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE, + WrapMode::Border => vk::SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER, + } +} + +pub fn map_border_color(col: PackedColor) -> Option { + match col.0 { + 0x00000000 => Some(vk::BORDER_COLOR_FLOAT_TRANSPARENT_BLACK), + 0xFF000000 => Some(vk::BORDER_COLOR_FLOAT_OPAQUE_BLACK), + 0xFFFFFFFF => Some(vk::BORDER_COLOR_FLOAT_OPAQUE_WHITE), + _ => None + } +} + +pub fn map_comparison(fun: state::Comparison) -> vk::CompareOp { + use gfx_core::state::Comparison::*; + match fun { + Never => vk::COMPARE_OP_NEVER, + Less => vk::COMPARE_OP_LESS, + LessEqual => vk::COMPARE_OP_LESS_OR_EQUAL, + Equal => vk::COMPARE_OP_EQUAL, + GreaterEqual => vk::COMPARE_OP_GREATER_OR_EQUAL, + Greater => vk::COMPARE_OP_GREATER, + NotEqual => vk::COMPARE_OP_NOT_EQUAL, + Always => vk::COMPARE_OP_ALWAYS, + } +} + +pub fn map_topology(prim: Primitive) -> vk::PrimitiveTopology { + match prim { + Primitive::PointList => vk::PRIMITIVE_TOPOLOGY_POINT_LIST, + Primitive::LineList => vk::PRIMITIVE_TOPOLOGY_LINE_LIST, + Primitive::LineStrip => vk::PRIMITIVE_TOPOLOGY_LINE_STRIP, + Primitive::TriangleList => vk::PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, + Primitive::TriangleStrip => vk::PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP, + } +} + +pub fn map_polygon_mode(rm: state::RasterMethod) -> (vk::PolygonMode, f32) { + match rm { + state::RasterMethod::Point => (vk::POLYGON_MODE_POINT, 1.0), + state::RasterMethod::Line(w) => (vk::POLYGON_MODE_LINE, w as f32), + state::RasterMethod::Fill => (vk::POLYGON_MODE_FILL, 1.0), + } +} + +pub fn map_cull_face(cf: state::CullFace) -> vk::CullModeFlagBits { + match cf { + state::CullFace::Nothing => vk::CULL_MODE_NONE, + state::CullFace::Front => vk::CULL_MODE_FRONT_BIT, + state::CullFace::Back => vk::CULL_MODE_BACK_BIT, + } +} + +pub fn map_front_face(ff: state::FrontFace) -> vk::FrontFace { + match ff { + state::FrontFace::Clockwise => vk::FRONT_FACE_CLOCKWISE, + state::FrontFace::CounterClockwise => vk::FRONT_FACE_COUNTER_CLOCKWISE, + } +} + +pub fn map_stencil_op(op: state::StencilOp) -> vk::StencilOp { + use gfx_core::state::StencilOp::*; + match op { + Keep => vk::STENCIL_OP_KEEP, + Zero => vk::STENCIL_OP_ZERO, + Replace => vk::STENCIL_OP_REPLACE, + IncrementClamp => vk::STENCIL_OP_INCREMENT_AND_CLAMP, + IncrementWrap => vk::STENCIL_OP_INCREMENT_AND_WRAP, + DecrementClamp => vk::STENCIL_OP_DECREMENT_AND_CLAMP, + DecrementWrap => vk::STENCIL_OP_DECREMENT_AND_WRAP, + Invert => vk::STENCIL_OP_INVERT, + } +} + +pub fn map_stencil_side(side: &state::StencilSide) -> vk::StencilOpState { + vk::StencilOpState { + failOp: map_stencil_op(side.op_fail), + passOp: map_stencil_op(side.op_pass), + depthFailOp: map_stencil_op(side.op_depth_fail), + compareOp: map_comparison(side.fun), + compareMask: side.mask_read as u32, + writeMask: side.mask_write as u32, + reference: 0, + } +} + +pub fn map_blend_factor(factor: state::Factor) -> vk::BlendFactor { + use gfx_core::state::Factor::*; + use gfx_core::state::BlendValue::*; + match factor { + Zero => vk::BLEND_FACTOR_ZERO, + One => vk::BLEND_FACTOR_ONE, + SourceAlphaSaturated => vk::BLEND_FACTOR_SRC_ALPHA_SATURATE, + ZeroPlus(SourceColor) => vk::BLEND_FACTOR_SRC_COLOR, + ZeroPlus(SourceAlpha) => vk::BLEND_FACTOR_SRC_ALPHA, + ZeroPlus(DestColor) => vk::BLEND_FACTOR_DST_COLOR, + ZeroPlus(DestAlpha) => vk::BLEND_FACTOR_DST_ALPHA, + ZeroPlus(ConstColor) => vk::BLEND_FACTOR_CONSTANT_COLOR, + ZeroPlus(ConstAlpha) => vk::BLEND_FACTOR_CONSTANT_ALPHA, + OneMinus(SourceColor) => vk::BLEND_FACTOR_ONE_MINUS_SRC_COLOR, + OneMinus(SourceAlpha) => vk::BLEND_FACTOR_ONE_MINUS_SRC_ALPHA, + OneMinus(DestColor) => vk::BLEND_FACTOR_ONE_MINUS_DST_COLOR, + OneMinus(DestAlpha) => vk::BLEND_FACTOR_ONE_MINUS_DST_ALPHA, + OneMinus(ConstColor) => vk::BLEND_FACTOR_ONE_MINUS_CONSTANT_COLOR, + OneMinus(ConstAlpha) => vk::BLEND_FACTOR_ONE_MINUS_CONSTANT_ALPHA, + } +} + +pub fn map_blend_op(op: state::Equation) -> vk::BlendOp { + use gfx_core::state::Equation::*; + match op { + Add => vk::BLEND_OP_ADD, + Sub => vk::BLEND_OP_SUBTRACT, + RevSub => vk::BLEND_OP_REVERSE_SUBTRACT, + Min => vk::BLEND_OP_MIN, + Max => vk::BLEND_OP_MAX, + } +} + +pub fn map_blend(ci: &ColorInfo) -> vk::PipelineColorBlendAttachmentState { + vk::PipelineColorBlendAttachmentState { + blendEnable: if ci.color.is_some() || ci.alpha.is_some() { vk::TRUE } else { vk::FALSE }, + srcColorBlendFactor: ci.color.map_or(0, |c| map_blend_factor(c.source)), + dstColorBlendFactor: ci.color.map_or(0, |c| map_blend_factor(c.destination)), + colorBlendOp: ci.color.map_or(0, |c| map_blend_op(c.equation)), + srcAlphaBlendFactor: ci.alpha.map_or(0, |a| map_blend_factor(a.source)), + dstAlphaBlendFactor: ci.alpha.map_or(0, |a| map_blend_factor(a.destination)), + alphaBlendOp: ci.alpha.map_or(0, |a| map_blend_op(a.equation)), + colorWriteMask: + if ci.mask.contains(state::RED) {vk::COLOR_COMPONENT_R_BIT} else {0} | + if ci.mask.contains(state::GREEN) {vk::COLOR_COMPONENT_G_BIT} else {0} | + if ci.mask.contains(state::BLUE) {vk::COLOR_COMPONENT_B_BIT} else {0} | + if ci.mask.contains(state::ALPHA) {vk::COLOR_COMPONENT_A_BIT} else {0}, + } +} + +pub fn map_stage(usage: shade::Usage) -> vk::ShaderStageFlags { + (if usage.contains(shade::VERTEX) { vk::SHADER_STAGE_VERTEX_BIT } else { 0 }) | + (if usage.contains(shade::GEOMETRY) { vk::SHADER_STAGE_GEOMETRY_BIT } else { 0 }) | + (if usage.contains(shade::PIXEL) { vk::SHADER_STAGE_FRAGMENT_BIT } else { 0 }) +} diff --git a/src/backend/vulkan/src/factory.rs b/src/backend/vulkan/src/factory.rs new file mode 100644 index 00000000000..9fee2759916 --- /dev/null +++ b/src/backend/vulkan/src/factory.rs @@ -0,0 +1,881 @@ +// Copyright 2016 The Gfx-rs Developers. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use std::{cell, mem, ptr, slice}; +use std::os::raw::c_void; +use gfx_core::{self as core, handle as h, factory as f, pso, state}; +use gfx_core::format::ChannelType; +use gfx_core::target::Layer; +use vk; +use {command, data, native}; +use {Resources as R, SharePointer}; + + +#[derive(Copy, Clone)] +pub struct RawMapping { + pointer: *mut c_void, +} + +impl core::mapping::Raw for RawMapping { + unsafe fn set(&self, index: usize, val: T) { + *(self.pointer as *mut T).offset(index as isize) = val; + } + + unsafe fn to_slice(&self, len: usize) -> &[T] { + slice::from_raw_parts(self.pointer as *const T, len) + } + + unsafe fn to_mut_slice(&self, len: usize) -> &mut [T] { + slice::from_raw_parts_mut(self.pointer as *mut T, len) + } +} + +pub struct Factory { + share: SharePointer, + queue_family_index: u32, + mem_video_id: u32, + mem_system_id: u32, + command_pool: vk::CommandPool, + frame_handles: h::Manager, +} + +impl Factory { + pub fn new(share: SharePointer, qf_index: u32, mvid: u32, msys: u32) -> Factory { + let com_info = vk::CommandPoolCreateInfo { + sType: vk::STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO, + pNext: ptr::null(), + flags: vk::COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, + queueFamilyIndex: qf_index, + }; + let mut com_pool = 0; + assert_eq!(vk::SUCCESS, unsafe { + let (dev, vk) = share.get_device(); + vk.CreateCommandPool(dev, &com_info, ptr::null(), &mut com_pool) + }); + Factory { + share: share, + queue_family_index: qf_index, + mem_video_id: mvid, + mem_system_id: msys, + command_pool: com_pool, + frame_handles: h::Manager::new(), + } + } + + pub fn create_command_buffer(&mut self) -> command::Buffer { + command::Buffer::new(self.command_pool, self.queue_family_index, self.share.clone()) + } + + fn view_texture(&mut self, htex: &h::RawTexture, desc: core::tex::ResourceDesc, is_target: bool) + -> Result { + let raw_tex = self.frame_handles.ref_texture(htex); + let td = htex.get_info(); + let info = vk::ImageViewCreateInfo { + sType: vk::STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, + pNext: ptr::null(), + flags: 0, + image: raw_tex.image, + viewType: match data::map_image_view_type(td.kind, desc.layer) { + Ok(vt) => vt, + Err(e) => return Err(f::ResourceViewError::Layer(e)), + }, + format: match data::map_format(td.format, desc.channel) { + Some(f) => f, + None => return Err(f::ResourceViewError::Channel(desc.channel)), + }, + components: data::map_swizzle(desc.swizzle), + subresourceRange: vk::ImageSubresourceRange { + aspectMask: data::map_image_aspect(td.format, desc.channel, is_target), + baseMipLevel: desc.min as u32, + levelCount: (desc.max + 1 - desc.min) as u32, + baseArrayLayer: desc.layer.unwrap_or(0) as u32, + layerCount: match desc.layer { + Some(_) => 1, + None => td.kind.get_num_slices().unwrap_or(1) as u32, + }, + }, + }; + + let (dev, vk) = self.share.get_device(); + let mut view = 0; + assert_eq!(vk::SUCCESS, unsafe { + vk.CreateImageView(dev, &info, ptr::null(), &mut view) + }); + Ok(native::TextureView { + image: raw_tex.image, + view: view, + layout: raw_tex.layout.get(), //care! + sub_range: info.subresourceRange, + }) + } + + fn view_target(&mut self, htex: &h::RawTexture, channel: ChannelType, layer: Option) + -> Result + { + let rdesc = core::tex::ResourceDesc { + channel: channel, + layer: layer, + min: 0, + max: 0, + swizzle: core::format::Swizzle::new(), + }; + self.view_texture(htex, rdesc, true).map_err(|err| match err { + f::ResourceViewError::NoBindFlag => f::TargetViewError::NoBindFlag, + f::ResourceViewError::Channel(ct) => f::TargetViewError::Channel(ct), + f::ResourceViewError::Layer(le) => f::TargetViewError::Layer(le), + f::ResourceViewError::Unsupported => f::TargetViewError::Unsupported, + }) + } + + + #[doc(hidden)] + pub fn view_swapchain_image(&mut self, image: vk::Image, format: core::format::Format, size: (u32, u32)) + -> Result, f::TargetViewError> { + use gfx_core::Factory; + use gfx_core::handle::Producer; + use gfx_core::tex as t; + + let raw_tex = native::Texture { + image: image, + layout: cell::Cell::new(vk::IMAGE_LAYOUT_GENERAL), + memory: 0, + }; + let tex_desc = t::Descriptor { + kind: t::Kind::D2(size.0 as t::Size, size.1 as t::Size, t::AaMode::Single), + levels: 1, + format: format.0, + bind: f::RENDER_TARGET, + usage: f::Usage::GpuOnly, + }; + let tex = self.frame_handles.make_texture(raw_tex, tex_desc); + let view_desc = t::RenderDesc { + channel: format.1, + level: 0, + layer: None, + }; + + self.view_texture_as_render_target_raw(&tex, view_desc) + } + + pub fn create_fence(&mut self, signalled: bool) -> vk::Fence { + let info = vk::FenceCreateInfo { + sType: vk::STRUCTURE_TYPE_FENCE_CREATE_INFO, + pNext: ptr::null(), + flags: if signalled { vk::FENCE_CREATE_SIGNALED_BIT } else { 0 }, + }; + let (dev, vk) = self.share.get_device(); + let mut fence = 0; + assert_eq!(vk::SUCCESS, unsafe { + vk.CreateFence(dev, &info, ptr::null(), &mut fence) + }); + fence + } + + fn create_buffer_impl(&mut self, info: &f::BufferInfo) -> native::Buffer { + let (usage, _) = data::map_usage_tiling(info.usage, info.bind); + let native_info = vk::BufferCreateInfo { + sType: vk::STRUCTURE_TYPE_BUFFER_CREATE_INFO, + pNext: ptr::null(), + flags: 0, + size: info.size as vk::DeviceSize, + usage: usage, + sharingMode: vk::SHARING_MODE_EXCLUSIVE, + queueFamilyIndexCount: 1, + pQueueFamilyIndices: &self.queue_family_index, + }; + let (dev, vk) = self.share.get_device(); + let mut buf = 0; + assert_eq!(vk::SUCCESS, unsafe { + vk.CreateBuffer(dev, &native_info, ptr::null(), &mut buf) + }); + let reqs = unsafe { + let mut out = mem::zeroed(); + vk.GetBufferMemoryRequirements(dev, buf, &mut out); + out + }; + let mem = self.alloc(info.usage, reqs); + assert_eq!(vk::SUCCESS, unsafe { + vk.BindBufferMemory(dev, buf, mem, 0) + }); + native::Buffer { + buffer: buf, + memory: mem, + } + } + + fn alloc(&self, usage: f::Usage, reqs: vk::MemoryRequirements) -> vk::DeviceMemory { + let info = vk::MemoryAllocateInfo { + sType: vk::STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO, + pNext: ptr::null(), + allocationSize: reqs.size, + memoryTypeIndex: if let f::Usage::CpuOnly(_) = usage { + self.mem_system_id + }else { + self.mem_video_id + }, + }; + let (dev, vk) = self.share.get_device(); + let mut mem = 0; + assert_eq!(vk::SUCCESS, unsafe { + vk.AllocateMemory(dev, &info, ptr::null(), &mut mem) + }); + mem + } + + fn get_shader_stages(&mut self, program: &h::Program) -> Vec { + let prog = self.frame_handles.ref_program(program); + let entry_name = b"main\0"; //TODO + let mut stages = Vec::new(); + if true { + stages.push(vk::PipelineShaderStageCreateInfo { + sType: vk::STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, + pNext: ptr::null(), + flags: 0, + stage: vk::SHADER_STAGE_VERTEX_BIT, + module: *prog.vertex.reference(&mut self.frame_handles), + pName: entry_name.as_ptr() as *const i8, + pSpecializationInfo: ptr::null(), + }); + } + if let Some(ref geom) = prog.geometry { + stages.push(vk::PipelineShaderStageCreateInfo { + sType: vk::STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, + pNext: ptr::null(), + flags: 0, + stage: vk::SHADER_STAGE_GEOMETRY_BIT, + module: *geom.reference(&mut self.frame_handles), + pName: entry_name.as_ptr() as *const i8, + pSpecializationInfo: ptr::null(), + }); + } + if true { + stages.push(vk::PipelineShaderStageCreateInfo { + sType: vk::STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, + pNext: ptr::null(), + flags: 0, + stage: vk::SHADER_STAGE_FRAGMENT_BIT, + module: *prog.pixel.reference(&mut self.frame_handles), + pName: entry_name.as_ptr() as *const i8, + pSpecializationInfo: ptr::null(), + }); + } + stages + } +} + +impl Drop for Factory { + fn drop(&mut self) { + let (dev, vk) = self.share.get_device(); + unsafe { + vk.DestroyCommandPool(dev, self.command_pool, ptr::null()) + }; + } +} + +impl core::Factory for Factory { + type Mapper = RawMapping; + + fn get_capabilities(&self) -> &core::Capabilities { + unimplemented!() + } + + fn create_buffer_raw(&mut self, info: f::BufferInfo) -> Result, f::BufferError> { + use gfx_core::handle::Producer; + let buffer = self.create_buffer_impl(&info); + Ok(self.share.handles.borrow_mut().make_buffer(buffer, info)) + } + + fn create_buffer_const_raw(&mut self, data: &[u8], stride: usize, role: f::BufferRole, bind: f::Bind) + -> Result, f::BufferError> { + use gfx_core::handle::Producer; + let info = f::BufferInfo { + role: role, + usage: f::Usage::Const, + bind: bind, + size: data.len(), + stride: stride, + }; + let buffer = self.create_buffer_impl(&info); + let (dev, vk) = self.share.get_device(); + unsafe { + let mut ptr = ptr::null_mut(); + assert_eq!(vk::SUCCESS, vk.MapMemory(dev, buffer.memory, 0, data.len() as u64, 0, &mut ptr)); + ptr::copy_nonoverlapping(data.as_ptr(), ptr as *mut u8, data.len()); + vk.UnmapMemory(dev, buffer.memory); + } + Ok(self.share.handles.borrow_mut().make_buffer(buffer, info)) + } + + fn create_shader(&mut self, _stage: core::shade::Stage, code: &[u8]) + -> Result, core::shade::CreateShaderError> { + use gfx_core::handle::Producer; + let info = vk::ShaderModuleCreateInfo { + sType: vk::STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO, + pNext: ptr::null(), + flags: 0, + codeSize: code.len(), + pCode: code.as_ptr() as *const _, + }; + let (dev, vk) = self.share.get_device(); + let mut shader = 0; + assert_eq!(vk::SUCCESS, unsafe { + vk.CreateShaderModule(dev, &info, ptr::null(), &mut shader) + }); + Ok(self.share.handles.borrow_mut().make_shader(shader)) + } + + fn create_program(&mut self, shader_set: &core::ShaderSet) + -> Result, core::shade::CreateProgramError> { + use gfx_core::handle::Producer; + use gfx_core::shade as s; + + let prog = match shader_set.clone() { + core::ShaderSet::Simple(vs, ps) => native::Program { + vertex: vs, + geometry: None, + pixel: ps, + }, + core::ShaderSet::Geometry(vs, gs, ps) => native::Program { + vertex: vs, + geometry: Some(gs), + pixel: ps, + }, + }; + let info = s::ProgramInfo { + vertex_attributes: Vec::new(), + globals: Vec::new(), + constant_buffers: Vec::new(), + textures: Vec::new(), + unordereds: Vec::new(), + samplers: Vec::new(), + outputs: Vec::new(), + output_depth: false, + knows_outputs: false, + }; + Ok(self.share.handles.borrow_mut().make_program(prog, info)) + } + + fn create_pipeline_state_raw(&mut self, program: &h::Program, desc: &pso::Descriptor) + -> Result, pso::CreationError> { + use gfx_core::handle::Producer; + let stages = self.get_shader_stages(program); + let (dev, vk) = self.share.get_device(); + + let set_layout = { + let mut bindings = Vec::new(); + for (i, cb) in desc.constant_buffers.iter().enumerate() { + if let &Some(usage) = cb { + bindings.push(vk::DescriptorSetLayoutBinding { + binding: i as u32, + descriptorType: vk::DESCRIPTOR_TYPE_UNIFORM_BUFFER, + descriptorCount: 1, + stageFlags: data::map_stage(usage), + pImmutableSamplers: ptr::null(), + }); + } + } + for (i, srv) in desc.resource_views.iter().enumerate() { + if let &Some(usage) = srv { + bindings.push(vk::DescriptorSetLayoutBinding { + binding: i as u32, + descriptorType: vk::DESCRIPTOR_TYPE_SAMPLED_IMAGE, + descriptorCount: 1, + stageFlags: data::map_stage(usage), + pImmutableSamplers: ptr::null(), + }); + } + } + for (i, uav) in desc.unordered_views.iter().enumerate() { + if let &Some(usage) = uav { + bindings.push(vk::DescriptorSetLayoutBinding { + binding: i as u32, + descriptorType: vk::DESCRIPTOR_TYPE_STORAGE_IMAGE, //TODO: buffer views + descriptorCount: 1, + stageFlags: data::map_stage(usage), + pImmutableSamplers: ptr::null(), + }); + } + } + for (i, sam) in desc.samplers.iter().enumerate() { + if let &Some(usage) = sam { + bindings.push(vk::DescriptorSetLayoutBinding { + binding: i as u32, + descriptorType: vk::DESCRIPTOR_TYPE_SAMPLER, + descriptorCount: 1, + stageFlags: data::map_stage(usage), + pImmutableSamplers: ptr::null(), + }); + } + } + let info = vk::DescriptorSetLayoutCreateInfo { + sType: vk::STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO, + pNext: ptr::null(), + flags: 0, + bindingCount: bindings.len() as u32, + pBindings: bindings.as_ptr(), + }; + let mut out = 0; + assert_eq!(vk::SUCCESS, unsafe { + vk.CreateDescriptorSetLayout(dev, &info, ptr::null(), &mut out) + }); + out + }; + let pipe_layout = { + let info = vk::PipelineLayoutCreateInfo { + sType: vk::STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO, + pNext: ptr::null(), + flags: 0, + setLayoutCount: 1, + pSetLayouts: &set_layout, + pushConstantRangeCount: 0, + pPushConstantRanges: ptr::null(), + }; + let mut out = 0; + assert_eq!(vk::SUCCESS, unsafe { + vk.CreatePipelineLayout(dev, &info, ptr::null(), &mut out) + }); + out + }; + let pool = { + let info = vk::DescriptorPoolCreateInfo { + sType: vk::STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO, + pNext: ptr::null(), + flags: 0, + maxSets: 100, //TODO + poolSizeCount: 0, + pPoolSizes: ptr::null(), + }; + let mut out = 0; + assert_eq!(vk::SUCCESS, unsafe { + vk.CreateDescriptorPool(dev, &info, ptr::null(), &mut out) + }); + out + }; + let render_pass = { + let mut attachments = Vec::new(); + let mut color_refs = Vec::new(); + for col in desc.color_targets.iter().filter_map(|c| c.as_ref()) { + let layout = vk::IMAGE_LAYOUT_GENERAL; //TODO + color_refs.push(vk::AttachmentReference { + attachment: attachments.len() as u32, + layout: layout, + }); + attachments.push(vk::AttachmentDescription { + flags: 0, + format: match data::map_format((col.0).0, (col.0).1) { + Some(fm) => fm, + None => return Err(pso::CreationError), + }, + samples: vk::SAMPLE_COUNT_1_BIT, //TODO + loadOp: vk::ATTACHMENT_LOAD_OP_LOAD, + storeOp: vk::ATTACHMENT_STORE_OP_STORE, + stencilLoadOp: vk::ATTACHMENT_LOAD_OP_DONT_CARE, + stencilStoreOp: vk::ATTACHMENT_STORE_OP_DONT_CARE, + initialLayout: layout, + finalLayout: layout, + }); + } + let ds_ref = vk::AttachmentReference { + attachment: attachments.len() as u32, + layout: vk::IMAGE_LAYOUT_GENERAL, //TODO + }; + if let Some(ds) = desc.depth_stencil { + attachments.push(vk::AttachmentDescription { + flags: 0, + format: match data::map_format((ds.0).0, (ds.0).1) { + Some(fm) => fm, + None => return Err(pso::CreationError), + }, + samples: vk::SAMPLE_COUNT_1_BIT, //TODO + loadOp: vk::ATTACHMENT_LOAD_OP_LOAD, + storeOp: vk::ATTACHMENT_STORE_OP_STORE, + stencilLoadOp: vk::ATTACHMENT_LOAD_OP_LOAD, + stencilStoreOp: vk::ATTACHMENT_STORE_OP_STORE, + initialLayout: vk::IMAGE_LAYOUT_GENERAL, //TODO + finalLayout: vk::IMAGE_LAYOUT_GENERAL, + }); + } + let info = vk::RenderPassCreateInfo { + sType: vk::STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO, + pNext: ptr::null(), + flags: 0, + attachmentCount: attachments.len() as u32, + pAttachments: attachments.as_ptr(), + subpassCount: 1, + pSubpasses: &vk::SubpassDescription { + flags: 0, + pipelineBindPoint: vk::PIPELINE_BIND_POINT_GRAPHICS, + inputAttachmentCount: 0, + pInputAttachments: ptr::null(), + colorAttachmentCount: color_refs.len() as u32, + pColorAttachments: color_refs.as_ptr(), + pResolveAttachments: ptr::null(), + pDepthStencilAttachment: if desc.depth_stencil.is_some() {&ds_ref} else {ptr::null()}, + preserveAttachmentCount: 0, + pPreserveAttachments: ptr::null(), + }, + dependencyCount: 0, + pDependencies: ptr::null(), + }; + let mut out = 0; + assert_eq!(vk::SUCCESS, unsafe { + vk.CreateRenderPass(dev, &info, ptr::null(), &mut out) + }); + out + }; + let pipeline = { + let mut vertex_bindings = Vec::new(); + for (i, vbuf) in desc.vertex_buffers.iter().enumerate() { + if let &Some(v) = vbuf { + vertex_bindings.push(vk::VertexInputBindingDescription { + binding: i as u32, + stride: v.stride as u32, + inputRate: v.rate as vk::VertexInputRate, + }); + } + } + let mut vertex_attributes = Vec::new(); + for (i, attr) in desc.attributes.iter().enumerate() { + if let &Some(a) = attr { + vertex_attributes.push(vk::VertexInputAttributeDescription { + location: i as u32, + binding: a.0 as u32, + format: match data::map_format(a.1.format.0, a.1.format.1) { + Some(fm) => fm, + None => return Err(pso::CreationError), + }, + offset: a.1.offset as u32, + }); + } + } + let mut attachments = Vec::new(); + for ocd in desc.color_targets.iter() { + if let &Some(ref cd) = ocd { + attachments.push(data::map_blend(&cd.1)); + } + } + let (polygon, line_width) = data::map_polygon_mode(desc.rasterizer.method); + let info = vk::GraphicsPipelineCreateInfo { + sType: vk::STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO, + pNext: ptr::null(), + flags: 0, + stageCount: stages.len() as u32, + pStages: stages.as_ptr(), + pVertexInputState: &vk::PipelineVertexInputStateCreateInfo { + sType: vk::STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO, + pNext: ptr::null(), + flags: 0, + vertexBindingDescriptionCount: vertex_bindings.len() as u32, + pVertexBindingDescriptions: vertex_bindings.as_ptr(), + vertexAttributeDescriptionCount: vertex_attributes.len() as u32, + pVertexAttributeDescriptions: vertex_attributes.as_ptr(), + }, + pInputAssemblyState: &vk::PipelineInputAssemblyStateCreateInfo { + sType: vk::STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO, + pNext: ptr::null(), + flags: 0, + topology: data::map_topology(desc.primitive), + primitiveRestartEnable: vk::FALSE, + }, + pTessellationState: ptr::null(), + pViewportState: &vk::PipelineViewportStateCreateInfo { + sType: vk::STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO, + pNext: ptr::null(), + flags: 0, + viewportCount: 1, + pViewports: &vk::Viewport { + x: 0.0, + y: 0.0, + width: 1.0, + height: 1.0, + minDepth: 0.0, + maxDepth: 1.0, + }, + scissorCount: 1, + pScissors: &vk::Rect2D { + offset: vk::Offset2D { + x: 0, y: 0, + }, + extent: vk::Extent2D { + width: 1, height: 1, + }, + }, + }, + pRasterizationState: &vk::PipelineRasterizationStateCreateInfo { + sType: vk::STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO, + pNext: ptr::null(), + flags: 0, + depthClampEnable: vk::TRUE, + rasterizerDiscardEnable: vk::FALSE, + polygonMode: polygon, + cullMode: data::map_cull_face(desc.rasterizer.cull_face), + frontFace: data::map_front_face(desc.rasterizer.front_face), + depthBiasEnable: if desc.rasterizer.offset.is_some() { vk::TRUE } else { vk::FALSE }, + depthBiasConstantFactor: desc.rasterizer.offset.map_or(0.0, |off| off.1 as f32), + depthBiasClamp: 1.0, + depthBiasSlopeFactor: desc.rasterizer.offset.map_or(0.0, |off| off.0 as f32), + lineWidth: line_width, + }, + pMultisampleState: &vk::PipelineMultisampleStateCreateInfo { + sType: vk::STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO, + pNext: ptr::null(), + flags: 0, + rasterizationSamples: vk::SAMPLE_COUNT_1_BIT, //TODO + sampleShadingEnable: vk::FALSE, + minSampleShading: 0.0, + pSampleMask: ptr::null(), + alphaToCoverageEnable: vk::FALSE, + alphaToOneEnable: vk::FALSE, + }, + pDepthStencilState: &vk::PipelineDepthStencilStateCreateInfo { + sType: vk::STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO, + pNext: ptr::null(), + flags: 0, + depthTestEnable: match desc.depth_stencil { + Some((_, pso::DepthStencilInfo { depth: Some(_), ..} )) => vk::TRUE, + _ => vk::FALSE, + }, + depthWriteEnable: match desc.depth_stencil { + Some((_, pso::DepthStencilInfo { depth: Some(state::Depth { write: true, ..}), ..} )) => vk::TRUE, + _ => vk::FALSE, + }, + depthCompareOp: match desc.depth_stencil { + Some((_, pso::DepthStencilInfo { depth: Some(state::Depth { fun, ..}), ..} )) => data::map_comparison(fun), + _ => vk::COMPARE_OP_NEVER, + }, + depthBoundsTestEnable: vk::FALSE, + stencilTestEnable: match desc.depth_stencil { + Some((_, pso::DepthStencilInfo { front: Some(_), ..} )) => vk::TRUE, + Some((_, pso::DepthStencilInfo { back: Some(_), ..} )) => vk::TRUE, + _ => vk::FALSE, + }, + front: match desc.depth_stencil { + Some((_, pso::DepthStencilInfo { front: Some(ref s), ..} )) => data::map_stencil_side(s), + _ => unsafe { mem::zeroed() }, + }, + back: match desc.depth_stencil { + Some((_, pso::DepthStencilInfo { back: Some(ref s), ..} )) => data::map_stencil_side(s), + _ => unsafe { mem::zeroed() }, + }, + minDepthBounds: 0.0, + maxDepthBounds: 1.0, + }, + pColorBlendState: &vk::PipelineColorBlendStateCreateInfo { + sType: vk::STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO, + pNext: ptr::null(), + flags: 0, + logicOpEnable: vk::FALSE, + logicOp: vk::LOGIC_OP_CLEAR, + attachmentCount: attachments.len() as u32, + pAttachments: attachments.as_ptr(), + blendConstants: [0.0; 4], + }, + pDynamicState: &vk::PipelineDynamicStateCreateInfo { + sType: vk::STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO, + pNext: ptr::null(), + flags: 0, + dynamicStateCount: 1, + pDynamicStates: [ + vk::DYNAMIC_STATE_VIEWPORT, + vk::DYNAMIC_STATE_SCISSOR, + vk::DYNAMIC_STATE_BLEND_CONSTANTS, + vk::DYNAMIC_STATE_STENCIL_REFERENCE, + ].as_ptr(), + }, + layout: pipe_layout, + renderPass: render_pass, + subpass: 0, + basePipelineHandle: 0, + basePipelineIndex: 0, + }; + let mut out = 0; + assert_eq!(vk::SUCCESS, unsafe { + vk.CreateGraphicsPipelines(dev, 0, 1, &info, ptr::null(), &mut out) + }); + out + }; + let pso = native::Pipeline { + pipeline: pipeline, + pipe_layout: pipe_layout, + desc_layout: set_layout, + desc_pool: pool, + render_pass: render_pass, + program: program.clone(), + }; + Ok(self.share.handles.borrow_mut().make_pso(pso, program)) + } + + fn create_texture_raw(&mut self, desc: core::tex::Descriptor, hint: Option, + _data_opt: Option<&[&[u8]]>) -> Result, core::tex::Error> { + use gfx_core::handle::Producer; + + let (w, h, d, aa) = desc.kind.get_dimensions(); + let slices = desc.kind.get_num_slices(); + let (usage, tiling) = data::map_usage_tiling(desc.usage, desc.bind); + let chan_type = hint.unwrap_or(core::format::ChannelType::Uint); + let info = vk::ImageCreateInfo { + sType: vk::STRUCTURE_TYPE_IMAGE_CREATE_INFO, + pNext: ptr::null(), + flags: vk::IMAGE_CREATE_MUTABLE_FORMAT_BIT | + (if desc.kind.is_cube() {vk::IMAGE_CREATE_CUBE_COMPATIBLE_BIT} else {0}), + imageType: data::map_image_type(desc.kind), + format: match data::map_format(desc.format, chan_type) { + Some(f) => f, + None => return Err(core::tex::Error::Format(desc.format, hint)), + }, + extent: vk::Extent3D { + width: w as u32, + height: h as u32, + depth: if slices.is_none() {d as u32} else {1}, + }, + mipLevels: desc.levels as u32, + arrayLayers: slices.unwrap_or(1) as u32, + samples: aa.get_num_fragments() as vk::SampleCountFlagBits, + tiling: tiling, + usage: usage, + sharingMode: vk::SHARING_MODE_EXCLUSIVE, + queueFamilyIndexCount: 0, + pQueueFamilyIndices: ptr::null(), + initialLayout: data::map_image_layout(desc.bind), + }; + let (dev, vk) = self.share.get_device(); + let mut image = 0; + assert_eq!(vk::SUCCESS, unsafe { + vk.CreateImage(dev, &info, ptr::null(), &mut image) + }); + let reqs = unsafe { + let mut out = mem::zeroed(); + vk.GetImageMemoryRequirements(dev, image, &mut out); + out + }; + let tex = native::Texture { + image: image, + layout: cell::Cell::new(info.initialLayout), + memory: self.alloc(desc.usage, reqs), + }; + assert_eq!(vk::SUCCESS, unsafe { + vk.BindImageMemory(dev, image, tex.memory, 0) + }); + Ok(self.share.handles.borrow_mut().make_texture(tex, desc)) + } + + fn view_buffer_as_shader_resource_raw(&mut self, _hbuf: &h::RawBuffer) + -> Result, f::ResourceViewError> { + Err(f::ResourceViewError::Unsupported) //TODO + } + + fn view_buffer_as_unordered_access_raw(&mut self, _hbuf: &h::RawBuffer) + -> Result, f::ResourceViewError> { + Err(f::ResourceViewError::Unsupported) //TODO + } + + fn view_texture_as_shader_resource_raw(&mut self, htex: &h::RawTexture, desc: core::tex::ResourceDesc) + -> Result, f::ResourceViewError> { + use gfx_core::handle::Producer; + self.view_texture(htex, desc, false).map(|view| + self.share.handles.borrow_mut().make_texture_srv(view, htex)) + } + + fn view_texture_as_unordered_access_raw(&mut self, _htex: &h::RawTexture) + -> Result, f::ResourceViewError> { + Err(f::ResourceViewError::Unsupported) //TODO + } + + fn view_texture_as_render_target_raw(&mut self, htex: &h::RawTexture, desc: core::tex::RenderDesc) + -> Result, f::TargetViewError> + { + use gfx_core::handle::Producer; + let mut dim = htex.get_info().kind.get_dimensions(); + if desc.layer.is_some() { + dim.2 = 1; // slice of the depth/array + } + self.view_target(htex, desc.channel, desc.layer).map(|view| + self.share.handles.borrow_mut().make_rtv(view, htex, dim)) + } + + fn view_texture_as_depth_stencil_raw(&mut self, htex: &h::RawTexture, desc: core::tex::DepthStencilDesc) + -> Result, f::TargetViewError> + { + use gfx_core::handle::Producer; + let mut dim = htex.get_info().kind.get_dimensions(); + if desc.layer.is_some() { + dim.2 = 1; // slice of the depth/array + } + let channel = ChannelType::Unorm; //TODO + self.view_target(htex, channel, desc.layer).map(|view| + self.share.handles.borrow_mut().make_dsv(view, htex, dim)) + } + + fn create_sampler(&mut self, info: core::tex::SamplerInfo) -> h::Sampler { + use gfx_core::handle::Producer; + + let (min, mag, mip, aniso) = data::map_filter(info.filter); + let native_info = vk::SamplerCreateInfo { + sType: vk::STRUCTURE_TYPE_SAMPLER_CREATE_INFO, + pNext: ptr::null(), + flags: 0, + magFilter: mag, + minFilter: min, + mipmapMode: mip, + addressModeU: data::map_wrap(info.wrap_mode.0), + addressModeV: data::map_wrap(info.wrap_mode.1), + addressModeW: data::map_wrap(info.wrap_mode.2), + mipLodBias: info.lod_bias.into(), + anisotropyEnable: if aniso > 0.0 { vk::TRUE } else { vk::FALSE }, + maxAnisotropy: aniso, + compareEnable: if info.comparison.is_some() { vk::TRUE } else { vk::FALSE }, + compareOp: data::map_comparison(info.comparison.unwrap_or(state::Comparison::Never)), + minLod: info.lod_range.0.into(), + maxLod: info.lod_range.1.into(), + borderColor: match data::map_border_color(info.border) { + Some(bc) => bc, + None => { + error!("Unsupported border color {:x}", info.border.0); + vk::BORDER_COLOR_FLOAT_TRANSPARENT_BLACK + } + }, + unnormalizedCoordinates: vk::FALSE, + }; + + let (dev, vk) = self.share.get_device(); + let mut sampler = 0; + assert_eq!(vk::SUCCESS, unsafe { + vk.CreateSampler(dev, &native_info, ptr::null(), &mut sampler) + }); + self.share.handles.borrow_mut().make_sampler(sampler, info) + } + + fn map_buffer_raw(&mut self, _buf: &h::RawBuffer, _access: f::MapAccess) -> RawMapping { + unimplemented!() + } + + fn unmap_buffer_raw(&mut self, _map: RawMapping) { + unimplemented!() + } + + fn map_buffer_readable(&mut self, _buf: &h::Buffer) + -> core::mapping::Readable { + unimplemented!() + } + + fn map_buffer_writable(&mut self, _buf: &h::Buffer) + -> core::mapping::Writable { + unimplemented!() + } + + fn map_buffer_rw(&mut self, _buf: &h::Buffer) + -> core::mapping::RW { + unimplemented!() + } +} \ No newline at end of file diff --git a/src/backend/vulkan/src/lib.rs b/src/backend/vulkan/src/lib.rs new file mode 100644 index 00000000000..26fe91f179f --- /dev/null +++ b/src/backend/vulkan/src/lib.rs @@ -0,0 +1,281 @@ +// Copyright 2016 The Gfx-rs Developers. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#[macro_use] +extern crate log; +extern crate shared_library; +extern crate gfx_core; +extern crate vk_sys as vk; + +use std::{fmt, iter, mem, ptr}; +use std::cell::RefCell; +use std::sync::Arc; +use shared_library::dynamic_library::DynamicLibrary; + +pub use self::command::{GraphicsQueue, Buffer as CommandBuffer}; +pub use self::factory::Factory; + +mod command; +pub mod data; +mod factory; +mod native; + + +struct PhysicalDeviceInfo { + device: vk::PhysicalDevice, + _properties: vk::PhysicalDeviceProperties, + queue_families: Vec, + memory: vk::PhysicalDeviceMemoryProperties, + _features: vk::PhysicalDeviceFeatures, +} + +impl PhysicalDeviceInfo { + pub fn new(dev: vk::PhysicalDevice, vk: &vk::InstancePointers) -> PhysicalDeviceInfo { + PhysicalDeviceInfo { + device: dev, + _properties: unsafe { + let mut out = mem::zeroed(); + vk.GetPhysicalDeviceProperties(dev, &mut out); + out + }, + queue_families: unsafe { + let mut num = 4; + let mut families = Vec::with_capacity(num as usize); + vk.GetPhysicalDeviceQueueFamilyProperties(dev, &mut num, families.as_mut_ptr()); + families.set_len(num as usize); + families + }, + memory: unsafe { + let mut out = mem::zeroed(); + vk.GetPhysicalDeviceMemoryProperties(dev, &mut out); + out + }, + _features: unsafe { + let mut out = mem::zeroed(); + vk.GetPhysicalDeviceFeatures(dev, &mut out); + out + }, + } + } +} + + +pub struct Share { + _dynamic_lib: DynamicLibrary, + _library: vk::Static, + instance: vk::Instance, + inst_pointers: vk::InstancePointers, + device: vk::Device, + dev_pointers: vk::DevicePointers, + handles: RefCell>, +} + +pub type SharePointer = Arc; + +impl Share { + pub fn get_instance(&self) -> (vk::Instance, &vk::InstancePointers) { + (self.instance, &self.inst_pointers) + } + pub fn get_device(&self) -> (vk::Device, &vk::DevicePointers) { + (self.device, &self.dev_pointers) + } +} + +pub fn create(app_name: &str, app_version: u32, layers: &[&str], extensions: &[&str], + dev_extensions: &[&str]) -> (command::GraphicsQueue, factory::Factory, SharePointer) { + use std::ffi::CString; + use std::path::Path; + + let dynamic_lib = DynamicLibrary::open(Some(Path::new("libvulkan.so.1"))).unwrap(); + let lib = vk::Static::load(|name| unsafe { + let name = name.to_str().unwrap(); + dynamic_lib.symbol(name).unwrap() + }); + let entry_points = vk::EntryPoints::load(|name| unsafe { + mem::transmute(lib.GetInstanceProcAddr(0, name.as_ptr())) + }); + + let app_info = vk::ApplicationInfo { + sType: vk::STRUCTURE_TYPE_APPLICATION_INFO, + pNext: ptr::null(), + pApplicationName: app_name.as_ptr() as *const _, + applicationVersion: app_version, + pEngineName: "gfx-rs".as_ptr() as *const _, + engineVersion: 0x1000, //TODO + apiVersion: 0x400000, //TODO + }; + + + let instance = { + let cstrings = layers.iter().chain(extensions.iter()) + .map(|&s| CString::new(s).unwrap()) + .collect::>(); + let str_pointers = cstrings.iter().map(|s| s.as_ptr()) + .collect::>(); + + let create_info = vk::InstanceCreateInfo { + sType: vk::STRUCTURE_TYPE_INSTANCE_CREATE_INFO, + pNext: ptr::null(), + flags: 0, + pApplicationInfo: &app_info, + enabledLayerCount: layers.len() as u32, + ppEnabledLayerNames: str_pointers.as_ptr(), + enabledExtensionCount: extensions.len() as u32, + ppEnabledExtensionNames: str_pointers[layers.len()..].as_ptr(), + }; + let mut out = 0; + assert_eq!(vk::SUCCESS, unsafe { + entry_points.CreateInstance(&create_info, ptr::null(), &mut out) + }); + out + }; + + let inst_pointers = vk::InstancePointers::load(|name| unsafe { + mem::transmute(lib.GetInstanceProcAddr(instance, name.as_ptr())) + }); + + let mut physical_devices: [vk::PhysicalDevice; 4] = unsafe { mem::zeroed() }; + let mut num = physical_devices.len() as u32; + assert_eq!(vk::SUCCESS, unsafe { + inst_pointers.EnumeratePhysicalDevices(instance, &mut num, physical_devices.as_mut_ptr()) + }); + let devices = physical_devices[..num as usize].iter() + .map(|dev| PhysicalDeviceInfo::new(*dev, &inst_pointers)) + .collect::>(); + + let (dev, (qf_id, _)) = devices.iter() + .flat_map(|d| iter::repeat(d).zip(d.queue_families.iter().enumerate())) + .find(|&(_, (_, qf))| qf.queueFlags & vk::QUEUE_GRAPHICS_BIT != 0) + .unwrap(); + info!("Chosen physical device {:?} with queue family {}", dev.device, qf_id); + + let mvid_id = dev.memory.memoryTypes.iter().take(dev.memory.memoryTypeCount as usize) + .position(|mt| mt.propertyFlags & vk::MEMORY_PROPERTY_DEVICE_LOCAL_BIT != 0) + .unwrap() as u32; + let msys_id = dev.memory.memoryTypes.iter().take(dev.memory.memoryTypeCount as usize) + .position(|mt| mt.propertyFlags & vk::MEMORY_PROPERTY_HOST_COHERENT_BIT != 0) + .unwrap() as u32; + + let device = { + let cstrings = dev_extensions.iter() + .map(|&s| CString::new(s).unwrap()) + .collect::>(); + let str_pointers = cstrings.iter().map(|s| s.as_ptr()) + .collect::>(); + + let queue_info = vk::DeviceQueueCreateInfo { + sType: vk::STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO, + pNext: ptr::null(), + flags: 0, + queueFamilyIndex: qf_id as u32, + queueCount: 1, + pQueuePriorities: &1.0, + }; + let features = unsafe{ mem::zeroed() }; + + let dev_info = vk::DeviceCreateInfo { + sType: vk::STRUCTURE_TYPE_DEVICE_CREATE_INFO, + pNext: ptr::null(), + flags: 0, + queueCreateInfoCount: 1, + pQueueCreateInfos: &queue_info, + enabledLayerCount: 0, + ppEnabledLayerNames: ptr::null(), + enabledExtensionCount: str_pointers.len() as u32, + ppEnabledExtensionNames: str_pointers.as_ptr(), + pEnabledFeatures: &features, + }; + let mut out = 0; + assert_eq!(vk::SUCCESS, unsafe { + inst_pointers.CreateDevice(dev.device, &dev_info, ptr::null(), &mut out) + }); + out + }; + + let dev_pointers = vk::DevicePointers::load(|name| unsafe { + inst_pointers.GetDeviceProcAddr(device, name.as_ptr()) as *const _ + }); + let queue = unsafe { + let mut out = mem::zeroed(); + dev_pointers.GetDeviceQueue(device, qf_id as u32, 0, &mut out); + out + }; + + let share = Arc::new(Share { + _dynamic_lib: dynamic_lib, + _library: lib, + instance: instance, + inst_pointers: inst_pointers, + device: device, + dev_pointers: dev_pointers, + handles: RefCell::new(gfx_core::handle::Manager::new()), + }); + let gfx_device = command::GraphicsQueue::new(share.clone(), queue, qf_id as u32); + let gfx_factory = factory::Factory::new(share.clone(), qf_id as u32, mvid_id, msys_id); + + (gfx_device, gfx_factory, share) +} + + +#[derive(Clone, PartialEq, Eq)] +pub struct Error(pub vk::Result); + +impl fmt::Debug for Error { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.write_str(match self.0 { + vk::SUCCESS => "success", + vk::NOT_READY => "not ready", + vk::TIMEOUT => "timeout", + vk::EVENT_SET => "event_set", + vk::EVENT_RESET => "event_reset", + vk::INCOMPLETE => "incomplete", + vk::ERROR_OUT_OF_HOST_MEMORY => "out of host memory", + vk::ERROR_OUT_OF_DEVICE_MEMORY => "out of device memory", + vk::ERROR_INITIALIZATION_FAILED => "initialization failed", + vk::ERROR_DEVICE_LOST => "device lost", + vk::ERROR_MEMORY_MAP_FAILED => "memory map failed", + vk::ERROR_LAYER_NOT_PRESENT => "layer not present", + vk::ERROR_EXTENSION_NOT_PRESENT => "extension not present", + vk::ERROR_FEATURE_NOT_PRESENT => "feature not present", + vk::ERROR_INCOMPATIBLE_DRIVER => "incompatible driver", + vk::ERROR_TOO_MANY_OBJECTS => "too many objects", + vk::ERROR_FORMAT_NOT_SUPPORTED => "format not supported", + vk::ERROR_SURFACE_LOST_KHR => "surface lost (KHR)", + vk::ERROR_NATIVE_WINDOW_IN_USE_KHR => "native window in use (KHR)", + vk::SUBOPTIMAL_KHR => "suboptimal (KHR)", + vk::ERROR_OUT_OF_DATE_KHR => "out of date (KHR)", + vk::ERROR_INCOMPATIBLE_DISPLAY_KHR => "incompatible display (KHR)", + vk::ERROR_VALIDATION_FAILED_EXT => "validation failed (EXT)", + _ => "unknown", + }) + } +} + + +#[derive(Copy, Clone, Debug, Eq, Hash, PartialEq)] +pub enum Resources {} + +impl gfx_core::Resources for Resources { + type Buffer = native::Buffer; + type Shader = vk::ShaderModule; + type Program = native::Program; + type PipelineStateObject = native::Pipeline; + type Texture = native::Texture; + type ShaderResourceView = native::TextureView; //TODO: buffer view + type UnorderedAccessView = (); + type RenderTargetView = native::TextureView; + type DepthStencilView = native::TextureView; + type Sampler = vk::Sampler; + type Fence = vk::Fence; +} diff --git a/src/backend/vulkan/src/native.rs b/src/backend/vulkan/src/native.rs new file mode 100644 index 00000000000..1444d8dafb7 --- /dev/null +++ b/src/backend/vulkan/src/native.rs @@ -0,0 +1,74 @@ +// Copyright 2016 The Gfx-rs Developers. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use std::{cell, hash}; +use vk; +use gfx_core; +use Resources as R; + + +#[derive(Clone, Debug, Eq, Hash, PartialEq)] +pub struct Program { + pub vertex: gfx_core::VertexShader, + pub geometry: Option>, + pub pixel: gfx_core::PixelShader, +} +unsafe impl Send for Program {} +unsafe impl Sync for Program {} + + +#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] +pub struct Buffer { + pub buffer: vk::Buffer, + pub memory: vk::DeviceMemory, +} +unsafe impl Send for Buffer {} +unsafe impl Sync for Buffer {} + + +#[derive(Clone, Debug, Eq, PartialEq)] +pub struct Texture { + pub image: vk::Image, + pub layout: cell::Cell, + pub memory: vk::DeviceMemory, +} +impl hash::Hash for Texture { + fn hash(&self, state: &mut H) where H: hash::Hasher { + self.image.hash(state); + self.layout.get().hash(state); + self.memory.hash(state); + } +} +unsafe impl Send for Texture {} +unsafe impl Sync for Texture {} + +#[derive(Clone, Copy, Debug, Hash, Eq, PartialEq)] +pub struct TextureView { + pub image: vk::Image, + pub view: vk::ImageView, + pub layout: vk::ImageLayout, + pub sub_range: vk::ImageSubresourceRange, +} +unsafe impl Send for TextureView {} +unsafe impl Sync for TextureView {} + +#[derive(Clone, Debug, Hash, Eq, PartialEq)] +pub struct Pipeline { + pub pipeline: vk::Pipeline, + pub pipe_layout: vk::PipelineLayout, + pub desc_layout: vk::DescriptorSetLayout, + pub desc_pool: vk::DescriptorPool, + pub render_pass: vk::RenderPass, + pub program: gfx_core::handle::Program, +} diff --git a/src/core/Cargo.toml b/src/core/Cargo.toml index b841376ce41..4c315927ddf 100644 --- a/src/core/Cargo.toml +++ b/src/core/Cargo.toml @@ -14,7 +14,7 @@ [package] name = "gfx_core" -version = "0.4.0" +version = "0.5.0" description = "Core library of Gfx-rs" homepage = "https://github.com/gfx-rs/gfx" repository = "https://github.com/gfx-rs/gfx" diff --git a/src/core/src/draw.rs b/src/core/src/draw.rs index f57ab25742d..04323ad075c 100644 --- a/src/core/src/draw.rs +++ b/src/core/src/draw.rs @@ -38,8 +38,6 @@ pub type InstanceOption = Option<(InstanceCount, VertexCount)>; /// efficient API-specific manner, to be ready for execution on the device. #[allow(missing_docs)] pub trait CommandBuffer { - /// Clone as an empty buffer - fn clone_empty(&self) -> Self; /// Reset the command buffer contents, retain the allocated storage fn reset(&mut self); /// Bind a pipeline state object diff --git a/src/core/src/dummy.rs b/src/core/src/dummy.rs index b8968c5d63d..9fa4d3f4a48 100644 --- a/src/core/src/dummy.rs +++ b/src/core/src/dummy.rs @@ -68,7 +68,6 @@ impl DummyDevice { /// Dummy command buffer, which ignores all the calls. pub struct DummyCommandBuffer; impl draw::CommandBuffer for DummyCommandBuffer { - fn clone_empty(&self) -> DummyCommandBuffer { DummyCommandBuffer } fn reset(&mut self) {} fn bind_pipeline_state(&mut self, _: ()) {} fn bind_vertex_buffers(&mut self, _: pso::VertexBufferSet) {} diff --git a/src/core/src/factory.rs b/src/core/src/factory.rs index d33720af2af..6102fdd1f10 100644 --- a/src/core/src/factory.rs +++ b/src/core/src/factory.rs @@ -152,7 +152,7 @@ impl Error for BufferError { } /// An error happening on buffer updates. -#[derive(Clone, PartialEq, Debug)] +#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] pub enum BufferUpdateError { /// Trying to change the contents outside of the allocation. OutOfBounds, @@ -173,6 +173,33 @@ impl Error for BufferUpdateError { } } +/// An error associated with selected texture layer. +#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] +pub enum LayerError { + /// The source texture kind doesn't support array slices. + NotExpected(tex::Kind), + /// Selected layer is outside of the provided range. + OutOfBounds(target::Layer, target::Layer), +} + +impl fmt::Display for LayerError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match *self { + LayerError::NotExpected(kind) => write!(f, "{}: {:?}", self.description(), kind), + LayerError::OutOfBounds(layer, count) => write!(f, "{}: {}/{}", self.description(), layer, count), + } + } +} + +impl Error for LayerError { + fn description(&self) -> &str { + match *self { + LayerError::NotExpected(_) => "The source texture kind doesn't support array slices", + LayerError::OutOfBounds(_, _) => "Selected layer is outside of the provided range", + } + } +} + /// Error creating either a ShaderResourceView, or UnorderedAccessView. #[derive(Clone, PartialEq, Debug)] pub enum ResourceViewError { @@ -180,16 +207,18 @@ pub enum ResourceViewError { NoBindFlag, /// Selected channel type is not supported for this texture. Channel(format::ChannelType), + /// Selected layer can not be viewed for this texture. + Layer(LayerError), /// The backend was refused for some reason. Unsupported, } impl fmt::Display for ResourceViewError { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - if let ResourceViewError::Channel(ref channel_type) = *self { - write!(f, "{}: {:?}", self.description(), channel_type) - } else { - write!(f, "{}", self.description()) + match *self { + ResourceViewError::Channel(ref channel_type) => write!(f, "{}: {:?}", self.description(), channel_type), + ResourceViewError::Layer(ref le) => write!(f, "{}: {}", self.description(), le), + _ => write!(f, "{}", self.description()) } } } @@ -199,6 +228,7 @@ impl Error for ResourceViewError { match *self { ResourceViewError::NoBindFlag => "The corresponding bind flag is not present in the texture", ResourceViewError::Channel(_) => "Selected channel type is not supported for this texture", + ResourceViewError::Layer(_) => "Selected layer can not be viewed for this texture", ResourceViewError::Unsupported => "The backend was refused for some reason", } } @@ -210,9 +240,9 @@ pub enum TargetViewError { /// The `RENDER_TARGET`/`DEPTH_STENCIL` flag is not present in the texture. NoBindFlag, /// Selected mip level doesn't exist. - BadLevel(target::Level), + Level(target::Level), /// Selected array layer doesn't exist. - BadLayer(target::Layer), + Layer(LayerError), /// Selected channel type is not supported for this texture. Channel(format::ChannelType), /// The backend was refused for some reason. @@ -223,8 +253,8 @@ impl fmt::Display for TargetViewError { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { let description = self.description(); match *self { - TargetViewError::BadLevel(ref level) => write!(f, "{}: {}", description, level), - TargetViewError::BadLayer(ref layer) => write!(f, "{}: {}", description, layer), + TargetViewError::Level(ref level) => write!(f, "{}: {}", description, level), + TargetViewError::Layer(ref layer) => write!(f, "{}: {}", description, layer), TargetViewError::Channel(ref channel) => write!(f, "{}: {:?}", description, channel), _ => write!(f, "{}", description) } @@ -236,9 +266,9 @@ impl Error for TargetViewError { match *self { TargetViewError::NoBindFlag => "The `RENDER_TARGET`/`DEPTH_STENCIL` flag is not present in the texture", - TargetViewError::BadLevel(_) => + TargetViewError::Level(_) => "Selected mip level doesn't exist", - TargetViewError::BadLayer(_) => + TargetViewError::Layer(_) => "Selected array layer doesn't exist", TargetViewError::Channel(_) => "Selected channel type is not supported for this texture", @@ -454,6 +484,7 @@ pub trait Factory { assert!(levels.0 <= levels.1); let desc = tex::ResourceDesc { channel: ::get_channel_type(), + layer: None, min: levels.0, max: levels.1, swizzle: swizzle, diff --git a/src/core/src/handle.rs b/src/core/src/handle.rs index de89ec184c0..4c63f2093b3 100644 --- a/src/core/src/handle.rs +++ b/src/core/src/handle.rs @@ -16,7 +16,7 @@ //! Device resource handles -use std::mem; +use std::{cmp, hash, mem}; use std::marker::PhantomData; use std::sync::Arc; use {shade, tex, Resources}; @@ -33,7 +33,7 @@ impl RawBuffer { } /// Type-safe buffer handle -#[derive(Clone, Debug, Hash, PartialEq)] +#[derive(Clone, Debug, Eq, Hash, PartialEq)] pub struct Buffer(RawBuffer, PhantomData); impl Typed for Buffer { @@ -62,28 +62,41 @@ impl Buffer { } /// Shader Handle -#[derive(Clone, Debug, Hash, PartialEq)] +#[derive(Clone, Debug, Eq, Hash, PartialEq)] pub struct Shader(Arc); /// Program Handle -#[derive(Clone, Debug, PartialEq)] +#[derive(Clone, Debug)] pub struct Program(Arc, shade::ProgramInfo); +// custom implementations due to the limitations of `ProgramInfo` impl Program { /// Get program info pub fn get_info(&self) -> &shade::ProgramInfo { &self.1 } } +impl hash::Hash for Program { + fn hash(&self, state: &mut H) where H: hash::Hasher { + self.0.hash(state); + } +} +impl cmp::PartialEq for Program { + fn eq(&self, other: &Program) -> bool { + self.0.eq(&other.0) + } +} +impl cmp::Eq for Program {} + /// Raw Pipeline State Handle #[derive(Clone, Debug, PartialEq)] pub struct RawPipelineState(Arc, Arc); /// Raw texture object -#[derive(Clone, Debug, Hash, PartialEq)] +#[derive(Clone, Debug, Eq, Hash, PartialEq)] pub struct RawTexture(Arc, tex::Descriptor); /// Typed texture object -#[derive(Clone, Debug, Hash, PartialEq)] +#[derive(Clone, Debug, Eq, Hash, PartialEq)] pub struct Texture(RawTexture, PhantomData); impl RawTexture { @@ -106,18 +119,18 @@ impl Texture { pub fn get_info(&self) -> &tex::Descriptor { self.raw().get_info() } } -#[derive(Clone, Debug, Hash, PartialEq)] +#[derive(Clone, Debug, Eq, Hash, PartialEq)] enum ViewSource { Buffer(Arc), Texture(Arc), } /// Raw Shader Resource View Handle -#[derive(Clone, Debug, Hash, PartialEq)] +#[derive(Clone, Debug, Eq, Hash, PartialEq)] pub struct RawShaderResourceView(Arc, ViewSource); /// Type-safe Shader Resource View Handle -#[derive(Clone, Debug, Hash, PartialEq)] +#[derive(Clone, Debug, Eq, Hash, PartialEq)] pub struct ShaderResourceView(RawShaderResourceView, PhantomData); impl Typed for ShaderResourceView { @@ -131,11 +144,11 @@ impl Typed for ShaderResourceView { } /// Raw Unordered Access View Handle -#[derive(Clone, Debug, Hash, PartialEq)] +#[derive(Clone, Debug, Eq, Hash, PartialEq)] pub struct RawUnorderedAccessView(Arc, ViewSource); /// Type-safe Unordered Access View Handle -#[derive(Clone, Debug, Hash, PartialEq)] +#[derive(Clone, Debug, Eq, Hash, PartialEq)] pub struct UnorderedAccessView(RawUnorderedAccessView, PhantomData); impl Typed for UnorderedAccessView { @@ -213,7 +226,7 @@ impl Typed for DepthStencilView { } /// Sampler Handle -#[derive(Clone, Debug, PartialEq)] +#[derive(Clone, Debug, Eq, PartialEq)] pub struct Sampler(Arc, tex::SamplerInfo); impl Sampler { @@ -222,7 +235,7 @@ impl Sampler { } /// Fence Handle -#[derive(Clone, Debug, PartialEq)] +#[derive(Clone, Debug, Eq, PartialEq)] pub struct Fence(Arc); /// Stores reference-counted resources used in a command buffer. diff --git a/src/core/src/lib.rs b/src/core/src/lib.rs index 4f433d4fbcd..d8285a18b2d 100644 --- a/src/core/src/lib.rs +++ b/src/core/src/lib.rs @@ -75,6 +75,7 @@ pub type SamplerSlot = u8; macro_rules! define_shaders { ($($name:ident),+) => {$( #[allow(missing_docs)] + #[derive(Clone, Debug, Eq, Hash, PartialEq)] pub struct $name(handle::Shader); impl $name { #[allow(missing_docs)] @@ -88,6 +89,7 @@ macro_rules! define_shaders { define_shaders!(VertexShader, HullShader, DomainShader, GeometryShader, PixelShader); /// A complete set of shaders to link a program. +#[derive(Clone, Debug, Eq, Hash, PartialEq)] pub enum ShaderSet { /// Simple program: Vs-Ps Simple(VertexShader, PixelShader), diff --git a/src/core/src/pso.rs b/src/core/src/pso.rs index 547f477e985..848e8d732f1 100644 --- a/src/core/src/pso.rs +++ b/src/core/src/pso.rs @@ -18,7 +18,8 @@ //! will want to use the typed and safe `PipelineState`. See the `pso` module inside the `gfx` //! crate. -use {MAX_COLOR_TARGETS, MAX_VERTEX_ATTRIBUTES}; +use {MAX_COLOR_TARGETS, MAX_VERTEX_ATTRIBUTES, MAX_CONSTANT_BUFFERS, + MAX_RESOURCE_VIEWS, MAX_UNORDERED_VIEWS, MAX_SAMPLERS}; use {ConstantBufferSlot, ColorSlot, ResourceViewSlot, UnorderedViewSlot, SamplerSlot, Primitive, Resources}; @@ -28,6 +29,9 @@ use std::error::Error; use std::fmt; +/// Maximum number of vertex buffers used in a PSO definition. +pub const MAX_VERTEX_BUFFERS: usize = 4; + /// An offset inside a vertex buffer, in bytes. pub type BufferOffset = usize; @@ -114,6 +118,8 @@ impl From<(s::Depth, s::Stencil)> for DepthStencilInfo { } } +/// Index of a vertex buffer. +pub type BufferIndex = u8; /// Offset of an attribute from the start of the buffer, in bytes pub type ElemOffset = u32; /// Offset between attribute values, in bytes @@ -128,16 +134,31 @@ pub struct Element { pub format: F, /// Offset from the beginning of the container, in bytes pub offset: ElemOffset, +} + +/// Vertex buffer descriptor +#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] +pub struct VertexBufferDesc { /// Total container size, in bytes pub stride: ElemStride, + /// Rate of the input for the given buffer + pub rate: InstanceRate, } /// PSO vertex attribute descriptor -pub type AttributeDesc = (Element, InstanceRate); +pub type AttributeDesc = (BufferIndex, Element); +/// PSO constant buffer descriptor +pub type ConstantBufferDesc = Usage; +/// PSO shader resource view descriptor +pub type ResourceViewDesc = Usage; +/// PSO unordered access view descriptor +pub type UnorderedViewDesc = Usage; +/// PSO sampler descriptor +pub type SamplerDesc = Usage; /// PSO color target descriptor pub type ColorTargetDesc = (format::Format, ColorInfo); /// PSO depth-stencil target descriptor -pub type DepthStencilDesc = (format::SurfaceType, DepthStencilInfo); +pub type DepthStencilDesc = (format::Format, DepthStencilInfo); /// All the information surrounding a shader program that is required /// for PSO creation, including the formats of vertex buffers and pixel targets; @@ -149,8 +170,18 @@ pub struct Descriptor { pub rasterizer: s::Rasterizer, /// Enable scissor test pub scissor: bool, + /// Vertex buffers + pub vertex_buffers: [Option; MAX_VERTEX_BUFFERS], /// Vertex attributes pub attributes: [Option; MAX_VERTEX_ATTRIBUTES], + /// Constant buffers + pub constant_buffers: [Option; MAX_CONSTANT_BUFFERS], + /// Shader resource views + pub resource_views: [Option; MAX_RESOURCE_VIEWS], + /// Unordered access views + pub unordered_views: [Option; MAX_UNORDERED_VIEWS], + /// Samplers + pub samplers: [Option; MAX_SAMPLERS], /// Render target views (RTV) pub color_targets: [Option; MAX_COLOR_TARGETS], /// Depth stencil view (DSV) @@ -164,7 +195,12 @@ impl Descriptor { primitive: primitive, rasterizer: rast, scissor: false, + vertex_buffers: [None; MAX_VERTEX_BUFFERS], attributes: [None; MAX_VERTEX_ATTRIBUTES], + constant_buffers: [None; MAX_CONSTANT_BUFFERS], + resource_views: [None; MAX_RESOURCE_VIEWS], + unordered_views: [None; MAX_UNORDERED_VIEWS], + samplers: [None; MAX_SAMPLERS], color_targets: [None; MAX_COLOR_TARGETS], depth_stencil: None, } @@ -202,7 +238,7 @@ pub struct UnorderedViewParam(pub R::UnorderedAccessView, pub Usag pub struct SamplerParam(pub R::Sampler, pub Usage, pub SamplerSlot); /// A complete set of render targets to be used for pixel export in PSO. -#[derive(Copy, Clone, Debug, Eq, PartialEq)] +#[derive(Copy, Clone, Debug, Eq, Hash, PartialEq)] pub struct PixelTargetSet { /// Array of color target views pub colors: [Option; MAX_COLOR_TARGETS], diff --git a/src/core/src/tex.rs b/src/core/src/tex.rs index 7919f684ae3..9159a154eb7 100644 --- a/src/core/src/tex.rs +++ b/src/core/src/tex.rs @@ -218,7 +218,7 @@ impl Kind { } } /// Return the number of slices for an array, or None for non-arrays. - pub fn get_num_slices(&self) -> Option { + pub fn get_num_slices(&self) -> Option { match *self { Kind::D1(..) | Kind::D2(..) | Kind::D3(..) | Kind::Cube(..) => None, Kind::D1Array(_, a) => Some(a), @@ -419,6 +419,7 @@ impl Descriptor { #[derive(Eq, Ord, PartialEq, PartialOrd, Hash, Copy, Clone, Debug)] pub struct ResourceDesc { pub channel: format::ChannelType, + pub layer: Option, pub min: Level, pub max: Level, pub swizzle: format::Swizzle, diff --git a/src/lib.rs b/src/lib.rs index eaf249c8b32..576d9bfa3ef 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -17,10 +17,11 @@ extern crate winit; extern crate glutin; extern crate gfx; extern crate gfx_device_gl; -#[cfg(target_os = "windows")] -extern crate gfx_device_dx11; extern crate gfx_window_glutin; //extern crate gfx_window_glfw; + +#[cfg(target_os = "windows")] +extern crate gfx_device_dx11; #[cfg(target_os = "windows")] extern crate gfx_window_dxgi; @@ -29,6 +30,11 @@ extern crate gfx_device_metal; #[cfg(target_os = "macos")] extern crate gfx_window_metal; +#[cfg(feature = "vulkan")] +extern crate gfx_device_vulkan; +#[cfg(feature = "vulkan")] +extern crate gfx_window_vulkan; + pub mod shade; @@ -90,9 +96,15 @@ impl Drop for Harness { } } +pub trait Factory: gfx::Factory { + type CommandBuffer: gfx::CommandBuffer; + fn create_encoder(&mut self) -> gfx::Encoder; +} + + pub trait ApplicationBase> { - fn new(F, gfx::Encoder, Init) -> Self where - F: gfx::Factory; + fn new(F, Init) -> Self where + F: Factory; fn render(&mut self, &mut D) where D: gfx::Device; } @@ -112,6 +124,10 @@ pub trait Application: Sized { fn launch_default(name: &str) where WrapMetal: ApplicationMetal { WrapMetal::::launch(name, DEFAULT_CONFIG) }*/ + /*#[cfg(feature = "vulkan")] + fn launch_default(name: &str) where WrapVulkan: ApplicationVulkan { + WrapVulkan::::launch(name, DEFAULT_CONFIG); + }*/ } pub struct Wrap, A>{ @@ -128,17 +144,20 @@ pub type D3D11CommandBufferFake = gfx_device_dx11::CommandBuffer = Wrap; pub type WrapGL2 = Wrap; +#[cfg(feature = "vulkan")] +pub type WrapVulkan = Wrap; + impl ApplicationBase for Wrap where R: gfx::Resources, C: gfx::CommandBuffer, A: Application { - fn new(factory: F, encoder: gfx::Encoder, init: Init) -> Self where - F: gfx::Factory + fn new(mut factory: F, init: Init) -> Self where + F: Factory, { Wrap { - encoder: encoder, + encoder: factory.create_encoder(), app: A::new(factory, init), } } @@ -156,14 +175,11 @@ pub trait ApplicationGL { fn launch(&str, Config); } -#[cfg(target_os = "macos")] -pub trait ApplicationMetal { - fn launch(&str, Config); -} - -#[cfg(target_os = "windows")] -pub trait ApplicationD3D11 { - fn launch(&str, Config); +impl Factory for gfx_device_gl::Factory { + type CommandBuffer = gfx_device_gl::CommandBuffer; + fn create_encoder(&mut self) -> gfx::Encoder { + self.create_command_buffer().into() + } } impl ApplicationGL for A where @@ -183,13 +199,12 @@ impl ApplicationGL for A where .with_dimensions(config.size.0 as u32, config.size.1 as u32) .with_gl(gl_version) .with_vsync(); - let (window, mut device, mut factory, main_color, main_depth) = + let (window, mut device, factory, main_color, main_depth) = gfx_window_glutin::init::(builder); let (width, height) = window.get_inner_size().unwrap(); - let combuf = factory.create_command_buffer(); let shade_lang = device.get_info().shading_language; - let mut app = Self::new(factory, combuf.into(), Init { + let mut app = Self::new(factory, Init { backend: if shade_lang.is_embedded { shade::Backend::GlslEs(shade_lang) } else { @@ -219,6 +234,66 @@ impl ApplicationGL for A where } } + +#[cfg(target_os = "windows")] +pub trait ApplicationD3D11 { + fn launch(&str, Config); +} + +#[cfg(target_os = "windows")] +impl Factory for gfx_device_dx11::Factory { + type CommandBuffer = D3D11CommandBuffer; + fn create_encoder(&mut self) -> gfx::Encoder { + self.create_command_buffer_native().into() + } +} + +#[cfg(target_os = "windows")] +impl< + A: ApplicationBase +> ApplicationD3D11 for A { + fn launch(title: &str, config: Config) { + use gfx::traits::{Device, Factory}; + + env_logger::init().unwrap(); + let (window, device, mut factory, main_color) = + gfx_window_dxgi::init::(title, config.size.0, config.size.1) + .unwrap(); + let main_depth = factory.create_depth_stencil_view_only( + window.size.0, window.size.1).unwrap(); + + let mut app = Self::new(factory, Init { + backend: shade::Backend::Hlsl(device.get_shader_model()), + color: main_color, + depth: main_depth, + aspect_ratio: window.size.0 as f32 / window.size.1 as f32, + }); + let mut device: gfx_device_dx11::Deferred = device.into(); + + let mut harness = Harness::new(); + while window.dispatch() { + app.render(&mut device); + window.swap_buffers(1); + device.cleanup(); + harness.bump(); + } + } +} + + +#[cfg(target_os = "macos")] +pub trait ApplicationMetal { + fn launch(&str, Config); +} + +#[cfg(target_os = "macos")] +impl Factory for gfx_device_metal::Factory { + type CommandBuffer = gfx_device_meta::CommandBuffer; + fn create_encoder(&mut self) -> gfx::Encoder { + self.create_command_buffer().into() + } +} + #[cfg(target_os = "macos")] impl< A: ApplicationBase @@ -262,38 +337,45 @@ impl< } } -#[cfg(target_os = "windows")] + +#[cfg(feature = "vulkan")] +pub trait ApplicationVulkan { + fn launch(&str, Config); +} + +#[cfg(feature = "vulkan")] +impl Factory for gfx_device_vulkan::Factory { + type CommandBuffer = gfx_device_vulkan::CommandBuffer; + fn create_encoder(&mut self) -> gfx::Encoder { + self.create_command_buffer().into() + } +} + +#[cfg(feature = "vulkan")] impl< - A: ApplicationBase -> ApplicationD3D11 for A { + A: ApplicationBase +> ApplicationVulkan for A { fn launch(title: &str, config: Config) { use gfx::traits::{Device, Factory}; env_logger::init().unwrap(); - let (window, device, mut factory, main_color) = - gfx_window_dxgi::init::(title, config.size.0, config.size.1) - .unwrap(); - let main_depth = factory.create_depth_stencil_view_only( - window.size.0, window.size.1).unwrap(); - - //let combuf = factory.create_command_buffer(); - let combuf = factory.create_command_buffer_native(); - - let mut app = Self::new(factory, combuf.into(), Init { - backend: shade::Backend::Hlsl(device.get_shader_model()), - color: main_color, - depth: main_depth, - aspect_ratio: window.size.0 as f32 / window.size.1 as f32, + let (mut win, mut factory) = gfx_window_vulkan::init_xcb::(title, config.size.0 as u32, config.size.1 as u32); + let main_depth = factory.create_depth_stencil::(config.size.0, config.size.1).unwrap(); + + let mut app = Self::new(factory, Init { + backend: shade::Backend::Vulkan, + color: win.get_any_target(), + depth: main_depth.2, + aspect_ratio: config.size.0 as f32 / config.size.1 as f32, //TODO }); - let mut device: gfx_device_dx11::Deferred = device.into(); - let mut harness = Harness::new(); - while window.dispatch() { - app.render(&mut device); - window.swap_buffers(1); - device.cleanup(); - harness.bump(); + while let Ok(frame_opt) = win.wait_draw() { + if let Some(mut frame) = frame_opt { + app.render(frame.get_queue()); + frame.get_queue().cleanup(); + harness.bump(); + } } } } diff --git a/src/render/Cargo.toml b/src/render/Cargo.toml index 14d98a16457..8ca070185bd 100644 --- a/src/render/Cargo.toml +++ b/src/render/Cargo.toml @@ -14,7 +14,7 @@ [package] name = "gfx" -version = "0.12.0" +version = "0.13.0" description = "A high-performance, bindless graphics API" homepage = "https://github.com/gfx-rs/gfx" repository = "https://github.com/gfx-rs/gfx" @@ -32,4 +32,4 @@ unstable = [] [dependencies] draw_state = "0.6" log = "0.3" -gfx_core = { path = "../core", version = "0.4" } +gfx_core = { path = "../core", version = "0.5" } diff --git a/src/render/src/encoder.rs b/src/render/src/encoder.rs index dc8819c2bd5..bf183c6e8bd 100644 --- a/src/render/src/encoder.rs +++ b/src/render/src/encoder.rs @@ -110,15 +110,6 @@ impl> Encoder { self.handles.clear(); } - /// Clone the renderer shared data but ignore the commands. - pub fn clone_empty(&self) -> Encoder { - Encoder { - command_buffer: self.command_buffer.clone_empty(), - raw_pso_data: pso::RawDataSet::new(), - handles: handle::Manager::new(), - } - } - /// Update a buffer with a slice of data. pub fn update_buffer(&mut self, buf: &handle::Buffer, data: &[T], offset_elements: usize) diff --git a/src/render/src/lib.rs b/src/render/src/lib.rs index a8bb5e37adf..01e6b665fd2 100644 --- a/src/render/src/lib.rs +++ b/src/render/src/lib.rs @@ -40,7 +40,7 @@ pub use gfx_core::{ShaderSet, VertexShader, HullShader, DomainShader, pub use gfx_core::{format, handle, tex}; pub use gfx_core::factory::{Factory, Typed, Usage, Bind, MapAccess, BufferRole, BufferInfo, BufferError, BufferUpdateError, - ResourceViewError, TargetViewError, CombinedError, + LayerError, ResourceViewError, TargetViewError, CombinedError, RENDER_TARGET, DEPTH_STENCIL, SHADER_RESOURCE, UNORDERED_ACCESS, cast_slice}; pub use gfx_core::draw::{CommandBuffer, InstanceOption}; diff --git a/src/render/src/macros/pso.rs b/src/render/src/macros/pso.rs index 0488619818e..6b311867e54 100644 --- a/src/render/src/macros/pso.rs +++ b/src/render/src/macros/pso.rs @@ -43,6 +43,14 @@ macro_rules! gfx_pipeline_inner { $( $field: <$ty as DataLink<'a>>::new(), )* }; // v# + let mut _num_vb = 0; + $( + if let Some(d) = meta.$field.link_vertex_buffer(_num_vb, &self.$field) { + assert!(meta.$field.is_active()); + desc.vertex_buffers[_num_vb as usize] = Some(d); + _num_vb += 1; + } + )* for at in &info.vertex_attributes { $( match meta.$field.link_input(at, &self.$field) { @@ -63,8 +71,9 @@ macro_rules! gfx_pipeline_inner { for cb in &info.constant_buffers { $( match meta.$field.link_constant_buffer(cb, &self.$field) { - Some(Ok(())) => { + Some(Ok(d)) => { assert!(meta.$field.is_active()); + desc.constant_buffers[cb.slot as usize] = Some(d); continue; }, Some(Err(e)) => return Err( @@ -95,8 +104,9 @@ macro_rules! gfx_pipeline_inner { for srv in &info.textures { $( match meta.$field.link_resource_view(srv, &self.$field) { - Some(Ok(())) => { + Some(Ok(d)) => { assert!(meta.$field.is_active()); + desc.resource_views[srv.slot as usize] = Some(d); continue; }, Some(Err(_)) => return Err( @@ -111,8 +121,9 @@ macro_rules! gfx_pipeline_inner { for uav in &info.unordereds { $( match meta.$field.link_unordered_view(uav, &self.$field) { - Some(Ok(())) => { + Some(Ok(d)) => { assert!(meta.$field.is_active()); + desc.unordered_views[uav.slot as usize] = Some(d); continue; }, Some(Err(_)) => return Err( @@ -127,8 +138,9 @@ macro_rules! gfx_pipeline_inner { for sm in &info.samplers { $( match meta.$field.link_sampler(sm, &self.$field) { - Some(()) => { + Some(d) => { assert!(meta.$field.is_active()); + desc.samplers[sm.slot as usize] = Some(d); continue; }, None => (), diff --git a/src/render/src/macros/structure.rs b/src/render/src/macros/structure.rs index 2b35063bc6f..d727311c2ed 100644 --- a/src/render/src/macros/structure.rs +++ b/src/render/src/macros/structure.rs @@ -29,8 +29,7 @@ macro_rules! gfx_impl_struct { impl $crate::pso::buffer::Structure<$runtime_format> for $root { fn query(name: &str) -> Option<$crate::pso::buffer::Element<$runtime_format>> { use std::mem::size_of; - use $crate::pso::buffer::{Element, ElemOffset, ElemStride}; - let stride = size_of::<$root>() as ElemStride; + use $crate::pso::buffer::{Element, ElemOffset}; let tmp: &$root = unsafe{ ::std::mem::uninitialized() }; let base = tmp as *const _ as usize; //HACK: special treatment of array queries @@ -44,7 +43,7 @@ macro_rules! gfx_impl_struct { Some(s) if s.starts_with('.') => &s[1..], _ => name, }; - (sub_name, array_id * (stride as ElemOffset)) + (sub_name, array_id * (size_of::<$root>() as ElemOffset)) }, None => (name, 0), } @@ -54,7 +53,6 @@ macro_rules! gfx_impl_struct { $name => Some(Element { format: <$ty as $compile_format>::get_format(), offset: ((&tmp.$field as *const _ as usize) - base) as ElemOffset + big_offset, - stride: stride, }), )* _ => None, diff --git a/src/render/src/pso/buffer.rs b/src/render/src/pso/buffer.rs index 3743361e1ba..62824dcf2d6 100644 --- a/src/render/src/pso/buffer.rs +++ b/src/render/src/pso/buffer.rs @@ -22,7 +22,7 @@ use gfx_core::format::Format; use shade::{ToUniform, Usage}; use super::{DataLink, DataBind, ElementError, RawDataSet}; -pub use gfx_core::pso::{Element, ElemOffset, ElemStride, InstanceRate}; +pub use gfx_core::pso::{BufferIndex, Element, ElemOffset, ElemStride, InstanceRate}; /// A trait to be implemented by any struct having the layout described /// in the graphics API, like a vertex buffer. @@ -41,9 +41,9 @@ pub type VertexBuffer = VertexBufferCommon; /// Instance buffer component. Same as the vertex buffer but advances per instance. pub type InstanceBuffer = VertexBufferCommon; /// Raw vertex/instance buffer component. -/// - init: ? +/// - init: `(&[&str, element], stride, inst_rate)` /// - data: `RawBuffer` -pub struct RawVertexBuffer(AttributeSlotSet); +pub struct RawVertexBuffer(Option, AttributeSlotSet); /// Constant buffer component. /// - init: `&str` = name of the buffer /// - data: `Buffer` @@ -65,16 +65,25 @@ impl<'a, > DataLink<'a> for VertexBufferCommon { type Init = (); fn new() -> Self { - VertexBufferCommon(RawVertexBuffer(0), PhantomData) + VertexBufferCommon(DataLink::new(), PhantomData) } fn is_active(&self) -> bool { self.0.is_active() } + fn link_vertex_buffer(&mut self, index: BufferIndex, _: &Self::Init) + -> Option { + use std::mem; + (self.0).0 = Some(index); + let rate = ::default().as_ref().len(); + Some(pso::VertexBufferDesc { + stride: mem::size_of::() as ElemStride, + rate: rate as InstanceRate, + }) + } fn link_input(&mut self, at: &shade::AttributeVar, _: &Self::Init) -> Option> { T::query(&at.name).map(|el| { - let rate = ::default().as_ref().len(); - self.0.link(at, el, rate as InstanceRate) + self.0.link(at, el) }) } } @@ -87,11 +96,11 @@ impl DataBind for VertexBufferCommon { } impl RawVertexBuffer { - fn link(&mut self, at: &shade::AttributeVar, el: Element, rate: InstanceRate) + fn link(&mut self, at: &shade::AttributeVar, el: Element) -> Result { - self.0 |= 1 << (at.slot as AttributeSlotSet); + self.1 |= 1 << (at.slot as AttributeSlotSet); if match_attribute(at, el.format) { - Ok((el, rate)) + Ok((self.0.unwrap(), el)) }else { Err(el.format) } @@ -99,17 +108,25 @@ impl RawVertexBuffer { } impl<'a> DataLink<'a> for RawVertexBuffer { - type Init = &'a [(&'a str, Element, InstanceRate)]; + type Init = (&'a [(&'a str, Element)], ElemStride, InstanceRate); fn new() -> Self { - RawVertexBuffer(0) + RawVertexBuffer(None, 0) } fn is_active(&self) -> bool { - self.0 != 0 + self.0.is_some() + } + fn link_vertex_buffer(&mut self, index: BufferIndex, init: &Self::Init) + -> Option { + self.0 = Some(index); + Some(pso::VertexBufferDesc { + stride: init.1, + rate: init.2, + }) } fn link_input(&mut self, at: &shade::AttributeVar, init: &Self::Init) -> Option> { - init.iter().find(|x| x.0 == &at.name) - .map(|x| self.link(at, x.1, x.2)) + init.0.iter().find(|x| x.0 == &at.name) + .map(|x| self.link(at, x.1)) } } @@ -118,7 +135,7 @@ impl DataBind for RawVertexBuffer { fn bind_to(&self, out: &mut RawDataSet, data: &Self::Data, man: &mut handle::Manager) { let value = Some((man.ref_buffer(data).clone(), 0)); for i in 0 .. MAX_VERTEX_ATTRIBUTES { - if (self.0 & (1< for ConstantBuffer { self.0.is_some() } fn link_constant_buffer<'b>(&mut self, cb: &'b shade::ConstantBufferVar, init: &Self::Init) - -> Option>> { + -> Option>> { if &cb.name == *init { for el in cb.elements.iter() { return Some(Err(match T::query(&el.name) { @@ -147,7 +164,7 @@ DataLink<'a> for ConstantBuffer { })) } self.0 = Some((cb.usage, cb.slot)); - Some(Ok(())) + Some(Ok(cb.usage)) }else { None } diff --git a/src/render/src/pso/mod.rs b/src/render/src/pso/mod.rs index a41f851b8c8..e4ba3b306bd 100644 --- a/src/render/src/pso/mod.rs +++ b/src/render/src/pso/mod.rs @@ -245,12 +245,15 @@ pub trait DataLink<'a>: Sized { fn new() -> Self; /// Check if this link is actually used by the shader. fn is_active(&self) -> bool; + /// Attempt to link with a vertex buffer containing multiple attributes. + fn link_vertex_buffer(&mut self, _: d::pso::BufferIndex, _: &Self::Init) -> + Option { None } /// Attempt to link with a vertex attribute. fn link_input(&mut self, _: &d::shade::AttributeVar, _: &Self::Init) -> Option> { None } /// Attempt to link with a constant buffer. fn link_constant_buffer<'b>(&mut self, _: &'b d::shade::ConstantBufferVar, _: &Self::Init) -> - Option>> { None } + Option>> { None } /// Attempt to link with a global constant. fn link_global_constant(&mut self, _: &d::shade::ConstVar, _: &Self::Init) -> Option> { None } @@ -262,12 +265,13 @@ pub trait DataLink<'a>: Sized { Option { None } /// Attempt to link with a shader resource (SRV). fn link_resource_view(&mut self, _: &d::shade::TextureVar, _: &Self::Init) -> - Option> { None } + Option> { None } /// Attempt to link with an unordered access (UAV). fn link_unordered_view(&mut self, _: &d::shade::UnorderedVar, _: &Self::Init) -> - Option> { None } + Option> { None } /// Attempt to link with a sampler. - fn link_sampler(&mut self, _: &d::shade::SamplerVar, _: &Self::Init) -> Option<()> { None } + fn link_sampler(&mut self, _: &d::shade::SamplerVar, _: &Self::Init) + -> Option { None } /// Attempt to enable scissor test. fn link_scissor(&mut self) -> bool { false } } diff --git a/src/render/src/pso/resource.rs b/src/render/src/pso/resource.rs index 23a5052fbe3..583a3eff7c2 100644 --- a/src/render/src/pso/resource.rs +++ b/src/render/src/pso/resource.rs @@ -58,7 +58,7 @@ impl<'a, T> DataLink<'a> for ShaderResource { self.0.is_active() } fn link_resource_view(&mut self, var: &shade::TextureVar, init: &Self::Init) - -> Option> { + -> Option> { self.0.link_resource_view(var, init) } } @@ -80,10 +80,10 @@ impl<'a> DataLink<'a> for RawShaderResource { self.0.is_some() } fn link_resource_view(&mut self, var: &shade::TextureVar, init: &Self::Init) - -> Option> { + -> Option> { if *init == var.name { self.0 = Some((var.slot, var.usage)); - Some(Ok(())) //TODO: check format + Some(Ok(var.usage)) //TODO: check format }else { None } @@ -110,10 +110,10 @@ impl<'a, T> DataLink<'a> for UnorderedAccess { self.0.is_some() } fn link_unordered_view(&mut self, var: &shade::UnorderedVar, init: &Self::Init) - -> Option> { + -> Option> { if *init == var.name { self.0 = Some((var.slot, var.usage)); - Some(Ok(())) //TODO: check format + Some(Ok(var.usage)) //TODO: check format }else { None } @@ -139,10 +139,11 @@ impl<'a> DataLink<'a> for Sampler { fn is_active(&self) -> bool { self.0.is_some() } - fn link_sampler(&mut self, var: &shade::SamplerVar, init: &Self::Init) -> Option<()> { + fn link_sampler(&mut self, var: &shade::SamplerVar, init: &Self::Init) + -> Option { if *init == var.name { self.0 = Some((var.slot, var.usage)); - Some(()) + Some(var.usage) }else { None } @@ -169,10 +170,10 @@ impl<'a, T> DataLink<'a> for TextureSampler { self.0.is_active() } fn link_resource_view(&mut self, var: &shade::TextureVar, init: &Self::Init) - -> Option> { + -> Option> { self.0.link_resource_view(var, init) } - fn link_sampler(&mut self, var: &shade::SamplerVar, init: &Self::Init) -> Option<()> { + fn link_sampler(&mut self, var: &shade::SamplerVar, init: &Self::Init) -> Option { self.1.link_sampler(var, init) } } diff --git a/src/render/src/pso/target.rs b/src/render/src/pso/target.rs index 1be4d3c2aae..0535ca316e5 100644 --- a/src/render/src/pso/target.rs +++ b/src/render/src/pso/target.rs @@ -145,7 +145,7 @@ impl<'a, T: format::DepthFormat> DataLink<'a> for DepthTarget { fn new() -> Self { DepthTarget(PhantomData) } fn is_active(&self) -> bool { true } fn link_depth_stencil(&mut self, init: &Self::Init) -> Option { - Some((T::get_format().0, (*init).into())) + Some((T::get_format(), (*init).into())) } } @@ -162,7 +162,7 @@ impl<'a, T: format::StencilFormat> DataLink<'a> for StencilTarget { fn new() -> Self { StencilTarget(PhantomData) } fn is_active(&self) -> bool { true } fn link_depth_stencil(&mut self, init: &Self::Init) -> Option { - Some((T::get_format().0, (*init).into())) + Some((T::get_format(), (*init).into())) } } @@ -180,7 +180,7 @@ impl<'a, T: format::DepthStencilFormat> DataLink<'a> for DepthStencilTarget { fn new() -> Self { DepthStencilTarget(PhantomData) } fn is_active(&self) -> bool { true } fn link_depth_stencil(&mut self, init: &Self::Init) -> Option { - Some((T::get_format().0, (*init).into())) + Some((T::get_format(), (*init).into())) } } diff --git a/src/shade.rs b/src/shade.rs index 30109616da7..124bd35f340 100644 --- a/src/shade.rs +++ b/src/shade.rs @@ -20,14 +20,16 @@ pub use gfx_device_dx11::ShaderModel as DxShaderModel; pub use gfx_device_metal::ShaderModel as MetalShaderModel; /// Shader backend with version numbers. -#[derive(Copy, Clone, PartialEq, Debug)] +#[derive(Copy, Clone, Debug, PartialEq)] pub enum Backend { Glsl(GlslVersion), GlslEs(GlslVersion), #[cfg(target_os = "windows")] Hlsl(DxShaderModel), #[cfg(target_os = "macos")] - Msl(MetalShaderModel) + Msl(MetalShaderModel), + #[cfg(feature = "vulkan")] + Vulkan, } pub const EMPTY: &'static [u8] = &[]; @@ -48,9 +50,13 @@ pub struct Source<'a> { pub hlsl_41 : &'a [u8], pub hlsl_50 : &'a [u8], pub msl_10 : &'a [u8], - pub msl_11 : &'a [u8] + pub msl_11 : &'a [u8], + pub vulkan : &'a [u8], } +#[derive(Clone, Copy, Debug, PartialEq)] +pub struct SelectError(Backend); + impl<'a> Source<'a> { /// Create an empty shader source. Useful for specifying the remaining /// structure members upon construction. @@ -69,12 +75,13 @@ impl<'a> Source<'a> { hlsl_41: EMPTY, hlsl_50: EMPTY, msl_10: EMPTY, - msl_11: EMPTY + msl_11: EMPTY, + vulkan: EMPTY, } } /// Pick one of the stored versions that is the highest supported by the backend. - pub fn select(&self, backend: Backend) -> Result<&'a [u8], ()> { + pub fn select(&self, backend: Backend) -> Result<&'a [u8], SelectError> { Ok(match backend { Backend::Glsl(version) => { let v = version.major * 100 + version.minor; @@ -84,7 +91,7 @@ impl<'a> Source<'a> { Source { glsl_140: s, .. } if s != EMPTY && v >= 140 => s, Source { glsl_130: s, .. } if s != EMPTY && v >= 130 => s, Source { glsl_120: s, .. } if s != EMPTY && v >= 120 => s, - _ => return Err(()) + _ => return Err(SelectError(backend)) } }, Backend::GlslEs(version) => { @@ -93,7 +100,7 @@ impl<'a> Source<'a> { Source { glsl_es_100: s, .. } if s != EMPTY && v >= 100 => s, Source { glsl_es_200: s, .. } if s != EMPTY && v >= 200 => s, Source { glsl_es_300: s, .. } if s != EMPTY && v >= 300 => s, - _ => return Err(()) + _ => return Err(SelectError(backend)) } }, #[cfg(target_os = "windows")] @@ -102,14 +109,19 @@ impl<'a> Source<'a> { Source { hlsl_41: s, .. } if s != EMPTY && model >= 41 => s, Source { hlsl_40: s, .. } if s != EMPTY && model >= 40 => s, Source { hlsl_30: s, .. } if s != EMPTY && model >= 30 => s, - _ => return Err(()) + _ => return Err(SelectError(backend)) }, #[cfg(target_os = "macos")] Backend::Msl(revision) => match *self { Source { msl_11: s, .. } if s != EMPTY && revision >= 11 => s, Source { msl_10: s, .. } if s != EMPTY && revision >= 10 => s, - _ => return Err(()) - } + _ => return Err(SelectError(backend)) + }, + #[cfg(feature = "vulkan")] + Backend::Vulkan => match *self { + Source { vulkan: s, .. } if s != EMPTY => s, + _ => return Err(SelectError(backend)) + }, }) } } diff --git a/src/window/dxgi/Cargo.toml b/src/window/dxgi/Cargo.toml index b557bfb9566..3736775e5b3 100644 --- a/src/window/dxgi/Cargo.toml +++ b/src/window/dxgi/Cargo.toml @@ -14,7 +14,7 @@ [package] name = "gfx_window_dxgi" -version = "0.3.0" +version = "0.4.0" description = "DXGI window for gfx-rs" homepage = "https://github.com/gfx-rs/gfx" repository = "https://github.com/gfx-rs/gfx" @@ -30,5 +30,5 @@ log = "0.3" kernel32-sys = "0.2" user32-sys = "0.1" winapi = "0.2" -gfx_core = { path = "../../core", version = "0.4" } -gfx_device_dx11 = { path = "../../backend/dx11", version = "0.3" } +gfx_core = { path = "../../core", version = "0.5" } +gfx_device_dx11 = { path = "../../backend/dx11", version = "0.4" } diff --git a/src/window/glfw/Cargo.toml b/src/window/glfw/Cargo.toml index 72e34c86c2e..3185851d27a 100644 --- a/src/window/glfw/Cargo.toml +++ b/src/window/glfw/Cargo.toml @@ -14,7 +14,7 @@ [package] name = "gfx_window_glfw" -version = "0.11.0" +version = "0.12.0" description = "GLFW window for gfx-rs" homepage = "https://github.com/gfx-rs/gfx" repository = "https://github.com/gfx-rs/gfx" @@ -27,5 +27,5 @@ name = "gfx_window_glfw" [dependencies] glfw = "0.5" -gfx_core = { path = "../../core", version = "0.4" } -gfx_device_gl = { path = "../../backend/gl", version = "0.11" } +gfx_core = { path = "../../core", version = "0.5" } +gfx_device_gl = { path = "../../backend/gl", version = "0.12" } diff --git a/src/window/glutin/Cargo.toml b/src/window/glutin/Cargo.toml index 70405e05722..27d7dc55ee6 100644 --- a/src/window/glutin/Cargo.toml +++ b/src/window/glutin/Cargo.toml @@ -14,7 +14,7 @@ [package] name = "gfx_window_glutin" -version = "0.12.0" +version = "0.13.0" description = "Glutin window for gfx-rs" homepage = "https://github.com/gfx-rs/gfx" repository = "https://github.com/gfx-rs/gfx" @@ -27,5 +27,5 @@ name = "gfx_window_glutin" [dependencies] glutin = "0.6" -gfx_core = { path = "../../core", version = "0.4" } -gfx_device_gl = { path = "../../backend/gl", version = "0.11" } +gfx_core = { path = "../../core", version = "0.5" } +gfx_device_gl = { path = "../../backend/gl", version = "0.12" } diff --git a/src/window/metal/Cargo.toml b/src/window/metal/Cargo.toml index ca1c80c7192..58b0deb5c7b 100644 --- a/src/window/metal/Cargo.toml +++ b/src/window/metal/Cargo.toml @@ -31,5 +31,5 @@ cocoa = "0.2.4" objc = "0.1.8" winit = "0.5.1" metal = { git = "https://github.com/fkaa/metal-rs" } -gfx_core = { path = "../../core", version = "0.4" } +gfx_core = { path = "../../core", version = "0.5" } gfx_device_metal = { path = "../../backend/metal", version = "0.1" } diff --git a/src/window/sdl/Cargo.toml b/src/window/sdl/Cargo.toml index 5fba92fa58b..265a5add087 100644 --- a/src/window/sdl/Cargo.toml +++ b/src/window/sdl/Cargo.toml @@ -14,7 +14,7 @@ [package] name = "gfx_window_sdl" -version = "0.3.0" +version = "0.4.0" description = "SDL2 window for gfx-rs" homepage = "https://github.com/gfx-rs/gfx" repository = "https://github.com/gfx-rs/gfx" @@ -27,5 +27,5 @@ name = "gfx_window_sdl" [dependencies] sdl2 = "0.18" -gfx_core = { path = "../../core", version = "0.4" } -gfx_device_gl = { path = "../../backend/gl", version = "0.11" } +gfx_core = { path = "../../core", version = "0.5" } +gfx_device_gl = { path = "../../backend/gl", version = "0.12" } diff --git a/src/window/vulkan/Cargo.toml b/src/window/vulkan/Cargo.toml new file mode 100644 index 00000000000..e1e02bbf3e8 --- /dev/null +++ b/src/window/vulkan/Cargo.toml @@ -0,0 +1,19 @@ +[package] +name = "gfx_window_vulkan" +version = "0.1.0" +description = "Vulkan window for gfx-rs" +homepage = "https://github.com/gfx-rs/gfx" +repository = "https://github.com/gfx-rs/gfx" +keywords = ["graphics", "gamedev"] +license = "Apache-2.0" +authors = ["The Gfx-rs Developers"] + +[lib] +name = "gfx_window_vulkan" + +[dependencies] +winit = "0.5" +xcb = "0.7" +vk-sys = { git = "https://github.com/sectopod/vulkano", branch = "bind" } +gfx_core = { path = "../../core", version = "0.5" } +gfx_device_vulkan = { path = "../../backend/vulkan", version = "0.1" } diff --git a/src/window/vulkan/src/lib.rs b/src/window/vulkan/src/lib.rs new file mode 100644 index 00000000000..4f242638124 --- /dev/null +++ b/src/window/vulkan/src/lib.rs @@ -0,0 +1,297 @@ +// Copyright 2016 The Gfx-rs Developers. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +extern crate winit; +extern crate xcb; +extern crate vk_sys as vk; +extern crate gfx_core; +extern crate gfx_device_vulkan; + +use std::ffi::CStr; +use std::ptr; +use std::os::raw; +use gfx_core::format; + + +pub fn init_winit(builder: winit::WindowBuilder) -> (winit::Window, gfx_device_vulkan::GraphicsQueue, gfx_device_vulkan::Factory) { + let (device, factory, _backend) = gfx_device_vulkan::create(&builder.window.title, 1, &[], + &["VK_KHR_surface", "VK_KHR_xcb_surface"], &["VK_KHR_swapchain"]); + let win = builder.build().unwrap(); + (win, device, factory) +} + +pub type TargetHandle = gfx_core::handle::RenderTargetView; + +pub struct SwapTarget { + _image: vk::Image, + target: TargetHandle, + _fence: vk::Fence, +} + +pub struct Window { + connection: xcb::Connection, + _foreground: u32, + window: u32, + _debug_callback: Option, + swapchain: vk::SwapchainKHR, + targets: Vec>, + queue: gfx_device_vulkan::GraphicsQueue, +} + +pub struct Frame<'a, T: 'a> { + window: &'a mut Window, + target_id: u32, +} + +impl<'a, T: Clone> Frame<'a, T> { + pub fn get_target(&self) -> TargetHandle { + self.window.targets[self.target_id as usize].target.clone() + } + pub fn get_queue(&mut self) -> &mut gfx_device_vulkan::GraphicsQueue { + &mut self.window.queue + } +} + +impl<'a, T> Drop for Frame<'a, T> { + fn drop(&mut self) { + let mut result = vk::SUCCESS; + let info = vk::PresentInfoKHR { + sType: vk::STRUCTURE_TYPE_PRESENT_INFO_KHR, + pNext: ptr::null(), + waitSemaphoreCount: 0, + pWaitSemaphores: ptr::null(), + swapchainCount: 1, + pSwapchains: &self.window.swapchain, + pImageIndices: &self.target_id, + pResults: &mut result, + }; + let (_dev, vk) = self.window.queue.get_share().get_device(); + unsafe { + vk.QueuePresentKHR(self.window.queue.get_queue(), &info); + } + assert_eq!(vk::SUCCESS, result); + } +} + +impl Window { + pub fn wait_draw(&mut self) -> Result>, ()> { + let ev = match self.connection.wait_for_event() { + Some(ev) => ev, + None => return Err(()), + }; + //self.connection.flush(); + match ev.response_type() & 0x7F { + xcb::EXPOSE => Ok(Some(self.start_frame())), + xcb::KEY_PRESS => Err(()), + _ => Ok(None) + } + } + + pub fn start_frame(&mut self) -> Frame { + //TODO: handle window resize + let index = unsafe { + let (dev, vk) = self.queue.get_share().get_device(); + let mut i = 0; + assert_eq!(vk::SUCCESS, vk.AcquireNextImageKHR(dev, self.swapchain, 60, 0, 0, &mut i)); + i + }; + Frame { + window: self, + target_id: index, + } + } + + pub fn get_any_target(&self) -> TargetHandle { + self.targets[0].target.clone() + } +} + +impl Drop for Window { + fn drop(&mut self) { + xcb::unmap_window(&self.connection, self.window); + xcb::destroy_window(&self.connection, self.window); + self.connection.flush(); + } +} + +const LAYERS: &'static [&'static str] = &[ +]; +const LAYERS_DEBUG: &'static [&'static str] = &[ + "VK_LAYER_LUNARG_standard_validation", +]; +const EXTENSIONS: &'static [&'static str] = &[ + "VK_KHR_surface", + "VK_KHR_xcb_surface", +]; +const EXTENSIONS_DEBUG: &'static [&'static str] = &[ + "VK_KHR_surface", + "VK_KHR_xcb_surface", + "VK_EXT_debug_report", +]; +const DEV_EXTENSIONS: &'static [&'static str] = &[ + "VK_KHR_swapchain", +]; + +extern "system" fn callback(flags: vk::DebugReportFlagsEXT, + _ob_type: vk::DebugReportObjectTypeEXT, _object: u64, _location: usize, + _msg_code: i32, layer_prefix_c: *const raw::c_char, + description_c: *const raw::c_char, _user_data: *mut raw::c_void) -> u32 +{ + let layer_prefix = unsafe { CStr::from_ptr(layer_prefix_c) }.to_str().unwrap(); + let description = unsafe { CStr::from_ptr(description_c) }.to_str().unwrap(); + println!("Vk flags {:x} in layer {}: {}", flags, layer_prefix, description); + vk::FALSE +} + +pub fn init_xcb(title: &str, width: u32, height: u32) + -> (Window, gfx_device_vulkan::Factory) { + let debug = false; + let (mut device, mut factory, backend) = gfx_device_vulkan::create(title, 1, + if debug {LAYERS_DEBUG} else {LAYERS}, + if debug {EXTENSIONS_DEBUG} else {EXTENSIONS}, + DEV_EXTENSIONS); + + let debug_callback = if debug { + let info = vk::DebugReportCallbackCreateInfoEXT { + sType: vk::STRUCTURE_TYPE_DEBUG_REPORT_CREATE_INFO_EXT, + pNext: ptr::null(), + flags: vk::DEBUG_REPORT_INFORMATION_BIT_EXT | vk::DEBUG_REPORT_WARNING_BIT_EXT | + vk::DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT | vk::DEBUG_REPORT_ERROR_BIT_EXT | + vk::DEBUG_REPORT_DEBUG_BIT_EXT, + pfnCallback: callback, + pUserData: ptr::null_mut(), + }; + let (inst, vk) = backend.get_instance(); + let mut out = 0; + assert_eq!(vk::SUCCESS, unsafe { + vk.CreateDebugReportCallbackEXT(inst, &info, ptr::null(), &mut out) + }); + Some(out) + }else { + None + }; + + let (conn, screen_num) = xcb::Connection::connect(None).unwrap(); + let (window, foreground) = { + let setup = conn.get_setup(); + let screen = setup.roots().nth(screen_num as usize).unwrap(); + + let foreground = conn.generate_id(); + xcb::create_gc(&conn, foreground, screen.root(), &[ + (xcb::GC_FOREGROUND, screen.black_pixel()), + (xcb::GC_GRAPHICS_EXPOSURES, 0), + ]); + + let win = conn.generate_id(); + xcb::create_window(&conn, + xcb::COPY_FROM_PARENT as u8, + win, + screen.root(), + 0, 0, + width as u16, height as u16, + 10, + xcb::WINDOW_CLASS_INPUT_OUTPUT as u16, + screen.root_visual(), &[ + (xcb::CW_BACK_PIXEL, screen.black_pixel()), + (xcb::CW_EVENT_MASK, xcb::EVENT_MASK_KEY_PRESS | xcb::EVENT_MASK_EXPOSURE), + ] + ); + (win, foreground) + }; + + xcb::map_window(&conn, window); + xcb::change_property(&conn, xcb::PROP_MODE_REPLACE as u8, window, + xcb::ATOM_WM_NAME, xcb::ATOM_STRING, 8, title.as_bytes()); + conn.flush(); + + let surface = { + let (inst, vk) = backend.get_instance(); + let info = vk::XcbSurfaceCreateInfoKHR { + sType: vk::STRUCTURE_TYPE_XCB_SURFACE_CREATE_INFO_KHR, + pNext: ptr::null(), + flags: 0, + connection: conn.get_raw_conn() as *const _, + window: window as *const _, //HACK! TODO: fix the bindings + }; + let mut out = 0; + assert_eq!(vk::SUCCESS, unsafe { + vk.CreateXcbSurfaceKHR(inst, &info, ptr::null(), &mut out) + }); + out + }; + + let (dev, vk) = backend.get_device(); + let mut images: [vk::Image; 2] = [0; 2]; + let mut num = images.len() as u32; + let format = ::get_format(); + + let swapchain_info = vk::SwapchainCreateInfoKHR { + sType: vk::STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR, + pNext: ptr::null(), + flags: 0, + surface: surface, + minImageCount: num, + imageFormat: gfx_device_vulkan::data::map_format(format.0, format.1).unwrap(), + imageColorSpace: vk::COLOR_SPACE_SRGB_NONLINEAR_KHR, + imageExtent: vk::Extent2D { width: width, height: height }, + imageArrayLayers: 1, + imageUsage: vk::IMAGE_USAGE_COLOR_ATTACHMENT_BIT | vk::IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT, + imageSharingMode: vk::SHARING_MODE_EXCLUSIVE, + queueFamilyIndexCount: 1, + pQueueFamilyIndices: &0, + preTransform: vk::SURFACE_TRANSFORM_IDENTITY_BIT_KHR, + compositeAlpha: vk::COMPOSITE_ALPHA_OPAQUE_BIT_KHR, + presentMode: vk::PRESENT_MODE_FIFO_RELAXED_KHR, + clipped: vk::TRUE, + oldSwapchain: 0, + }; + + let mut swapchain = 0; + assert_eq!(vk::SUCCESS, unsafe { + vk.CreateSwapchainKHR(dev, &swapchain_info, ptr::null(), &mut swapchain) + }); + + assert_eq!(vk::SUCCESS, unsafe { + vk.GetSwapchainImagesKHR(dev, swapchain, &mut num, images.as_mut_ptr()) + }); + + let mut cbuf = factory.create_command_buffer(); + + let targets = images[.. num as usize].iter().map(|image| { + use gfx_core::factory::Typed; + cbuf.image_barrier(*image, vk::IMAGE_ASPECT_COLOR_BIT, vk::IMAGE_LAYOUT_UNDEFINED, vk::IMAGE_LAYOUT_PRESENT_SRC_KHR); + let raw_view = factory.view_swapchain_image(*image, format, (width, height)).unwrap(); + SwapTarget { + _image: *image, + target: Typed::new(raw_view), + _fence: factory.create_fence(true), + } + }).collect(); + + { + use gfx_core::Device; + device.submit(&mut cbuf); + } + + let win = Window { + connection: conn, + _foreground: foreground, + window: window, + _debug_callback: debug_callback, + swapchain: swapchain, + targets: targets, + queue: device, + }; + (win, factory) +} diff --git a/tests/macros.rs b/tests/macros.rs index 7e4a8b2c125..eabae307350 100644 --- a/tests/macros.rs +++ b/tests/macros.rs @@ -60,10 +60,9 @@ fn _test_raw(factory: &mut F) -> gfx::PipelineState wher let special = gfx::pso::buffer::Element { format: fm::Format(fm::SurfaceType::R32, fm::ChannelType::Float), offset: 0, - stride: 12, }; let init = testraw::Init { - vertex: &[("a_Special", special, 0)], + vertex: (&[("a_Special", special)], 12, 0), tex: "Specular", target: ("o_Color2", fm::Format(fm::SurfaceType::R8_G8_B8_A8, fm::ChannelType::Unorm),