Initialization, almost working swapchain

master
itycodes 2 weeks ago
parent 45ebc4a807
commit 380476549c

1
.gitignore vendored

@ -0,0 +1 @@
/target

335
Cargo.lock generated

@ -0,0 +1,335 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 4
[[package]]
name = "ash"
version = "0.38.0+1.3.281"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0bb44936d800fea8f016d7f2311c6a4f97aebd5dc86f09906139ec848cf3a46f"
dependencies = [
"libloading",
]
[[package]]
name = "ash-window"
version = "0.13.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "52bca67b61cb81e5553babde81b8211f713cb6db79766f80168f3e5f40ea6c82"
dependencies = [
"ash",
"raw-window-handle",
"raw-window-metal",
]
[[package]]
name = "bitflags"
version = "1.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
[[package]]
name = "block"
version = "0.1.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0d8c1fef690941d3e7788d328517591fecc684c084084702d6ff1641e993699a"
[[package]]
name = "cfg-if"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]]
name = "cocoa"
version = "0.25.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f6140449f97a6e97f9511815c5632d84c8aacf8ac271ad77c559218161a1373c"
dependencies = [
"bitflags",
"block",
"cocoa-foundation",
"core-foundation",
"core-graphics",
"foreign-types",
"libc",
"objc",
]
[[package]]
name = "cocoa-foundation"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8c6234cbb2e4c785b456c0644748b1ac416dd045799740356f8363dfe00c93f7"
dependencies = [
"bitflags",
"block",
"core-foundation",
"core-graphics-types",
"libc",
"objc",
]
[[package]]
name = "core-foundation"
version = "0.9.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f"
dependencies = [
"core-foundation-sys",
"libc",
]
[[package]]
name = "core-foundation-sys"
version = "0.8.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b"
[[package]]
name = "core-graphics"
version = "0.23.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c07782be35f9e1140080c6b96f0d44b739e2278479f64e02fdab4e32dfd8b081"
dependencies = [
"bitflags",
"core-foundation",
"core-graphics-types",
"foreign-types",
"libc",
]
[[package]]
name = "core-graphics-types"
version = "0.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "45390e6114f68f718cc7a830514a96f903cccd70d02a8f6d9f643ac4ba45afaf"
dependencies = [
"bitflags",
"core-foundation",
"libc",
]
[[package]]
name = "foreign-types"
version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d737d9aa519fb7b749cbc3b962edcf310a8dd1f4b67c91c4f83975dbdd17d965"
dependencies = [
"foreign-types-macros",
"foreign-types-shared",
]
[[package]]
name = "foreign-types-macros"
version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1a5c6c585bc94aaf2c7b51dd4c2ba22680844aba4c687be581871a6f518c5742"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "foreign-types-shared"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "aa9a19cbb55df58761df49b23516a86d432839add4af60fc256da840f66ed35b"
[[package]]
name = "lazy_static"
version = "1.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe"
[[package]]
name = "libc"
version = "0.2.171"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c19937216e9d3aa9956d9bb8dfc0b0c8beb6058fc4f7a4dc4d850edf86a237d6"
[[package]]
name = "libloading"
version = "0.8.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fc2f4eb4bc735547cfed7c0a4922cbd04a4655978c09b54f1f7b228750664c34"
dependencies = [
"cfg-if",
"windows-targets",
]
[[package]]
name = "malloc_buf"
version = "0.0.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "62bb907fe88d54d8d9ce32a3cceab4218ed2f6b7d35617cafe9adf84e43919cb"
dependencies = [
"libc",
]
[[package]]
name = "mineclone"
version = "0.1.0"
dependencies = [
"ash",
"ash-window",
"raw-window-handle",
"sdl2",
]
[[package]]
name = "objc"
version = "0.2.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "915b1b472bc21c53464d6c8461c9d3af805ba1ef837e1cac254428f4a77177b1"
dependencies = [
"malloc_buf",
]
[[package]]
name = "proc-macro2"
version = "1.0.94"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a31971752e70b8b2686d7e46ec17fb38dad4051d94024c88df49b667caea9c84"
dependencies = [
"unicode-ident",
]
[[package]]
name = "quote"
version = "1.0.40"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d"
dependencies = [
"proc-macro2",
]
[[package]]
name = "raw-window-handle"
version = "0.6.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "20675572f6f24e9e76ef639bc5552774ed45f1c30e2951e1e99c59888861c539"
[[package]]
name = "raw-window-metal"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "76e8caa82e31bb98fee12fa8f051c94a6aa36b07cddb03f0d4fc558988360ff1"
dependencies = [
"cocoa",
"core-graphics",
"objc",
"raw-window-handle",
]
[[package]]
name = "sdl2"
version = "0.37.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3b498da7d14d1ad6c839729bd4ad6fc11d90a57583605f3b4df2cd709a9cd380"
dependencies = [
"bitflags",
"lazy_static",
"libc",
"raw-window-handle",
"sdl2-sys",
]
[[package]]
name = "sdl2-sys"
version = "0.37.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "951deab27af08ed9c6068b7b0d05a93c91f0a8eb16b6b816a5e73452a43521d3"
dependencies = [
"cfg-if",
"libc",
"version-compare",
]
[[package]]
name = "syn"
version = "2.0.100"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b09a44accad81e1ba1cd74a32461ba89dee89095ba17b32f5d03683b1b1fc2a0"
dependencies = [
"proc-macro2",
"quote",
"unicode-ident",
]
[[package]]
name = "unicode-ident"
version = "1.0.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512"
[[package]]
name = "version-compare"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "579a42fc0b8e0c63b76519a339be31bed574929511fa53c1a3acae26eb258f29"
[[package]]
name = "windows-targets"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973"
dependencies = [
"windows_aarch64_gnullvm",
"windows_aarch64_msvc",
"windows_i686_gnu",
"windows_i686_gnullvm",
"windows_i686_msvc",
"windows_x86_64_gnu",
"windows_x86_64_gnullvm",
"windows_x86_64_msvc",
]
[[package]]
name = "windows_aarch64_gnullvm"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3"
[[package]]
name = "windows_aarch64_msvc"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469"
[[package]]
name = "windows_i686_gnu"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b"
[[package]]
name = "windows_i686_gnullvm"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66"
[[package]]
name = "windows_i686_msvc"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66"
[[package]]
name = "windows_x86_64_gnu"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78"
[[package]]
name = "windows_x86_64_gnullvm"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d"
[[package]]
name = "windows_x86_64_msvc"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"

@ -4,3 +4,7 @@ version = "0.1.0"
edition = "2024"
[dependencies]
ash = { version = "0.38.0", features = ["linked"] }
ash-window = "0.13.0"
raw-window-handle = "0.6.2"
sdl2 = { version = "0.37.0", features = ["raw-window-handle"] }

@ -0,0 +1,18 @@
BIN = target/debug/mineclone
SHADERS = shaders/vert.spv shaders/frag.spv
SOURCES = $(shell find src -name '*.rs')
all: $(SHADERS) $(BIN)
run: all
cargo run
$(BIN): $(SOURCES)
cargo build
%.spv: %.vert
glslc $< -o $@
%.spv: %.frag
glslc $< -o $@

@ -0,0 +1,19 @@
#version 450
layout(location = 0) out vec4 outColor;
layout(location = 0) in vec4 normal;
layout(location = 1) in vec4 pos_pre;
layout(push_constant, std430) uniform pc {
layout(offset=32) vec4 data;
};
void main() {
outColor = vec4(data.rgb*(1.0+dot(normal.xyz, normalize(vec3(-0.7, -0.5, -0.1))))/2.0, 1.0);
//if(pos_post.z <= 0.0) {
// outColor = vec4(1.0);
//}
//outColor = normal.xyz;
//outColor = vec4(vec3(1.0-gl_FragCoord.z), 1.0);
}

Binary file not shown.

Binary file not shown.

@ -0,0 +1,109 @@
#version 450
// vim: ft=c
layout(std430, set = 0, binding = 0) buffer positions_buffer {
mat2x4 posnrm[];
} pos;
layout(push_constant, std430) uniform pc {
layout(offset=0) vec4 cam_orig;
layout(offset=16) vec4 cam_rot;
};
layout (location = 0) out vec4 normal;
layout (location = 1) out vec4 pos_pre;
const float PI = 3.14159;
// Forgive me for I have sinned
const float TAU = PI*2.0;
void main() {
// assign outs
normal = pos.posnrm[gl_VertexIndex][1];
pos_pre = pos.posnrm[gl_VertexIndex][0];
// define constants
const float zFar = 100.0;
const float zNear = 0.1;
// assign the transformee
gl_Position = pos.posnrm[gl_VertexIndex][0];
mat4 view_orig = mat4(
1.0, 0.0, 0.0, cam_orig.x,
0.0, 1.0, 0.0, cam_orig.y,
0.0, 0.0, 1.0, cam_orig.z,
0.0, 0.0, 0.0, 1.0
);
mat4 view_rot_xz = mat4(
cos(cam_rot.y), 0.0, sin(cam_rot.y), 0.0,
0.0, 1.0, 0.0, 0.0,
-sin(cam_rot.y), 0.0, cos(cam_rot.y), 0.0,
0.0, 0.0, 0.0, 1.0
);
mat4 view_rot_yz = mat4(
1.0, 0.0, 0.0, 0.0,
0.0, cos(cam_rot.x), sin(cam_rot.x), 0.0,
0.0, -sin(cam_rot.x), cos(cam_rot.x), 0.0,
0.0, 0.0, 0.0, 1.0
);
mat4 project_aspect = mat4(
(1080.0/1920.0), 0.0, 0.0, 0.0,
0.0, 1.0, 0.0, 0.0,
0.0, 0.0, 1.0, 0.0,
0.0, 0.0, 0.0, 1.0
);
mat4 project_znear = mat4(
1.0, 0.0, 0.0, 0.0,
0.0, 1.0, 0.0, 0.0,
0.0, 0.0, 1.0, -zNear,
0.0, 0.0, 0.0, 1.0
);
mat4 project_div = mat4(
1.0, 0.0, 0.0, 0.0,
0.0, 1.0, 0.0, 0.0,
0.0, 0.0, 1.0, 0.0,
0.0, 0.0, tan((70.0/2.0)/360.0*TAU), 0.0
);
mat4 project_normal = mat4(
1.0, 0.0, 0.0, 0.0,
0.0, 1.0, 0.0, 0.0,
0.0, 0.0, 1.0/zFar, 0.0,
0.0, 0.0, 0.0, 1.0
);
// apply view's origin transformation
//gl_Position.xyz += cam_orig.xyz;
gl_Position *= view_orig;
// apply view's xz rotation
//mat2 xz_rot;
//xz_rot[0] = vec2(cos(cam_rot.y), -sin(cam_rot.y));
//xz_rot[1] = vec2(sin(cam_rot.y), cos(cam_rot.y));
//gl_Position.xz *= inverse(xz_rot);
gl_Position *= view_rot_xz;
// apply view's yz rotation
//mat2 yz_rot;
//yz_rot[0] = vec2(cos(cam_rot.x), -sin(cam_rot.x));
//yz_rot[1] = vec2(sin(cam_rot.x), cos(cam_rot.x));
//gl_Position.yz *= inverse(yz_rot);
gl_Position *= view_rot_yz;
// aspect correction
//gl_Position.x *= (1080.0/1920.0);
gl_Position *= project_aspect;
// z near correction
//gl_Position.z -= zNear;
gl_Position *= project_znear;
// division by z
// has to be assigned by w so that the hardware performs the division AFTER clipping.
//gl_Position.w = (gl_Position.z*sin(140.0/360.0*TAU));
gl_Position *= project_div;
// z normalization
//gl_Position.z /= zFar;
gl_Position *= project_normal;
}

@ -1,3 +1,747 @@
#![feature(inherent_str_constructors)]
#![allow(unused_variables, unused_mut)]
use ash::Device;
use ash::Entry;
use ash::Instance;
use ash::khr::{surface, swapchain};
use ash::vk;
use std::ffi::CStr;
use std::ffi::CString;
use raw_window_handle::HasDisplayHandle;
use raw_window_handle::HasWindowHandle;
use sdl2::video::Window;
const APP_NAME: &str = "MineClone";
const MESH_SIZE: u64 = 36 * 2 * 4 * 4;
const POSITIONS: [f32; 36 * 2 * 4] = [
// BOTTOM
-0.5, 0.5, 1.0, 1.0, 0.0, 1.0, 0.0, 0.0, 0.5, 0.5, 2.0, 1.0, 0.0, 1.0, 0.0, 0.0, -0.5, 0.5, 2.0,
1.0, 0.0, 1.0, 0.0, 0.0, 0.5, 0.5, 1.0, 1.0, 0.0, 1.0, 0.0, 0.0, 0.5, 0.5, 2.0, 1.0, 0.0, 1.0,
0.0, 0.0, -0.5, 0.5, 1.0, 1.0, 0.0, 1.0, 0.0, 0.0, // TOP
0.5, -0.5, 2.0, 1.0, 0.0, -1.0, 0.0, 0.0, -0.5, -0.5, 1.0, 1.0, 0.0, -1.0, 0.0, 0.0, -0.5,
-0.5, 2.0, 1.0, 0.0, -1.0, 0.0, 0.0, 0.5, -0.5, 2.0, 1.0, 0.0, -1.0, 0.0, 0.0, 0.5, -0.5, 1.0,
1.0, 0.0, -1.0, 0.0, 0.0, -0.5, -0.5, 1.0, 1.0, 0.0, -1.0, 0.0, 0.0, // FRONT
-0.5, -0.5, 1.0, 1.0, 0.0, 0.0, -1.0, 0.0, 0.5, 0.5, 1.0, 1.0, 0.0, 0.0, -1.0, 0.0, -0.5, 0.5,
1.0, 1.0, 0.0, 0.0, -1.0, 0.0, 0.5, -0.5, 1.0, 1.0, 0.0, 0.0, -1.0, 0.0, 0.5, 0.5, 1.0, 1.0,
0.0, 0.0, -1.0, 0.0, -0.5, -0.5, 1.0, 1.0, 0.0, 0.0, -1.0, 0.0, // BACK
0.5, 0.5, 2.0, 1.0, 0.0, 0.0, 1.0, 0.0, -0.5, -0.5, 2.0, 1.0, 0.0, 0.0, 1.0, 0.0, -0.5, 0.5,
2.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.5, 0.5, 2.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.5, -0.5, 2.0, 1.0, 0.0,
0.0, 1.0, 0.0, -0.5, -0.5, 2.0, 1.0, 0.0, 0.0, 1.0, 0.0, // LEFT
-0.5, -0.5, 1.0, 1.0, -1.0, 0.0, 0.0, 0.0, -0.5, 0.5, 2.0, 1.0, -1.0, 0.0, 0.0, 0.0, -0.5,
-0.5, 2.0, 1.0, -1.0, 0.0, 0.0, 0.0, -0.5, 0.5, 1.0, 1.0, -1.0, 0.0, 0.0, 0.0, -0.5, 0.5, 2.0,
1.0, -1.0, 0.0, 0.0, 0.0, -0.5, -0.5, 1.0, 1.0, -1.0, 0.0, 0.0, 0.0, // RIGHT
0.5, 0.5, 2.0, 1.0, 1.0, 0.0, 0.0, 0.0, 0.5, -0.5, 1.0, 1.0, 1.0, 0.0, 0.0, 0.0, 0.5, -0.5,
2.0, 1.0, 1.0, 0.0, 0.0, 0.0, 0.5, 0.5, 2.0, 1.0, 1.0, 0.0, 0.0, 0.0, 0.5, 0.5, 1.0, 1.0, 1.0,
0.0, 0.0, 0.0, 0.5, -0.5, 1.0, 1.0, 1.0, 0.0, 0.0, 0.0,
];
fn create_instance(window: &Window, entry: &Entry) -> Instance {
unsafe {
let n_app_name = CString::new(APP_NAME).unwrap();
let n_engine_name = CString::new(format!("{} Engine", APP_NAME)).unwrap();
let appinfo = vk::ApplicationInfo::default()
.application_name(n_app_name.as_c_str())
.application_version(0)
.engine_name(n_engine_name.as_c_str())
.engine_version(0)
.api_version(vk::make_api_version(0, 1, 3, 0));
let default_exts = window
.vulkan_instance_extensions()
.expect("Failed to get list of required extensions from SDL2");
let mut exts = vec![];
exts.extend(default_exts);
let exts: Vec<*const i8> = exts
.iter()
.map(|s| s.as_ptr() as *const i8)
.collect::<Vec<_>>();
let exts: &[*const i8] = exts.as_slice();
let insinfo = vk::InstanceCreateInfo::default()
.application_info(&appinfo)
.enabled_extension_names(exts);
let instance = entry
.create_instance(&insinfo, None)
.expect("Failed to create instance");
println!("Created instance");
instance
}
}
fn find_pdev_dgpu(instance: &Instance) -> vk::PhysicalDevice {
unsafe {
let mut pdevs = instance
.enumerate_physical_devices()
.expect("Failed to enumerate devices");
for (i, d) in pdevs.iter().enumerate() {
let props = instance.get_physical_device_properties(*d);
if props.device_type == vk::PhysicalDeviceType::DISCRETE_GPU {
// TODO this assumes that the first discrete GPU will have an RCS queue family
// This is not guaranteed by the spec (example, a compute-only GPU)
// Fix.
println!(
"Found discrete GPU: {}",
str::from_utf8(std::mem::transmute(props.device_name.as_slice())).unwrap()
);
return pdevs.remove(i);
}
}
println!("No discrete GPU found");
assert!(pdevs.len() > 0, "No GPU found");
return pdevs.remove(0);
}
}
fn make_surface(entry: &Entry, instance: &Instance, window: &Window) -> vk::SurfaceKHR {
unsafe {
let surface = ash_window::create_surface(
&entry,
&instance,
(&window).display_handle().unwrap().as_raw(),
(&window).window_handle().unwrap().as_raw(),
None,
)
.expect("Failed to create surface");
println!("Created surface");
surface
}
}
// Using Intel GPU hardware terminology 🥴
fn find_rcs_queue_inx(instance: &Instance, pdev: &vk::PhysicalDevice) -> Option<u32> {
unsafe {
let qfams = instance.get_physical_device_queue_family_properties(*pdev);
for (inx, qfam) in qfams.iter().enumerate() {
if qfam
.queue_flags
.contains(vk::QueueFlags::GRAPHICS | vk::QueueFlags::COMPUTE)
{
println!("Found RCS queue at index {}", inx);
return Some(inx as u32);
}
}
println!("No RCS queue found");
return None;
}
}
fn make_dev(
instance: &Instance,
pdev: &vk::PhysicalDevice,
rcs_queue_inx: u32,
exts: Vec<&CStr>,
) -> Device {
unsafe {
let dev_queue = vec![
vk::DeviceQueueCreateInfo::default()
.queue_family_index(rcs_queue_inx)
.queue_priorities(&[1.0]),
];
let exts = exts.iter().map(|&s| s.as_ptr()).collect::<Vec<_>>();
let exts = exts.as_slice();
// Enable all features
let features = instance.get_physical_device_features(*pdev);
let dev_info = vk::DeviceCreateInfo::default()
.queue_create_infos(&dev_queue)
.enabled_extension_names(exts)
.enabled_features(&features);
let dev = instance
.create_device(*pdev, &dev_info, None)
.expect("Failed to create device");
println!("Created device");
dev
}
}
fn make_command_pool(dev: &Device, rcs_queue_inx: u32) -> vk::CommandPool {
unsafe {
let pool_info = vk::CommandPoolCreateInfo::default()
.queue_family_index(rcs_queue_inx)
.flags(vk::CommandPoolCreateFlags::RESET_COMMAND_BUFFER);
let pool = dev
.create_command_pool(&pool_info, None)
.expect("Failed to create command pool");
println!("Created command pool");
pool
}
}
fn alloc_cmd_buf(dev: &Device, pool: vk::CommandPool) -> vk::CommandBuffer {
unsafe {
let alloc_info = vk::CommandBufferAllocateInfo::default()
.command_pool(pool)
.level(vk::CommandBufferLevel::PRIMARY)
.command_buffer_count(1);
let cmd_buf = dev
.allocate_command_buffers(&alloc_info)
.expect("Failed to allocate command buffer")
.remove(0);
println!("Allocated command buffer");
cmd_buf
}
}
fn find_host_visible(instance: &Instance, pdev: &vk::PhysicalDevice) -> Option<u32> {
unsafe {
let mem_props = instance.get_physical_device_memory_properties(*pdev);
for (i, mem_type) in mem_props.memory_types.iter().enumerate() {
if mem_type.property_flags.contains(
vk::MemoryPropertyFlags::DEVICE_LOCAL
| vk::MemoryPropertyFlags::HOST_VISIBLE
| vk::MemoryPropertyFlags::HOST_COHERENT,
) {
println!("Found host visible memory at index {}", i);
return Some(i as u32);
}
}
println!("No host visible memory found");
return None;
}
}
fn find_host_invisible(instance: &Instance, pdev: &vk::PhysicalDevice) -> Option<u32> {
unsafe {
let mem_props = instance.get_physical_device_memory_properties(*pdev);
for (i, mem_type) in mem_props.memory_types.iter().enumerate() {
if mem_type
.property_flags
.contains(vk::MemoryPropertyFlags::DEVICE_LOCAL)
&& !mem_type.property_flags.contains(
vk::MemoryPropertyFlags::HOST_VISIBLE | vk::MemoryPropertyFlags::HOST_COHERENT,
)
{
println!("Found host invisible memory at index {}", i);
return Some(i as u32);
}
}
println!("No host invisible memory found");
return None;
}
}
fn mem_alloc(dev: &Device, mem_type_inx: u32, size: u64) -> vk::DeviceMemory {
unsafe {
let mem_info = vk::MemoryAllocateInfo::default()
.allocation_size(size)
.memory_type_index(mem_type_inx);
let mem = dev
.allocate_memory(&mem_info, None)
.expect("Failed to allocate memory");
println!("Allocated memory");
mem
}
}
fn make_depth_img(
dev: &Device,
host_invisible_inx: u32,
width: u32,
height: u32,
mem: vk::DeviceMemory,
qfam: u32,
) -> vk::Image {
unsafe {
let queue_fams = [qfam];
let img_info = vk::ImageCreateInfo::default()
.flags(vk::ImageCreateFlags::empty())
.image_type(vk::ImageType::TYPE_2D)
.format(vk::Format::D32_SFLOAT)
.extent(vk::Extent3D {
width,
height,
depth: 1,
})
.mip_levels(1)
.array_layers(1)
.samples(vk::SampleCountFlags::TYPE_1)
.tiling(vk::ImageTiling::OPTIMAL)
.usage(vk::ImageUsageFlags::DEPTH_STENCIL_ATTACHMENT)
.sharing_mode(vk::SharingMode::EXCLUSIVE)
.queue_family_indices(&queue_fams)
.initial_layout(vk::ImageLayout::UNDEFINED);
let img = dev
.create_image(&img_info, None)
.expect("Failed to create image");
println!("Created image");
dev.bind_image_memory(img, mem, 0)
.expect("Failed to bind image memory");
img
}
}
fn alloc_buf(
dev: &Device,
mem: &vk::DeviceMemory,
size: u64,
usage: vk::BufferUsageFlags,
) -> vk::Buffer {
unsafe {
let buf_info = vk::BufferCreateInfo::default()
.size(size)
.usage(usage)
.sharing_mode(vk::SharingMode::EXCLUSIVE);
let buf = dev
.create_buffer(&buf_info, None)
.expect("Failed to create buffer");
dev.bind_buffer_memory(buf, *mem, 0)
.expect("Failed to bind buffer memory");
println!("Created buffer");
buf
}
}
fn buf_to_ptr(dev: &Device, mem: &vk::DeviceMemory, buf: &vk::Buffer) -> *mut std::ffi::c_void {
unsafe {
let ptr = dev
.map_memory(*mem, 0, vk::WHOLE_SIZE, vk::MemoryMapFlags::empty())
.expect("Failed to map memory");
println!("Mapped memory");
ptr
}
}
fn setup_desc_layout(dev: &Device) -> vk::DescriptorSetLayout {
let storage_binding = vk::DescriptorSetLayoutBinding::default()
.binding(0)
.descriptor_type(vk::DescriptorType::STORAGE_BUFFER)
.descriptor_count(1)
.stage_flags(vk::ShaderStageFlags::VERTEX);
let layouts = [storage_binding];
let layout_info = vk::DescriptorSetLayoutCreateInfo::default().bindings(&layouts);
let layout = unsafe {
dev.create_descriptor_set_layout(&layout_info, None)
.expect("Failed to create descriptor set layout")
};
layout
}
fn setup_render_pass(dev: &Device) -> vk::RenderPass {
let color_attach = vk::AttachmentDescription::default()
.format(vk::Format::B8G8R8A8_UNORM)
.samples(vk::SampleCountFlags::TYPE_1)
.load_op(vk::AttachmentLoadOp::CLEAR)
.store_op(vk::AttachmentStoreOp::STORE)
.stencil_load_op(vk::AttachmentLoadOp::DONT_CARE)
.stencil_store_op(vk::AttachmentStoreOp::DONT_CARE)
.initial_layout(vk::ImageLayout::UNDEFINED)
.final_layout(vk::ImageLayout::PRESENT_SRC_KHR);
let depth_attach = vk::AttachmentDescription::default()
.format(vk::Format::D32_SFLOAT)
.samples(vk::SampleCountFlags::TYPE_1)
.load_op(vk::AttachmentLoadOp::CLEAR)
.store_op(vk::AttachmentStoreOp::DONT_CARE)
.stencil_load_op(vk::AttachmentLoadOp::DONT_CARE)
.stencil_store_op(vk::AttachmentStoreOp::DONT_CARE)
.initial_layout(vk::ImageLayout::UNDEFINED)
.final_layout(vk::ImageLayout::DEPTH_STENCIL_ATTACHMENT_OPTIMAL);
let color_ref = vk::AttachmentReference::default()
.attachment(0)
.layout(vk::ImageLayout::COLOR_ATTACHMENT_OPTIMAL);
let depth_ref = vk::AttachmentReference::default()
.attachment(1)
.layout(vk::ImageLayout::DEPTH_STENCIL_ATTACHMENT_OPTIMAL);
let color_refs = [color_ref];
let depth_refs = [depth_ref];
let subpass = vk::SubpassDescription::default()
.pipeline_bind_point(vk::PipelineBindPoint::GRAPHICS)
.color_attachments(color_refs.as_ref())
.depth_stencil_attachment(&depth_ref);
let subpass_dep = vk::SubpassDependency::default()
.src_subpass(vk::SUBPASS_EXTERNAL)
.dst_subpass(0)
.src_stage_mask(
vk::PipelineStageFlags::COLOR_ATTACHMENT_OUTPUT
| vk::PipelineStageFlags::EARLY_FRAGMENT_TESTS,
)
.dst_stage_mask(
vk::PipelineStageFlags::COLOR_ATTACHMENT_OUTPUT
| vk::PipelineStageFlags::EARLY_FRAGMENT_TESTS,
)
.src_access_mask(vk::AccessFlags::empty())
.dst_access_mask(
vk::AccessFlags::COLOR_ATTACHMENT_WRITE
| vk::AccessFlags::DEPTH_STENCIL_ATTACHMENT_WRITE,
);
let attach_desc = [color_attach, depth_attach];
let subpasses = [subpass];
let deps = [subpass_dep];
let pass_info = vk::RenderPassCreateInfo::default()
.attachments(&attach_desc)
.subpasses(subpasses.as_ref())
.dependencies(deps.as_ref());
let pass = unsafe {
dev.create_render_pass(&pass_info, None)
.expect("Failed to create render pass")
};
pass
}
fn setup_pipe_layout(dev: &Device) -> vk::PipelineLayout {
let layout = setup_desc_layout(&dev);
let push_range: [vk::PushConstantRange; 2] = [
vk::PushConstantRange::default()
.stage_flags(vk::ShaderStageFlags::VERTEX)
.offset(0)
.size(32), // vec4 camera_orig, camera_rot
vk::PushConstantRange::default()
.stage_flags(vk::ShaderStageFlags::FRAGMENT)
.offset(32)
.size(16), // vec4 base_color
];
let layouts = &[layout];
let pipe_layout = vk::PipelineLayoutCreateInfo::default()
.set_layouts(layouts.as_ref())
.push_constant_ranges(&push_range);
let pipe_layout = unsafe {
dev.create_pipeline_layout(&pipe_layout, None)
.expect("Failed to create pipeline layout")
};
pipe_layout
}
fn setup_shader_stage(
dev: &Device,
vert_shader: vk::ShaderModule,
frag_shader: vk::ShaderModule,
) -> [vk::PipelineShaderStageCreateInfo; 2] {
let vert_stage = vk::PipelineShaderStageCreateInfo::default()
.stage(vk::ShaderStageFlags::VERTEX)
.module(vert_shader)
.name(CStr::from_bytes_with_nul(b"main\0").unwrap());
let frag_stage = vk::PipelineShaderStageCreateInfo::default()
.stage(vk::ShaderStageFlags::FRAGMENT)
.module(frag_shader)
.name(CStr::from_bytes_with_nul(b"main\0").unwrap());
[vert_stage, frag_stage]
}
fn setup_pipeline(
dev: &Device,
vert_shader: &vk::ShaderModule,
frag_shader: &vk::ShaderModule,
) -> vk::Pipeline {
let pipe_layout = setup_pipe_layout(&dev);
let pass = setup_render_pass(&dev);
let shader_stages = setup_shader_stage(&dev, *vert_shader, *frag_shader);
let vert_input = vk::PipelineVertexInputStateCreateInfo::default();
let input_assembly = vk::PipelineInputAssemblyStateCreateInfo::default()
.topology(vk::PrimitiveTopology::TRIANGLE_LIST);
let rasterization = vk::PipelineRasterizationStateCreateInfo::default()
.polygon_mode(vk::PolygonMode::FILL)
.cull_mode(vk::CullModeFlags::BACK)
.front_face(vk::FrontFace::CLOCKWISE)
.line_width(1.0);
let multisample = vk::PipelineMultisampleStateCreateInfo::default()
.rasterization_samples(vk::SampleCountFlags::TYPE_1);
let depth_stencil = vk::PipelineDepthStencilStateCreateInfo::default()
.depth_test_enable(true)
.depth_write_enable(true)
.depth_compare_op(vk::CompareOp::LESS)
.depth_bounds_test_enable(true)
.stencil_test_enable(false)
.min_depth_bounds(0.0)
.max_depth_bounds(1.0);
let blend = vk::PipelineColorBlendAttachmentState::default()
.src_color_blend_factor(vk::BlendFactor::SRC_COLOR)
.dst_color_blend_factor(vk::BlendFactor::SRC_COLOR)
.color_blend_op(vk::BlendOp::ADD)
.src_alpha_blend_factor(vk::BlendFactor::SRC_COLOR)
.dst_alpha_blend_factor(vk::BlendFactor::SRC_COLOR)
.alpha_blend_op(vk::BlendOp::ADD)
.color_write_mask(
vk::ColorComponentFlags::R
| vk::ColorComponentFlags::G
| vk::ColorComponentFlags::B
| vk::ColorComponentFlags::A,
);
let blend_attachments = [blend];
let color_blend = vk::PipelineColorBlendStateCreateInfo::default()
.attachments(blend_attachments.as_ref())
.logic_op_enable(false)
.logic_op(vk::LogicOp::COPY)
.blend_constants([1.0, 1.0, 1.0, 1.0]);
let dynamic = vk::PipelineDynamicStateCreateInfo::default().dynamic_states(&[
vk::DynamicState::VIEWPORT_WITH_COUNT,
vk::DynamicState::SCISSOR_WITH_COUNT,
]);
let pipe_info = vk::GraphicsPipelineCreateInfo::default()
.stages(&shader_stages)
.vertex_input_state(&vert_input)
.input_assembly_state(&input_assembly)
.rasterization_state(&rasterization)
.multisample_state(&multisample)
.depth_stencil_state(&depth_stencil)
.color_blend_state(&color_blend)
.layout(pipe_layout)
.dynamic_state(&dynamic)
.render_pass(pass)
.subpass(0);
let pipe = unsafe {
dev.create_graphics_pipelines(vk::PipelineCache::null(), &[pipe_info], None)
.expect("Failed to create graphics pipeline")
.remove(0)
};
println!("Created pipeline");
pipe
}
// TODO dynamic state for resizing
fn setup_swapchain(
pdev: &vk::PhysicalDevice,
dev: &Device,
surface: &vk::SurfaceKHR,
surface_loader: &surface::Instance,
swapchain_loader: &ash::khr::swapchain::Device,
instance: &Instance,
) -> vk::SwapchainKHR {
let caps = unsafe {
surface_loader
.get_physical_device_surface_capabilities(*pdev, *surface)
.expect("Failed to get surface capabilities")
};
let formats = unsafe {
surface_loader
.get_physical_device_surface_formats(*pdev, *surface)
.expect("Failed to get surface formats")
};
let format = (formats)
.iter()
.filter(|f| {
f.format == vk::Format::B8G8R8A8_UNORM
&& f.color_space == vk::ColorSpaceKHR::SRGB_NONLINEAR
})
.next()
.expect("No suitable format found");
let swap_create = vk::SwapchainCreateInfoKHR::default()
.surface(*surface)
.min_image_count(caps.min_image_count)
.image_format(format.format)
.image_color_space(format.color_space)
.image_extent(caps.current_extent)
.image_array_layers(1)
.image_usage(vk::ImageUsageFlags::COLOR_ATTACHMENT)
.image_sharing_mode(vk::SharingMode::EXCLUSIVE)
.pre_transform(vk::SurfaceTransformFlagsKHR::IDENTITY)
.composite_alpha(vk::CompositeAlphaFlagsKHR::OPAQUE)
.present_mode(vk::PresentModeKHR::MAILBOX)
.clipped(true);
let swapchain = unsafe {
swapchain_loader
.create_swapchain(&swap_create, None)
.expect("Failed to create swapchain")
};
println!("Created swapchain");
swapchain
}
fn setup_desc_pool(dev: &Device) -> vk::DescriptorPool {
let pool_size = vk::DescriptorPoolSize::default()
.ty(vk::DescriptorType::STORAGE_BUFFER)
.descriptor_count(1);
let pool_sizes = [pool_size];
let pool_info = vk::DescriptorPoolCreateInfo::default()
.max_sets(1)
.pool_sizes(&pool_sizes);
let pool = unsafe {
dev.create_descriptor_pool(&pool_info, None)
.expect("Failed to create descriptor pool")
};
pool
}
fn make_swap_images(
dev: &Device,
swapchain: &vk::SwapchainKHR,
swapchain_loader: &swapchain::Device,
) -> Vec<vk::Image> {
unsafe {
let images = swapchain_loader
.get_swapchain_images(*swapchain)
.expect("Failed to get swapchain images");
println!("Fetched swapchain images");
images
}
}
fn make_swap_views(
dev: &Device,
swap_images: &Vec<vk::Image>,
format: vk::Format,
) -> Vec<vk::ImageView> {
let mut views = Vec::new();
for img in swap_images.iter() {
let view_info = vk::ImageViewCreateInfo::default()
.image(*img)
.view_type(vk::ImageViewType::TYPE_2D)
.format(format)
.components(vk::ComponentMapping::default())
.subresource_range(
vk::ImageSubresourceRange::default()
.aspect_mask(vk::ImageAspectFlags::COLOR)
.base_mip_level(0)
.level_count(1)
.base_array_layer(0)
.layer_count(1),
);
let view = unsafe {
dev.create_image_view(&view_info, None)
.expect("Failed to create image view")
};
views.push(view);
}
views
}
fn main() {
println!("Hello, world!");
let sdl_context = sdl2::init().unwrap();
let video_subsystem = sdl_context.video().unwrap();
let mut width = 1024;
let mut height = 768;
let max_width = 3440;
let max_height = 1440;
let window = video_subsystem
.window(APP_NAME, width, height)
.vulkan()
.build()
.unwrap();
let entry = Entry::linked();
let instance = create_instance(&window, &entry);
let surface = make_surface(&entry, &instance, &window);
let pdev = find_pdev_dgpu(&instance);
let rcs_queue_inx = find_rcs_queue_inx(&instance, &pdev).expect("No RCS queue found");
let dev = make_dev(&instance, &pdev, rcs_queue_inx, vec![c"VK_KHR_swapchain", c"VK_EXT_extended_dynamic_state3"]);
let queue = unsafe { dev.get_device_queue(rcs_queue_inx, 0) };
let cmd_pool = make_command_pool(&dev, rcs_queue_inx);
let cmd_buf = alloc_cmd_buf(&dev, cmd_pool);
let host_visible_inx =
find_host_visible(&instance, &pdev).expect("No host visible memory found");
let host_invisible_inx =
find_host_invisible(&instance, &pdev).expect("No host invisible memory found");
let mesh_mem = mem_alloc(&dev, host_visible_inx, MESH_SIZE);
// Max viewport size is 3440x1440
let depth_mem = mem_alloc(&dev, host_invisible_inx, max_width * max_height * 8);
let depth_img = make_depth_img(
&dev,
host_invisible_inx,
width,
height,
depth_mem,
rcs_queue_inx,
);
let mesh_buf = alloc_buf(
&dev,
&mesh_mem,
MESH_SIZE,
vk::BufferUsageFlags::TRANSFER_SRC | vk::BufferUsageFlags::STORAGE_BUFFER,
);
let mesh_mem = buf_to_ptr(&dev, &mesh_mem, &mesh_buf);
unsafe {
std::ptr::copy(POSITIONS.as_ptr(), mesh_mem as *mut f32, POSITIONS.len());
}
let vert_shader_bin = std::fs::read("shaders/vert.spv").unwrap();
let frag_shader_bin = std::fs::read("shaders/frag.spv").unwrap();
let vert_shader = unsafe {
dev.create_shader_module(
&vk::ShaderModuleCreateInfo {
code_size: vert_shader_bin.len(),
p_code: vert_shader_bin.as_ptr() as *const u32,
..Default::default()
},
None,
)
.expect("Failed to create vertex shader module")
};
let frag_shader = unsafe {
dev.create_shader_module(
&vk::ShaderModuleCreateInfo {
code_size: frag_shader_bin.len(),
p_code: frag_shader_bin.as_ptr() as *const u32,
..Default::default()
},
None,
)
.expect("Failed to create fragment shader module")
};
let pipe = setup_pipeline(&dev, &vert_shader, &frag_shader);
let surface_loader = surface::Instance::new(&entry, &instance);
let swapchain_loader = swapchain::Device::new(&instance, &dev);
let swapchain = setup_swapchain(
&pdev,
&dev,
&surface,
&surface_loader,
&swapchain_loader,
&instance,
);
let desc_pool = setup_desc_pool(&dev);
let swap_images = make_swap_images(&dev, &swapchain, &swapchain_loader);
let swap_views = make_swap_views(&dev, &swap_images, vk::Format::B8G8R8A8_UNORM);
}

Loading…
Cancel
Save