Browse Source

new renderer code, heavy optimizations

master
Alison Watson 1 month ago
parent
commit
a37b7eeab6
38 changed files with 1374 additions and 3164 deletions
  1. +2
    -2
      glsl/main.frag
  2. +1
    -0
      source/framework/data.rs
  3. +52
    -26
      source/framework/data/bit.rs
  4. +24
    -61
      source/framework/data/model.rs
  5. +9
    -0
      source/framework/data/read.rs
  6. +32
    -0
      source/framework/data/shader.rs
  7. +12
    -13
      source/framework/data/vfs.rs
  8. +10
    -7
      source/framework/defl.rs
  9. +85
    -0
      source/framework/iter.rs
  10. +3
    -6
      source/framework/lib.rs
  11. +793
    -335
      source/framework/render.rs
  12. +133
    -186
      source/framework/render/buffer.rs
  13. +0
    -146
      source/framework/render/cmd.rs
  14. +0
    -52
      source/framework/render/descriptor_set_layout.rs
  15. +0
    -47
      source/framework/render/descriptorlayout.rs
  16. +0
    -142
      source/framework/render/descriptorpool.rs
  17. +0
    -203
      source/framework/render/device.rs
  18. +0
    -49
      source/framework/render/fence.rs
  19. +0
    -76
      source/framework/render/framebuffer.rs
  20. +0
    -359
      source/framework/render/image.rs
  21. +0
    -67
      source/framework/render/imageview.rs
  22. +0
    -93
      source/framework/render/instance.rs
  23. +0
    -62
      source/framework/render/misc.rs
  24. +24
    -89
      source/framework/render/model.rs
  25. +0
    -175
      source/framework/render/pipeline.rs
  26. +0
    -52
      source/framework/render/pipelinelayout.rs
  27. +0
    -30
      source/framework/render/properties.rs
  28. +0
    -90
      source/framework/render/queue.rs
  29. +0
    -106
      source/framework/render/renderpass.rs
  30. +0
    -61
      source/framework/render/sampler.rs
  31. +0
    -46
      source/framework/render/semaphore.rs
  32. +28
    -34
      source/framework/render/shader.rs
  33. +0
    -21
      source/framework/render/spir.rs
  34. +0
    -35
      source/framework/render/surface.rs
  35. +0
    -166
      source/framework/render/swapchain.rs
  36. +140
    -0
      source/framework/render/texture.rs
  37. +5
    -0
      source/framework/types.rs
  38. +21
    -327
      source/main_test/entry.rs

+ 2
- 2
glsl/main.frag View File

@@ -3,10 +3,10 @@ layout(location = 1) in vec4 in_color;

layout(location = 0) out vec4 out_color;

layout(binding = 2) uniform sampler2D u_sampler;
//layout(binding = 2) uniform sampler2D u_sampler;

void main() {
out_color = texture(u_sampler, in_tex_coord.xy);
out_color = vec4(0.0); //texture(u_sampler, in_tex_coord.xy);
out_color *= in_color;
}



+ 1
- 0
source/framework/data.rs View File

@@ -3,6 +3,7 @@ pub mod color;
pub mod image;
pub mod model;
pub mod read;
pub mod shader;
pub mod text;
pub mod uniforms;
pub mod vertex;


+ 52
- 26
source/framework/data/bit.rs View File

@@ -67,39 +67,49 @@ macro_rules! read_bits_impl {
fn read_bits_le(
b: &[u8], cr_bit: usize, mut width: usize,
) -> Option<Self> {
if width == 0 {
return Some(0);
}
match width {
| 0 => Some(0),
| 1 => {
let byte = cr_bit / 8;
if byte < b.len() {
let bitn = cr_bit % 8;
Some(if b[byte] & 1 << bitn != 0 { 1 } else { 0 })
} else {
None
}
}
| _ => {
let last = (cr_bit + width - 1) / 8;

let last = (cr_bit + width - 1) / 8;
if last >= b.len() {
return None;
}

if last >= b.len() {
return None;
}
let mut byte_ptr = cr_bit / 8;
let mut bits_ptr = cr_bit % 8;

let mut byte_ptr = cr_bit / 8;
let mut bits_ptr = cr_bit % 8;
let mut res = 0;
let mut bit = 1;

let mut res = 0;
let mut bit = 1;
while width > 0 {
width -= 1;

while width > 0 {
width -= 1;
if b[byte_ptr] & 1 << bits_ptr != 0 {
res |= bit;
}

if b[byte_ptr] & 1 << bits_ptr != 0 {
res |= bit;
}
bit <<= 1;
bits_ptr += 1;

bit <<= 1;
bits_ptr += 1;
if bits_ptr > 7 {
bits_ptr = 0;
byte_ptr += 1;
}
}

if bits_ptr > 7 {
bits_ptr = 0;
byte_ptr += 1;
Some(res)
}
}

Some(res)
}
}
};
@@ -166,12 +176,28 @@ fn bit_tests() {
assert_eq!(n, 0b101);
p += 3;

let n = u64::read_bits_le(INPUT, p, 63).unwrap();
let n = u64::read_bits_le(INPUT, p, 59).unwrap();
assert_eq!(
n,
0b010011001110101100111000011111111100000000000100001010101001100,
0b11001110101100111000011111111100000000000100001010101001100,
);
p += 63;
p += 59;

let n = u8::read_bits_le(INPUT, p, 1).unwrap();
assert_eq!(n, 0b0);
p += 1;

let n = u8::read_bits_le(INPUT, p, 1).unwrap();
assert_eq!(n, 0b0);
p += 1;

let n = u8::read_bits_le(INPUT, p, 1).unwrap();
assert_eq!(n, 0b1);
p += 1;

let n = u8::read_bits_le(INPUT, p, 1).unwrap();
assert_eq!(n, 0b0);
p += 1;

let n = u8::read_bits_le(INPUT, p, 4).unwrap();
assert_eq!(n, 0b1001);


+ 24
- 61
source/framework/data/model.rs View File

@@ -2,8 +2,8 @@ use crate::{
data::{read, vertex::Vertex},
ffi,
math::*,
types::StkStr,
};
use smol_str::SmolStr;
use std::{
collections::HashMap,
io::{self, Read, Seek, SeekFrom},
@@ -33,17 +33,6 @@ pub enum Err {
VaFormat,
}

struct VertexZipper {
// kono jippa......
pos_v: std::vec::IntoIter<Vec3>,
tex_v: std::vec::IntoIter<Vec3>,
nrm_v: std::vec::IntoIter<Vec3>,
tan_v: std::vec::IntoIter<Vec4>,
idx_v: std::vec::IntoIter<Vec4>,
wgt_v: std::vec::IntoIter<Vec4>,
clr_v: std::vec::IntoIter<Vec4>,
}

struct Pose {
par: usize,
msk: u32,
@@ -52,13 +41,13 @@ struct Pose {
}

struct Joint {
nam: SmolStr,
nam: StkStr,
mat: Mat4,
inv: Mat4,
}

pub struct Mesh {
mat: SmolStr,
mat: StkStr,
vtx: Range<usize>,
idx: Range<usize>,
}
@@ -73,51 +62,25 @@ pub struct ModelData {
/// Run-time model data. Anything necessary for passing commands to
/// the GPU.
pub struct Model {
meshes: HashMap<SmolStr, Mesh>,
meshes: HashMap<StkStr, Mesh>,
frames: Vec<Vec<Mat4>>,
num_frms: usize,
}

impl Iterator for VertexZipper {
type Item = (
Option<Vec3>,
Option<Vec3>,
Option<Vec3>,
Option<Vec4>,
Option<Vec4>,
Option<Vec4>,
Option<Vec4>,
);

fn next(&mut self) -> Option<Self::Item> {
match (
self.pos_v.next(),
self.tex_v.next(),
self.nrm_v.next(),
self.tan_v.next(),
self.idx_v.next(),
self.wgt_v.next(),
self.clr_v.next(),
) {
| (None, None, None, None, None, None, None) => None,
| tuple => Some(tuple),
}
}
}

const FMT_I8: u32 = 0;
const FMT_U8: u32 = 1;
const FMT_I16: u32 = 2;
const FMT_U16: u32 = 3;
const FMT_I32: u32 = 4;
const FMT_U32: u32 = 5;
const FMT_F16: u32 = 6;
const FMT_F32: u32 = 7;
const FMT_F64: u32 = 8;

fn fmt_check(fm: u32) -> Result<(), Err> {
match fm {
| FMT_I8 | FMT_U8 | FMT_I16 | FMT_U16 | FMT_I32 | FMT_U32 | FMT_F32
| FMT_F64 => Ok(()),
| FMT_I8 | FMT_U8 | FMT_I16 | FMT_U16 | FMT_I32 | FMT_U32 | FMT_F16
| FMT_F32 | FMT_F64 => Ok(()),
| _ => Err(Err::VaFormat),
}
}
@@ -125,7 +88,7 @@ fn fmt_check(fm: u32) -> Result<(), Err> {
fn fmt_size(fm: u32) -> usize {
match fm {
| FMT_I8 | FMT_U8 => 1,
| FMT_I16 | FMT_U16 => 2,
| FMT_I16 | FMT_U16 | FMT_F16 => 2,
| FMT_I32 | FMT_U32 | FMT_F32 => 4,
| FMT_F64 => 8,
| _ => unsafe { std::hint::unreachable_unchecked() },
@@ -140,8 +103,9 @@ fn fmt_read_abs(fm: u32, vec: &[u8], pos: usize) -> f32 {
| FMT_U16 => f32::from(read::u16le_16(vec, pos)),
| FMT_I32 => read::i32le_32(vec, pos) as f32,
| FMT_U32 => read::u32le_32(vec, pos) as f32,
| FMT_F16 => read::f16le_32(vec, pos),
| FMT_F32 => read::f32le_32(vec, pos),
| FMT_F64 => read::f64le_64(vec, pos) as f32,
| FMT_F64 => read::f64le_32(vec, pos),
| _ => unsafe { std::hint::unreachable_unchecked() },
}
}
@@ -154,6 +118,7 @@ fn fmt_read_nrm(fm: u32, vec: &[u8], pos: usize) -> f32 {
| FMT_U16 => f32::from(read::u16le_16(vec, pos)) / 65535.0,
| FMT_I32 => (read::i32le_32(vec, pos) as f64 / 2147483648.0) as f32,
| FMT_U32 => (read::u32le_32(vec, pos) as f64 / 4294967295.0) as f32,
| FMT_F16 => f32::clamp(read::f16le_32(vec, pos), 0.0, 1.0),
| FMT_F32 => f32::clamp(read::f32le_32(vec, pos), 0.0, 1.0),
| FMT_F64 => f32::clamp(read::f64le_64(vec, pos) as f32, 0.0, 1.0),
| _ => unsafe { std::hint::unreachable_unchecked() },
@@ -314,19 +279,17 @@ impl Model {
}

// zip the vertex info
let zipper = VertexZipper {
pos_v: pos_v.into_iter(),
tex_v: tex_v.into_iter(),
nrm_v: nrm_v.into_iter(),
tan_v: tan_v.into_iter(),
idx_v: idx_v.into_iter(),
wgt_v: wgt_v.into_iter(),
clr_v: clr_v.into_iter(),
};

let mut vert_dat = Vec::with_capacity(num_vert);

for (pos, tex, nrm, tan, idx, wgt, clr) in zipper {
for (pos, tex, nrm, tan, idx, wgt, clr) in crate::iter::OpenZip((
pos_v.into_iter(),
tex_v.into_iter(),
nrm_v.into_iter(),
tan_v.into_iter(),
idx_v.into_iter(),
wgt_v.into_iter(),
clr_v.into_iter(),
)) {
let pos = pos.unwrap_or_else(|| Vec3::ZERO);
let tex = tex.unwrap_or_else(|| Vec3::ZERO);
let nrm = nrm.unwrap_or_else(|| Vec3::ZERO);
@@ -366,8 +329,8 @@ impl Model {
let idx = read::u32le_sz(mesh, 16) * 3;
let inu = read::u32le_sz(mesh, 20) * 3;

let nam = SmolStr::new(from_stab(&stab, nam)?);
let mat = SmolStr::new(from_stab(&stab, mat)?);
let nam = StkStr::new(from_stab(&stab, nam)?);
let mat = StkStr::new(from_stab(&stab, mat)?);

let vtx = vtx..vtx + vnu;
let idx = idx..idx + inu;
@@ -385,7 +348,7 @@ impl Model {
let par = read::u32le_sz(join, 4);
let trs = read::array(read::f32le_32, join, [0.0; 10], 4, 8);

let nam = SmolStr::new(from_stab(&stab, nam)?);
let nam = StkStr::new(from_stab(&stab, nam)?);

let xlt = Vec3::new(trs[0], trs[1], trs[2]);
let rot = Quat::from_xyzw(trs[3], trs[4], trs[5], trs[6]).normalize();
@@ -482,7 +445,7 @@ impl Model {
}

impl std::ops::Deref for Model {
type Target = HashMap<SmolStr, Mesh>;
type Target = HashMap<StkStr, Mesh>;

fn deref(&self) -> &Self::Target {
&self.meshes


+ 9
- 0
source/framework/data/read.rs View File

@@ -1,3 +1,4 @@
use half::f16;
use std::io::{self, Read};

pub const fn i16le_16(b: &[u8], p: usize) -> i16 {
@@ -28,6 +29,10 @@ pub const fn u32le_sz(b: &[u8], p: usize) -> usize {
u32le_32(b, p) as usize
}

pub fn f16le_32(b: &[u8], p: usize) -> f32 {
f16::from_le_bytes([b[p], b[p + 1]]).to_f32()
}

pub fn f32le_32(b: &[u8], p: usize) -> f32 {
f32::from_le_bytes([b[p], b[p + 1], b[p + 2], b[p + 3]])
}
@@ -45,6 +50,10 @@ pub fn f64le_64(b: &[u8], p: usize) -> f64 {
])
}

pub fn f64le_32(b: &[u8], p: usize) -> f32 {
f64le_64(b, p) as f32
}

pub fn array<T, const N: usize>(
f: impl Fn(&[u8], usize) -> T, b: &[u8], mut v: [T; N], step: usize,
beg: usize,


+ 32
- 0
source/framework/data/shader.rs View File

@@ -0,0 +1,32 @@
use super::read;

#[repr(u32)]
pub enum Stage {
Compute,
Fragment,
Geometry,
Vertex,
}

pub struct Module {
pub code: Vec<u32>,
pub size: usize,
pub stage: Stage,
pub name: String,
}

impl Module {
pub fn read(bytecode: &[u8], stage: Stage, name: &str) -> Self {
let mut code = Vec::with_capacity(bytecode.len() / 4);

for word in bytecode.chunks_exact(4) {
code.push(read::u32le_32(word, 0));
}

let size = code.len() * 4;

Self { code, size, stage, name: name.to_owned() }
}
}

// EOF

+ 12
- 13
source/framework/data/vfs.rs View File

@@ -1,5 +1,4 @@
use crate::{data::read, defl};
use smol_str::SmolStr;
use crate::{data::read, defl, types::StkStr};
use std::{
collections::HashMap,
fmt, fs,
@@ -17,9 +16,9 @@ pub enum ErrArc {
#[error(transparent)]
Deflate(#[from] defl::Err),
#[error("Duplicate of `{0}'")]
DuplicateFile(SmolStr),
DuplicateFile(StkStr),
#[error("Bad file type for `{0}'")]
FileType(SmolStr),
FileType(StkStr),
#[error("Invalid magic number")]
InvalidMagic,
#[error(transparent)]
@@ -27,7 +26,7 @@ pub enum ErrArc {
#[error("No archive `{0}'")]
NoArchive(usize),
#[error("No file `{0}'")]
NoFile(SmolStr),
NoFile(StkStr),
#[error(transparent)]
ParseInt(#[from] std::num::ParseIntError),
#[error(transparent)]
@@ -39,7 +38,7 @@ pub struct File {
}

pub struct Arc {
name_dat: Vec<SmolStr>,
name_dat: Vec<StkStr>,
file_dat: HashMap<u64, File>,
files: HashMap<&'static str, &'static File>,
}
@@ -54,8 +53,8 @@ fn from_utf8_null(v: &[u8]) -> Result<&str, Utf8Error> {
Ok(std::str::from_utf8(v)?.trim_end_matches(|c| c == '\0' || c == ' '))
}

fn path_to_local(top_path: &Path, path: &Path) -> SmolStr {
SmolStr::new(path.strip_prefix(top_path).unwrap().to_string_lossy())
fn path_to_local(top_path: &Path, path: &Path) -> StkStr {
StkStr::new(path.strip_prefix(top_path).unwrap().to_string_lossy())
}

fn file_ref(
@@ -106,14 +105,14 @@ impl Arc {
} else if path.is_file() {
Self::read_tar(&mut fs::File::open(path)?)
} else {
Err(ErrArc::FileType(SmolStr::new(path.to_string_lossy())))
Err(ErrArc::FileType(StkStr::new(path.to_string_lossy())))
}
}

pub fn read_dir(path: &Path) -> Result<Pin<Box<Self>>, ErrArc> {
fn recurse(
top_path: &Path, cur_path: &Path, file_dat: &mut HashMap<u64, File>,
name_map: &mut HashMap<SmolStr, u64>,
name_map: &mut HashMap<StkStr, u64>,
) -> Result<(), ErrArc> {
for ent in fs::read_dir(cur_path)? {
let path = ent?.path();
@@ -165,7 +164,7 @@ impl Arc {
let name = {
let pfx = from_utf8_null(&head[345..500])?;
let sfx = from_utf8_null(&head[0..100])?;
SmolStr::from_iter(pfx.chars().chain(sfx.chars()))
StkStr::from_iter(pfx.chars().chain(sfx.chars()))
};

if name_map.contains_key(&name) {
@@ -197,7 +196,7 @@ impl Arc {
}

fn finalize(
file_dat: HashMap<u64, File>, name_map: HashMap<SmolStr, u64>,
file_dat: HashMap<u64, File>, name_map: HashMap<StkStr, u64>,
) -> Result<Pin<Box<Self>>, ErrArc> {
// create a flat map of names
let mut refs_dat = Vec::with_capacity(name_map.len());
@@ -249,7 +248,7 @@ impl Vfs {
.files
.get(&name)
.copied()
.ok_or_else(|| ErrArc::NoFile(SmolStr::new(name)))
.ok_or_else(|| ErrArc::NoFile(StkStr::new(name)))
}
}



+ 10
- 7
source/framework/defl.rs View File

@@ -3,9 +3,12 @@
use crate::{
data::{bit::ReadBits, read},
ffi,
types::{stkvec, StkVec},
};
use std::cmp::Ordering;

type AlphabetTable = StkVec<[u16; 320]>;

#[derive(Error, Debug)]
pub enum Err {
#[error("Bad stream block type")]
@@ -16,8 +19,6 @@ pub enum Err {
Bits0,
#[error("Not enough bits for code-repeat")]
BitsCode,
#[error("Invalid alphabet index")]
AlphaIndex,
#[error("Couldn't decode from table")]
TableDecode,
#[error("Bad distance in pair")]
@@ -201,16 +202,18 @@ fn st_literal(b: &[u8], p: &mut usize, v: &mut Vec<u8>) -> Result<(), Err> {
}
}

fn next_alpha(alpha: &mut [u16], i: &mut usize, n: u16) -> Result<(), Err> {
*alpha.get_mut(*i).ok_or(Err::AlphaIndex)? = n;
fn next_alpha(
alpha: &mut AlphabetTable, i: &mut usize, n: u16,
) -> Result<(), Err> {
alpha[*i] = n;
*i += 1;
Ok(())
}

fn read_alphabet(
b: &[u8], p: &mut usize, n: usize, table: &HuffmanTable,
) -> Result<Vec<u16>, Err> {
let mut alpha = vec![0; n];
) -> Result<AlphabetTable, Err> {
let mut alpha = stkvec![0; n];
let mut i = 0;

while i < alpha.len() {
@@ -223,7 +226,7 @@ fn read_alphabet(
}
| 16 => {
// copy previous code 3-6 times
let lst = *alpha.get(i - 1).ok_or(Err::BitsCode)?;
let lst = alpha[i - 1];
let len = u8::read_bits_le(b, *p, 2).ok_or(Err::BitsCode)? + 3;
*p += 2;



+ 85
- 0
source/framework/iter.rs View File

@@ -0,0 +1,85 @@
#[macro_export]
macro_rules! coll {
(<$t:ty> $it:expr, $xp:expr) => {
IntoIterator::into_iter($it).map($xp).collect::<$t>()
};
(<$t:ty> $xp:expr; $sz:expr) => {
coll![<$t> (0..$sz), |_| $xp]
};
}

#[macro_export]
macro_rules! vec_r {
($it:expr, $xp:expr) => {coll![<Result<Vec<_>, _>> $it, $xp]};
($xp:expr; $sz:expr) => {coll![<Result<Vec<_>, _>> $xp; $sz]};
}

#[macro_export]
macro_rules! vec_e {
($it:expr, $xp:expr) => {coll![<Vec<_>> $it, $xp]};
($xp:expr; $sz:expr) => {coll![<Vec<_>> $xp; $sz]};
}

#[macro_export]
macro_rules! stkvec_r {
(<$t:ty> $it:expr, $xp:expr) => {coll![<Result<StkVec<$t>, _>> $it, $xp]};
(<$t:ty> $xp:expr; $sz:expr) => {coll![<Result<StkVec<$t>, _>> $xp; $sz]};
($it:expr, $xp:expr) => {coll![<Result<StkVec<_>, _>> $it, $xp]};
($xp:expr; $sz:expr) => {coll![<Result<StkVec<_>, _>> $xp; $sz]};
}

macro_rules! zips {
($i:ident) => {
None
};

($($t:ident/$n:ident),*) => {
impl<$($t),*> Iterator for OpenZip<($($t),*)>
where
$($t: Iterator),*
{
type Item = ($(Option<$t::Item>),*);

fn next(&mut self) -> Option<Self::Item> {
let ($($n),*) = &mut self.0;
match ($($n.next()),*) {
| ($(zips!($t)),*) => None,
| v => Some(v),
}
}
}

impl<$($t),*> Iterator for ClosedZip<($($t),*)>
where
$($t: Iterator),*
{
type Item = ($($t::Item),*);

fn next(&mut self) -> Option<Self::Item> {
let ($($n),*) = &mut self.0;
$(
let $n = match $n.next() {
None => return None,
Some(v) => v,
};
)*
Some(($($n),*))
}
}
};
}

zips!(A / a, B / b);
zips!(A / a, B / b, C / c);
zips!(A / a, B / b, C / c, D / d);
zips!(A / a, B / b, C / c, D / d, E / e);
zips!(A / a, B / b, C / c, D / d, E / e, F / f);
zips!(A / a, B / b, C / c, D / d, E / e, F / f, G / g);
zips!(A / a, B / b, C / c, D / d, E / e, F / f, G / g, H / h);
zips!(A / a, B / b, C / c, D / d, E / e, F / f, G / g, H / h, I / i);
zips!(A / a, B / b, C / c, D / d, E / e, F / f, G / g, H / h, I / i, J / j);

pub struct OpenZip<T>(pub T);
pub struct ClosedZip<T>(pub T);

// EOF

+ 3
- 6
source/framework/lib.rs View File

@@ -14,14 +14,10 @@
#![allow(clippy::type_complexity)]
#![cfg_attr(test, allow(dead_code))]

macro_rules! vec_r {
($exp:expr; $num:expr) => {
(0..$num).map($exp).collect::<Result<Vec<_>, _>>()
};
}

#[macro_use]
pub mod ffi;
#[macro_use]
pub mod iter;

#[macro_use(Error)]
extern crate thiserror;
@@ -33,6 +29,7 @@ pub mod hal;
pub mod math;
pub mod meta;
pub mod render;
pub mod types;
pub mod vire;

// EOF

+ 793
- 335
source/framework/render.rs
File diff suppressed because it is too large
View File


+ 133
- 186
source/framework/render/buffer.rs View File

@@ -1,229 +1,176 @@
use crate::{
data::{self, vertex::Vertex},
render::{misc::dev_size_of, CommandPool, Device, ErrAllocMem, GetDevice},
};
use ash::{version::DeviceV1_0, vk};
use std::{ptr, rc::Rc};

pub struct Buffer {
handle: vk::Buffer,
memory: vk::DeviceMemory,

size: vk::DeviceSize,

pub device: Rc<Device>,
}

unsafe fn create_buffer(
device: &Device, size: vk::DeviceSize, usage: vk::BufferUsageFlags,
memory_flags: vk::MemoryPropertyFlags,
) -> Result<(vk::Buffer, vk::DeviceMemory), ErrAllocMem> {
let create_info = vk::BufferCreateInfo {
size,
usage,
sharing_mode: vk::SharingMode::EXCLUSIVE,
..Default::default()
};

let handle = device.create_buffer(&create_info, None)?;

let memory = device.alloc_mem(
device.get_buffer_memory_requirements(handle),
memory_flags,
)?;

device.bind_buffer_memory(handle, memory, 0)?;

Ok((handle, memory))
}

impl GetDevice for Buffer {
fn get_device(&self) -> &Rc<Device> {
&self.device
}
}
use super::*;

impl StaticData {
pub(super) unsafe fn new_buf(
&self, info: &BufferInfo,
) -> Result<Buf, ErrRenderer> {
let create_info = vk::BufferCreateInfo {
size: info.size,
usage: info.usage,
sharing_mode: vk::SharingMode::EXCLUSIVE,
..Default::default()
};

impl Buffer {
/// Creates a vertex buffer.
pub fn create_vert(
cmd_pool: &CommandPool, vertices: &[Vertex],
) -> Result<Rc<Self>, ErrAllocMem> {
let device = cmd_pool.get_device().clone();
let size = dev_size_of(vertices);
let buff = self.dev.create_buffer(&create_info, None)?;

unsafe {
let (handle, memory) = create_buffer(
&device,
size,
vk::BufferUsageFlags::TRANSFER_DST
| vk::BufferUsageFlags::VERTEX_BUFFER,
vk::MemoryPropertyFlags::DEVICE_LOCAL,
)?;
let dmem = self.alloc_mem(
self.dev.get_buffer_memory_requirements(buff),
info.props,
)?;

let dst = Self { handle, memory, size, device };
self.dev.bind_buffer_memory(buff, dmem, 0)?;

dst.xfer_data(cmd_pool, vertices)?;
let info = vk::DescriptorBufferInfo {
buffer: buff,
range: info.size,
..Default::default()
};

Ok(Rc::new(dst))
}
Ok(Buf { buff, dmem, info })
}

/// Creates an index buffer.
pub fn create_indx(
cmd_pool: &CommandPool, indices: &[u32],
) -> Result<Rc<Self>, ErrAllocMem> {
let device = cmd_pool.get_device().clone();
let size = dev_size_of(indices);

unsafe {
let (handle, memory) = create_buffer(
&device,
size,
vk::BufferUsageFlags::TRANSFER_DST
| vk::BufferUsageFlags::INDEX_BUFFER,
vk::MemoryPropertyFlags::DEVICE_LOCAL,
)?;

let dst = Self { handle, memory, size, device };

dst.xfer_data(cmd_pool, indices)?;

Ok(Rc::new(dst))
}
}
pub(super) unsafe fn alloc_mem(
&self, memory_reqs: vk::MemoryRequirements,
memory_flags: vk::MemoryPropertyFlags,
) -> Result<vk::DeviceMemory, ErrRenderer> {
let memory_props =
self.ins.get_physical_device_memory_properties(self.physical);

let memory_type_index = get_memory_type(
memory_props,
memory_flags,
memory_reqs.memory_type_bits,
)?;

let allocate_info = vk::MemoryAllocateInfo {
memory_type_index,
allocation_size: memory_reqs.size,
..Default::default()
};

/// Creates an image buffer.
pub fn create_image(
device: Rc<Device>, images: &[data::image::Image],
) -> Result<Rc<Self>, ErrAllocMem> {
let size =
images.iter().fold(0, |acc, img| acc + dev_size_of(img.data()));

unsafe {
let (handle, memory) = create_buffer(
&device,
size,
vk::BufferUsageFlags::TRANSFER_SRC,
vk::MemoryPropertyFlags::HOST_VISIBLE
| vk::MemoryPropertyFlags::HOST_COHERENT,
)?;

let src = Self { handle, memory, size, device };

src.write_data_with(|mut out| {
for img in images {
let data = img.data();
ptr::copy_nonoverlapping(data.as_ptr(), out, data.len());
out = out.add(data.len());
}

Ok(())
})?;

Ok(Rc::new(src))
}
Ok(self.dev.allocate_memory(&allocate_info, None)?)
}

/// Creates a uniform buffer.
pub fn create_uniform(
device: Rc<Device>, size: vk::DeviceSize,
) -> Result<Rc<Self>, ErrAllocMem> {
let (handle, memory) = unsafe {
create_buffer(
&device,
size,
vk::BufferUsageFlags::UNIFORM_BUFFER,
vk::MemoryPropertyFlags::HOST_VISIBLE
| vk::MemoryPropertyFlags::HOST_COHERENT,
)?
pub(super) unsafe fn transient_buffer<F>(
&self, f: F,
) -> Result<(), vk::Result>
where
F: FnOnce(vk::CommandBuffer) -> Result<(), vk::Result>,
{
let create_info = vk::CommandBufferAllocateInfo {
command_pool: self.cmd_pool,
level: vk::CommandBufferLevel::PRIMARY,
command_buffer_count: 1,
..Default::default()
};

Ok(Rc::new(Self { handle, memory, size, device }))
}
let handles = self.dev.allocate_command_buffers(&create_info)?;

/// Copies the contents of `src` to `self` using a transient pool.
unsafe fn copy_buffer(
&self, src: &Self, cmd_pool: &CommandPool,
) -> Result<(), vk::Result> {
cmd_pool.with_transient_buffer(|cbuf| {
let copy =
[vk::BufferCopy { src_offset: 0, dst_offset: 0, size: self.size }];
let begin_info = vk::CommandBufferBeginInfo {
flags: vk::CommandBufferUsageFlags::ONE_TIME_SUBMIT,
..Default::default()
};

self.get_device().cmd_copy_buffer(cbuf, **src, **self, &copy);
self.dev.begin_command_buffer(handles[0], &begin_info)?;

Ok(())
})
}
f(handles[0])?;

/// Transfers `data` from the client to the server.
pub fn xfer_data<T>(
&self, cmd_pool: &CommandPool, data: &[T],
) -> Result<(), ErrAllocMem> {
let size = dev_size_of(data);
self.dev.end_command_buffer(handles[0])?;

unsafe {
let (handle, memory) = create_buffer(
self.get_device(),
size,
vk::BufferUsageFlags::TRANSFER_SRC,
vk::MemoryPropertyFlags::HOST_VISIBLE
| vk::MemoryPropertyFlags::HOST_COHERENT,
)?;
let submit_info = [vk::SubmitInfo {
command_buffer_count: handles.len() as u32,
p_command_buffers: handles.as_ptr(),
..Default::default()
}];

let src =
Self { handle, memory, size, device: self.get_device().clone() };
self.dev.queue_submit(
self.queue_gfx,
&submit_info,
vk::Fence::null(),
)?;

src.write_data(data)?;
self.dev.queue_wait_idle(self.queue_gfx)?;

self.copy_buffer(&src, cmd_pool)?;
}
self.dev.free_command_buffers(self.cmd_pool, &handles);

Ok(())
}

/// Writes to `self` with the function `f`.
pub fn write_data_with<T, F>(&self, f: F) -> Result<(), vk::Result>
pub(super) unsafe fn buf_write_with<T, F>(
&self, buf: &Buf, f: F,
) -> Result<(), vk::Result>
where
F: Fn(*mut T) -> Result<(), vk::Result>,
F: Fn(*mut T),
{
unsafe {
let flg = vk::MemoryMapFlags::empty();
let map =
self.get_device().map_memory(self.memory, 0, self.size, flg)?;
let flg = vk::MemoryMapFlags::empty();
let map = self.dev.map_memory(buf.dmem, 0, buf.info.range, flg)?;

f(map as *mut T)?;
f(map as *mut T);

self.get_device().unmap_memory(self.memory);
}
self.dev.unmap_memory(buf.dmem);

Ok(())
}

/// Writes `data` to `self`.
pub fn write_data<T>(&self, data: &[T]) -> Result<(), vk::Result> {
self.write_data_with(|out| {
unsafe {
ptr::copy_nonoverlapping(data.as_ptr(), out, data.len());
}
Ok(())
pub(super) unsafe fn buf_write_array<T>(
&self, buf: &Buf, data: &[T],
) -> Result<(), vk::Result> {
self.buf_write_with(buf, |out| {
std::ptr::copy_nonoverlapping(data.as_ptr(), out, data.len());
})
}

pub(super) unsafe fn buf_write_ref<T>(
&self, buf: &Buf, data: &T,
) -> Result<(), vk::Result> {
self.buf_write_with(buf, |out| {
std::ptr::copy_nonoverlapping(data, out, 1);
})
}
}

impl Drop for Buffer {
fn drop(&mut self) {
unsafe {
self.get_device().destroy_buffer(self.handle, None);
self.get_device().free_memory(self.memory, None);
}
impl Buf {
pub(super) const UFM: BufferInfo = BufferInfo {
size: size_of::<Uniforms>() as vk::DeviceSize,
usage: vk::BufferUsageFlags::UNIFORM_BUFFER,
props: vk::MemoryPropertyFlags::from_raw(
vk::MemoryPropertyFlags::HOST_VISIBLE.as_raw()
| vk::MemoryPropertyFlags::HOST_COHERENT.as_raw(),
),
};

pub(super) const BON: BufferInfo = BufferInfo {
size: size_of::<[crate::math::Mat4; 128]>() as vk::DeviceSize,
usage: vk::BufferUsageFlags::UNIFORM_BUFFER,
props: vk::MemoryPropertyFlags::from_raw(
vk::MemoryPropertyFlags::HOST_VISIBLE.as_raw()
| vk::MemoryPropertyFlags::HOST_COHERENT.as_raw(),
),
};

pub(super) unsafe fn destroy(&self, dev: &ash::Device) {
dev.destroy_buffer(self.buff, None);
dev.free_memory(self.dmem, None);
}
}

impl std::ops::Deref for Buffer {
type Target = vk::Buffer;
fn deref(&self) -> &Self::Target {
&self.handle
fn get_memory_type(
memory_props: vk::PhysicalDeviceMemoryProperties,
filter_flags: vk::MemoryPropertyFlags, filter_types: u32,
) -> Result<u32, ErrRenderer> {
let count = memory_props.memory_type_count as usize;
let iter = memory_props.memory_types.iter().take(count).enumerate();

for (i, memory_type) in iter {
let has_flags = memory_type.property_flags.contains(filter_flags);
let has_types = filter_types & 1 << i;

if has_flags && has_types != 0 {
return Ok(i as u32);
}
}

Err(ErrRenderer::NoMemoryType(filter_flags, filter_types))
}

// EOF

+ 0
- 146
source/framework/render/cmd.rs View File

@@ -1,146 +0,0 @@
use crate::render::{Device, GetDevice, Queue};
use ash::{version::DeviceV1_0, vk};
use std::{any::Any, rc::Rc};

pub struct CommandPool {
handle: vk::CommandPool,

pub queue: Rc<Queue>,
}

pub struct CommandBuffers {
handles: Vec<vk::CommandBuffer>,

pub pool: Rc<CommandPool>,

owners: Vec<Rc<dyn Any>>,
}

impl GetDevice for CommandPool {
fn get_device(&self) -> &Rc<Device> {
self.queue.get_device()
}
}

impl GetDevice for CommandBuffers {
fn get_device(&self) -> &Rc<Device> {
self.pool.get_device()
}
}

impl CommandPool {
pub fn create(queue: Rc<Queue>) -> Result<Rc<Self>, vk::Result> {
let create_info = vk::CommandPoolCreateInfo {
queue_family_index: queue.index,
..Default::default()
};

unsafe {
let handle =
queue.get_device().create_command_pool(&create_info, None)?;

Ok(Rc::new(Self { handle, queue }))
}
}

pub fn with_transient_buffer<F>(&self, f: F) -> Result<(), vk::Result>
where
F: FnOnce(vk::CommandBuffer) -> Result<(), vk::Result>,
{
let create_info = vk::CommandBufferAllocateInfo {
command_pool: **self,
level: vk::CommandBufferLevel::PRIMARY,
command_buffer_count: 1,
..Default::default()
};

unsafe {
let handles =
self.get_device().allocate_command_buffers(&create_info)?;

let begin_info = vk::CommandBufferBeginInfo {
flags: vk::CommandBufferUsageFlags::ONE_TIME_SUBMIT,
..Default::default()
};

self.get_device().begin_command_buffer(handles[0], &begin_info)?;

f(handles[0])?;

self.get_device().end_command_buffer(handles[0])?;

let submit_info = [vk::SubmitInfo {
command_buffer_count: handles.len() as u32,
p_command_buffers: handles.as_ptr(),
..Default::default()
}];

self.get_device().queue_submit(
**self.queue,
&submit_info,
vk::Fence::null(),
)?;

self.get_device().queue_wait_idle(**self.queue)?;

self.get_device().free_command_buffers(**self, &handles);

Ok(())
}
}
}

impl CommandBuffers {
pub fn allocate(
pool: Rc<CommandPool>, amount: usize,
) -> Result<Rc<Self>, vk::Result> {
let create_info = vk::CommandBufferAllocateInfo {
command_pool: **pool,
level: vk::CommandBufferLevel::PRIMARY,
command_buffer_count: amount as u32,
..Default::default()
};

unsafe {
let handles =
pool.get_device().allocate_command_buffers(&create_info)?;

Ok(Rc::new(Self { handles, pool, owners: Vec::new() }))
}
}

pub fn add_owner(&mut self, owner: Rc<dyn Any>) {
self.owners.push(owner);
}

pub fn get_handles(&self) -> &[vk::CommandBuffer] {
&self.handles
}
}

impl Drop for CommandPool {
fn drop(&mut self) {
unsafe {
self.get_device().destroy_command_pool(self.handle, None);
}
}
}

impl Drop for CommandBuffers {
fn drop(&mut self) {
unsafe {
self
.get_device()
.free_command_buffers(self.pool.handle, self.get_handles());
}
}
}

impl std::ops::Deref for CommandPool {
type Target = vk::CommandPool;
fn deref(&self) -> &Self::Target {
&self.handle
}
}

// EOF

+ 0
- 52
source/framework/render/descriptor_set_layout.rs View File

@@ -1,52 +0,0 @@
use crate::{data::uniforms::Uniforms, math::Mat4};
use ash::{version::DeviceV1_0, vk};
use std::mem::size_of;

pub(super) const UFM_BIND_SIZE: vk::DeviceSize = size_of::<Uniforms>() as _;
pub(super) const BON_BIND_SIZE: vk::DeviceSize = size_of::<[Mat4; 128]>() as _;

#[repr(u32)]
enum BindIden {
Ufm,
Bon,
Smp,
}

const BIND_DESC: [vk::DescriptorSetLayoutBinding; 3] = [
vk::DescriptorSetLayoutBinding {
binding: BindIden::Ufm as u32,
descriptor_type: vk::DescriptorType::UNIFORM_BUFFER,
descriptor_count: 1,
stage_flags: vk::ShaderStageFlags::VERTEX,
p_immutable_samplers: std::ptr::null(),
},
vk::DescriptorSetLayoutBinding {
binding: BindIden::Bon as u32,
descriptor_type: vk::DescriptorType::UNIFORM_BUFFER,
descriptor_count: 1,
stage_flags: vk::ShaderStageFlags::VERTEX,
p_immutable_samplers: std::ptr::null(),
},
vk::DescriptorSetLayoutBinding {
binding: BindIden::Smp as u32,
descriptor_type: vk::DescriptorType::COMBINED_IMAGE_SAMPLER,
descriptor_count: 1,
stage_flags: vk::ShaderStageFlags::FRAGMENT,
p_immutable_samplers: std::ptr::null(),
},
];

/// Creates a descriptor set layout.
pub(super) unsafe fn new_descriptor_set_layout(
dev: &ash::Device,
) -> Result<vk::DescriptorSetLayout, vk::Result> {
let create_info = vk::DescriptorSetLayoutCreateInfo {
binding_count: BIND_DESC.len() as u32,
p_bindings: BIND_DESC.as_ptr(),
..Default::default()
};

dev.create_descriptor_set_layout(&create_info, None)
}

// EOF

+ 0
- 47
source/framework/render/descriptorlayout.rs View File

@@ -1,47 +0,0 @@
use crate::render::{misc, Device, GetDevice};
use ash::{version::DeviceV1_0, vk};
use std::rc::Rc;

pub struct DescriptorSetLayout {
handle: vk::DescriptorSetLayout,

pub device: Rc<Device>,
}

impl GetDevice for DescriptorSetLayout {
fn get_device(&self) -> &Rc<Device> {
&self.device
}
}

impl DescriptorSetLayout {
pub fn create(device: Rc<Device>) -> Result<Rc<Self>, vk::Result> {
let create_info = vk::DescriptorSetLayoutCreateInfo {
binding_count: misc::DSC_BIND_DESC.len() as u32,
p_bindings: misc::DSC_BIND_DESC.as_ptr(),
..Default::default()
};

let handle =
unsafe { device.create_descriptor_set_layout(&create_info, None)? };

Ok(Rc::new(Self { handle, device }))
}
}

impl Drop for DescriptorSetLayout {
fn drop(&mut self) {
unsafe {
self.get_device().destroy_descriptor_set_layout(self.handle, None);
}
}
}

impl std::ops::Deref for DescriptorSetLayout {
type Target = vk::DescriptorSetLayout;
fn deref(&self) -> &Self::Target {
&self.handle
}
}

// EOF

+ 0
- 142
source/framework/render/descriptorpool.rs View File

@@ -1,142 +0,0 @@
use crate::render::{
misc, Buffer, DescriptorSetLayout, Device, GetDevice, ImageView, Sampler,
};
use ash::{version::DeviceV1_0, vk};
use std::rc::Rc;

pub struct DescriptorPool {
handle: vk::DescriptorPool,

pub layout: Rc<DescriptorSetLayout>,
pub buffers: Vec<(Rc<Buffer>, Rc<Buffer>)>,
pub sets: Vec<vk::DescriptorSet>,
pub image_view: Rc<ImageView>,
pub sampler: Rc<Sampler>,
}

impl GetDevice for DescriptorPool {
fn get_device(&self) -> &Rc<Device> {
self.layout.get_device()
}
}

impl DescriptorPool {
pub fn create(
layout: Rc<DescriptorSetLayout>, buffers: Vec<(Rc<Buffer>, Rc<Buffer>)>,
image_view: Rc<ImageView>, sampler: Rc<Sampler>,
) -> Result<Rc<Self>, vk::Result> {
let size_info = [
vk::DescriptorPoolSize {
ty: vk::DescriptorType::UNIFORM_BUFFER,
descriptor_count: buffers.len() as u32,
},
vk::DescriptorPoolSize {
ty: vk::DescriptorType::UNIFORM_BUFFER,
descriptor_count: buffers.len() as u32,
},
vk::DescriptorPoolSize {
ty: vk::DescriptorType::COMBINED_IMAGE_SAMPLER,
descriptor_count: buffers.len() as u32,
},
];

let create_info = vk::DescriptorPoolCreateInfo {
pool_size_count: size_info.len() as u32,
p_pool_sizes: size_info.as_ptr(),
max_sets: buffers.len() as u32,
..Default::default()
};

let handle = unsafe {
layout.get_device().create_descriptor_pool(&create_info, None)?
};

let set_layouts = vec![**layout; buffers.len()];

let alloc_info = vk::DescriptorSetAllocateInfo {
descriptor_pool: handle,
descriptor_set_count: set_layouts.len() as u32,
p_set_layouts: set_layouts.as_ptr(),
..Default::default()
};

let sets =
unsafe { layout.get_device().allocate_descriptor_sets(&alloc_info)? };

let mut write_infos = Vec::with_capacity(buffers.len());

for (ufm_buf, bon_buf) in buffers.iter() {
write_infos.push((
vk::DescriptorBufferInfo {
buffer: ***ufm_buf,
range: misc::UFM_BIND_SIZE,
..Default::default()
},
vk::DescriptorBufferInfo {
buffer: ***bon_buf,
range: misc::BON_BIND_SIZE,
..Default::default()
},
vk::DescriptorImageInfo {
sampler: **sampler,
image_view: **image_view,
image_layout: vk::ImageLayout::SHADER_READ_ONLY_OPTIMAL,
},
));
}

let mut write_descriptors = Vec::with_capacity(sets.len() * 3);

for (dst_set, infos) in sets.iter().zip(&write_infos) {
write_descriptors.push(vk::WriteDescriptorSet {
dst_set: *dst_set,
dst_binding: misc::UFM_BIND_IDEN,
descriptor_type: vk::DescriptorType::UNIFORM_BUFFER,
descriptor_count: 1,
p_buffer_info: &infos.0,
..Default::default()
});

write_descriptors.push(vk::WriteDescriptorSet {
dst_set: *dst_set,
dst_binding: misc::BON_BIND_IDEN,
descriptor_type: vk::DescriptorType::UNIFORM_BUFFER,
descriptor_count: 1,
p_buffer_info: &infos.1,
..Default::default()
});

write_descriptors.push(vk::WriteDescriptorSet {
dst_set: *dst_set,
dst_binding: misc::SMP_BIND_IDEN,
descriptor_type: vk::DescriptorType::COMBINED_IMAGE_SAMPLER,
descriptor_count: 1,
p_image_info: &infos.2,
..Default::default()
});
}

unsafe {
layout.get_device().update_descriptor_sets(&write_descriptors, &[]);
}

Ok(Rc::new(Self { handle, image_view, sampler, layout, buffers, sets }))
}
}

impl Drop for DescriptorPool {
fn drop(&mut self) {
unsafe {
self.get_device().destroy_descriptor_pool(self.handle, None);
}
}
}

impl std::ops::Deref for DescriptorPool {
type Target = vk::DescriptorPool;
fn deref(&self) -> &Self::Target {
&self.handle
}
}

// EOF

+ 0
- 203
source/framework/render/device.rs View File

@@ -1,203 +0,0 @@
use crate::render::{
ensure_properties, Conf, ErrProperty, Instance, QueueFamilyInfo,
};
use ash::{
extensions::khr,
version::{DeviceV1_0, InstanceV1_0},
vk,
};
use std::rc::Rc;

pub struct Device {
handle: ash::Device,

pub physical: Rc<PhysicalDevice>,
pub swapchain_ext: khr::Swapchain,
}

pub struct PhysicalDevice {
handle: vk::PhysicalDevice,

pub instance: Rc<Instance>,
}

#[derive(Error, Debug)]
pub enum ErrDeviceCreate {
#[error(transparent)]
Vk(#[from] vk::Result),
#[error("Missing extension: {0}")]
NoExtension(#[from] ErrProperty),
}

#[derive(Error, Debug)]
pub enum ErrPhysicalDeviceGet {
#[error(transparent)]
Vk(#[from] vk::Result),
#[error("No suitable devices available")]
NoDevice,
}

#[derive(Error, Debug)]
pub enum ErrAllocMem {
#[error(transparent)]
Vk(#[from] vk::Result),
#[error("No memory type with flags `{0:?}' and type `{1}'")]
NoMemoryType(vk::MemoryPropertyFlags, u32),
}

pub trait GetDevice {
fn get_device(&self) -> &Rc<Device>;
}

fn enable_device_extensions(
physical: &PhysicalDevice, extensions: &[crate::ffi::Nts],
) -> Result<vk::DeviceCreateInfo, ErrDeviceCreate> {
if !extensions.is_empty() {
let props = unsafe {
physical.instance.enumerate_device_extension_properties(**physical)?
};

ensure_properties(&props, extensions, |x| x.extension_name.as_ptr())?;
}

Ok(vk::DeviceCreateInfo {
enabled_extension_count: extensions.len() as u32,
pp_enabled_extension_names: extensions.as_ptr(),
..Default::default()
})
}

fn get_memory_type(
memory_props: vk::PhysicalDeviceMemoryProperties,
filter_flags: vk::MemoryPropertyFlags, filter_types: u32,
) -> Result<u32, ErrAllocMem> {
let count = memory_props.memory_type_count as usize;
let iter = memory_props.memory_types.iter().take(count).enumerate();

for (i, memory_type) in iter {
let has_flags = memory_type.property_flags.contains(filter_flags);
let has_types = filter_types & 1 << i;

if has_flags && has_types != 0 {
return Ok(i as u32);
}
}

Err(ErrAllocMem::NoMemoryType(filter_flags, filter_types))
}

impl Device {
pub fn create(
physical: Rc<PhysicalDevice>, qf_info: &QueueFamilyInfo,
) -> Result<Rc<Self>, ErrDeviceCreate> {
const QUEUE_PRIORITY: [f32; 1] = [1.0];

let queue_create_info = [
vk::DeviceQueueCreateInfo {
queue_family_index: qf_info.gfx_index,
queue_count: 1,
p_queue_priorities: QUEUE_PRIORITY.as_ptr(),
..Default::default()
},
vk::DeviceQueueCreateInfo {
queue_family_index: qf_info.srf_index,
queue_count: 1,
p_queue_priorities: QUEUE_PRIORITY.as_ptr(),
..Default::default()
},
];

let device_features = vk::PhysicalDeviceFeatures {
sampler_anisotropy: vk::TRUE,
..Default::default()
};

let extensions = [c_str!("VK_KHR_swapchain")];

let create_info = vk::DeviceCreateInfo {
queue_create_info_count: queue_create_info.len() as u32,
p_queue_create_infos: queue_create_info.as_ptr(),
p_enabled_features: &device_features,
..enable_device_extensions(&physical, &extensions)?
};

let handle = unsafe {
physical.instance.create_device(**physical, &create_info, None)?
};

let swapchain_ext = khr::Swapchain::new(&**physical.instance, &handle);

Ok(Rc::new(Self { handle, physical, swapchain_ext }))
}

pub fn alloc_mem(
&self, memory_reqs: vk::MemoryRequirements,
memory_flags: vk::MemoryPropertyFlags,
) -> Result<vk::DeviceMemory, ErrAllocMem> {
unsafe {
let memory_props = self
.physical
.instance
.get_physical_device_memory_properties(**self.physical);

let memory_type_index = get_memory_type(
memory_props,
memory_flags,
memory_reqs.memory_type_bits,
)?;

let allocate_info = vk::MemoryAllocateInfo {
memory_type_index,
allocation_size: memory_reqs.size,
..Default::default()
};

Ok(self.allocate_memory(&allocate_info, None)?)
}
}
}

impl PhysicalDevice {
pub fn get(
instance: Rc<Instance>, conf: &Conf,
) -> Result<Rc<Self>, ErrPhysicalDeviceGet> {
let devs = unsafe { instance.enumerate_physical_devices()? };

if conf.device < devs.len() {
let handle = devs[conf.device];
Ok(Rc::new(Self { handle, instance }))
} else {
Err(ErrPhysicalDeviceGet::NoDevice)
}
}
}

impl GetDevice for Rc<Device> {
fn get_device(&self) -> &Rc<Device> {
self
}
}

impl Drop for Device {
fn drop(&mut self) {
unsafe {
self.handle.destroy_device(None);
}
}
}

impl std::ops::Deref for Device {
type Target = ash::Device;
fn deref(&self) -> &Self::Target {
&self.handle
}
}

impl std::ops::Deref for PhysicalDevice {
type Target = vk::PhysicalDevice;
fn deref(&self) -> &Self::Target {
&self.handle
}
}

// EOF

+ 0
- 49
source/framework/render/fence.rs View File

@@ -1,49 +0,0 @@
use crate::render::{Device, GetDevice};
use ash::{version::DeviceV1_0, vk};
use std::rc::Rc;

pub struct Fence {
handle: vk::Fence,

pub device: Rc<Device>,
}

impl GetDevice for Fence {
fn get_device(&self) -> &Rc<Device> {
&self.device
}
}

impl Fence {
pub fn create(device: Rc<Device>) -> Result<Rc<Self>, vk::Result> {
let create_info = vk::FenceCreateInfo {
flags: vk::FenceCreateFlags::SIGNALED,
..Default::default()
};
let handle = unsafe { device.create_fence(&create_info, None)? };
Ok(Rc::new(Self { handle, device }))
}

pub fn create_all(
device: Rc<Device>, num: usize,
) -> Result<Vec<Rc<Self>>, vk::Result> {
(0..num).map(|_| Self::create(device.clone())).collect()
}
}

impl Drop for Fence {
fn drop(&mut self) {
unsafe {
self.get_device().destroy_fence(self.handle, None);
}
}
}

impl std::ops::Deref for Fence {
type Target = vk::Fence;
fn deref(&self) -> &Self::Target {
&self.handle
}
}

// EOF

+ 0
- 76
source/framework/render/framebuffer.rs View File

@@ -1,76 +0,0 @@
use crate::render::{Device, GetDevice, ImageView, RenderPass};
use ash::{version::DeviceV1_0, vk};
use std::rc::Rc;

pub struct Framebuffer {
handle: vk::Framebuffer,

pub render_pass: Rc<RenderPass>,
pub image_view: Rc<ImageView>,
pub depth_view: Rc<ImageView>,
}

impl GetDevice for Framebuffer {
fn get_device(&self) -> &Rc<Device> {
self.render_pass.get_device()
}
}

impl Framebuffer {
pub fn create(
render_pass: Rc<RenderPass>, image_view: Rc<ImageView>,
depth_view: Rc<ImageView>, image_extent: vk::Extent2D,
) -> Result<Rc<Self>, vk::Result> {
let attachments = [**image_view, **depth_view];

let create_info = vk::FramebufferCreateInfo {
render_pass: **render_pass,
attachment_count: attachments.len() as u32,
p_attachments: attachments.as_ptr(),
width: image_extent.width,
height: image_extent.height,
layers: 1,
..Default::default()
};

let handle = unsafe {
render_pass.get_device().create_framebuffer(&create_info, None)?
};

Ok(Rc::new(Self { handle, render_pass, image_view, depth_view }))
}

pub fn create_all(
render_pass: Rc<RenderPass>, image_views: &[Rc<ImageView>],
depth_view: Rc<ImageView>, extent: vk::Extent2D,
) -> Result<Vec<Rc<Self>>, vk::Result> {
image_views
.iter()
.map(|image_view| {
Self::create(
render_pass.clone(),
image_view.clone(),
depth_view.clone(),
extent,
)
})
.collect()
}
}

impl Drop for Framebuffer {
fn drop(&mut self) {
unsafe {
self.get_device().destroy_framebuffer(self.handle, None);
}
}
}

impl std::ops::Deref for Framebuffer {
type Target = vk::Framebuffer;
fn deref(&self) -> &Self::Target {
&self.handle
}
}

// EOF

+ 0
- 359
source/framework/render/image.rs View File

@@ -1,359 +0,0 @@
use crate::{
data::image::MipImage,
render::{
misc::dev_size_of, Buffer, CommandPool, Device, ErrAllocMem, GetDevice,
Swapchain,
},
};
use ash::{version::DeviceV1_0, vk};
use std::rc::Rc;

enum LayoutStage {
Xfer,
Dpth,
Frag,
}

pub struct ImageInfo {
pub extents: Vec<vk::Extent3D>,

pub imtype: vk::ImageType,
pub ivtype: vk::ImageViewType,
pub aspect: vk::ImageAspectFlags,
pub format: vk::Format,
pub usagef: vk::ImageUsageFlags,
}

pub struct OwnedImage {
handle: vk::Image,
info: ImageInfo,

pub swapchain: Rc<Swapchain>,
}

pub struct IndepImage {
handle: vk::Image,
memory: vk::DeviceMemory,
info: ImageInfo,

pub device: Rc<Device>,
}

pub enum Image {
Owned(OwnedImage),
Indep(IndepImage),
}

impl GetDevice for OwnedImage {
fn get_device(&self) -> &Rc<Device> {
self.swapchain.get_device()
}
}

impl GetDevice for IndepImage {
fn get_device(&self) -> &Rc<Device> {
&self.device
}
}

impl GetDevice for Image {
fn get_device(&self) -> &Rc<Device> {
match self {
| Self::Owned(image) => image.get_device(),
| Self::Indep(image) => image.get_device(),
}
}
}

impl OwnedImage {
pub fn own(swapchain: Rc<Swapchain>, handle: vk::Image) -> Self {
let info = ImageInfo {
extents: vec![vk::Extent3D {
width: swapchain.extent.width,
height: swapchain.extent.height,
depth: 1,
}],
aspect: vk::ImageAspectFlags::COLOR,
imtype: vk::ImageType::TYPE_2D,
ivtype: vk::ImageViewType::TYPE_2D,
format: swapchain.format,
usagef: vk::ImageUsageFlags::COLOR_ATTACHMENT,
};

Self { handle, info, swapchain }
}
}

impl ImageInfo {
fn create_info(&self) -> vk::ImageCreateInfo {
vk::ImageCreateInfo {
image_type: self.imtype,
format: self.format,
extent: self.extents[0],
mip_levels: self.extents.len() as u32,
array_layers: 1,
samples: vk::SampleCountFlags::TYPE_1,
tiling: vk::ImageTiling::OPTIMAL,
usage: self.usagef,
sharing_mode: vk::SharingMode::EXCLUSIVE,
initial_layout: vk::ImageLayout::UNDEFINED,
..Default::default()
}
}
}

impl IndepImage {
pub fn create(
cmd_pool: &CommandPool, mip: &MipImage,
) -> Result<Self, ErrAllocMem> {
let device = cmd_pool.get_device().clone();

let extents = mip
.data()
.iter()
.map(|level| vk::Extent3D {
width: level.w() as u32,
height: level.h() as u32,
depth: 1,
})
.collect();

let info = ImageInfo {
extents,
aspect: vk::ImageAspectFlags::COLOR,
imtype: vk::ImageType::TYPE_2D,
ivtype: vk::ImageViewType::TYPE_2D,
format: vk::Format::R8G8B8A8_UNORM,
usagef: vk::ImageUsageFlags::TRANSFER_DST
| vk::ImageUsageFlags::SAMPLED,
};

let create_info = info.create_info();

unsafe {
let handle = device.create_image(&create_info, None)?;

let memory = device.alloc_mem(
device.get_image_memory_requirements(handle),
vk::MemoryPropertyFlags::DEVICE_LOCAL,
)?;

device.bind_image_memory(handle, memory, 0)?;

let img = Self { handle, memory, info, device };

img.layout_barrier(cmd_pool, LayoutStage::Xfer)?;
img.copy_mips_to_image(cmd_pool, mip)?;
img.layout_barrier(cmd_pool, LayoutStage::Frag)?;

Ok(img)
}
}

pub fn create_depth(
cmd_pool: &CommandPool, width: u32, height: u32,
) -> Result<Self, ErrAllocMem> {
let device = cmd_pool.get_device().clone();

let info = ImageInfo {
extents: vec![vk::Extent3D { width, height, depth: 1 }],
aspect: vk::ImageAspectFlags::DEPTH | vk::ImageAspectFlags::STENCIL,
imtype: vk::ImageType::TYPE_2D,
ivtype: vk::ImageViewType::TYPE_2D,
format: vk::Format::D32_SFLOAT_S8_UINT,
usagef: vk::ImageUsageFlags::DEPTH_STENCIL_ATTACHMENT,
};

let create_info = info.create_info();

unsafe {
let handle = device.create_image(&create_info, None)?;

let memory = device.alloc_mem(
device.get_image_memory_requirements(handle),
vk::MemoryPropertyFlags::DEVICE_LOCAL,
)?;

device.bind_image_memory(handle, memory, 0)?;

let img = Self { handle, memory, info, device };

img.layout_barrier(cmd_pool, LayoutStage::Dpth)?;

Ok(img)
}
}

fn layout_barrier(
&self, cmd_pool: &CommandPool, layout_stage: LayoutStage,
) -> Result<(), vk::Result> {
let (
old_layout,
new_layout,
src_access_mask,
dst_access_mask,
src_stage,
dst_stage,
) = match layout_stage {
| LayoutStage::Xfer => (
vk::ImageLayout::UNDEFINED,
vk::ImageLayout::TRANSFER_DST_OPTIMAL,
vk::AccessFlags::empty(),
vk::AccessFlags::TRANSFER_WRITE,
vk::PipelineStageFlags::TOP_OF_PIPE,
vk::PipelineStageFlags::TRANSFER,
),
| LayoutStage::Dpth => (
vk::ImageLayout::UNDEFINED,
vk::ImageLayout::DEPTH_STENCIL_ATTACHMENT_OPTIMAL,
vk::AccessFlags::empty(),
vk::AccessFlags::DEPTH_STENCIL_ATTACHMENT_READ
| vk::AccessFlags::DEPTH_STENCIL_ATTACHMENT_WRITE,
vk::PipelineStageFlags::TOP_OF_PIPE,
vk::PipelineStageFlags::EARLY_FRAGMENT_TESTS,
),
| LayoutStage::Frag => (
vk::ImageLayout::TRANSFER_DST_OPTIMAL,
vk::ImageLayout::SHADER_READ_ONLY_OPTIMAL,
vk::AccessFlags::TRANSFER_WRITE,
vk::AccessFlags::SHADER_READ,
vk::PipelineStageFlags::TRANSFER,
vk::PipelineStageFlags::FRAGMENT_SHADER,
),
};

unsafe {
cmd_pool.with_transient_buffer(|cbuf| {
let barriers = [vk::ImageMemoryBarrier {
src_access_mask,
dst_access_mask,
old_layout,
new_layout,
src_queue_family_index: vk::QUEUE_FAMILY_IGNORED,
dst_queue_family_index: vk::QUEUE_FAMILY_IGNORED,
image: **self,
subresource_range: vk::ImageSubresourceRange {
aspect_mask: self.info.aspect,
base_mip_level: 0,
level_count: self.info.extents.len() as u32,
base_array_layer: 0,
layer_count: 1,
},
..Default::default()
}];

self.get_device().cmd_pipeline_barrier(
cbuf,
src_stage,
dst_stage,
vk::DependencyFlags::empty(),
&[],
&[],
&barriers,
);

Ok(())
})?;
}

Ok(())
}

fn copy_mips_to_image(
&self, cmd_pool: &CommandPool, mip: &MipImage,
) -> Result<(), ErrAllocMem> {
let buffer =
Buffer::create_image(cmd_pool.get_device().clone(), mip.data())?;

unsafe {
cmd_pool.with_transient_buffer(|cbuf| {
let mut image_copies = Vec::with_capacity(mip.levels());
let mut buffer_offset = 0;

for (mip_level, (&image_extent, img)) in
self.info.extents.iter().zip(mip.data()).enumerate()
{
image_copies.push(vk::BufferImageCopy {
buffer_offset,
buffer_row_length: 0,
buffer_image_height: 0,
image_subresource: vk::ImageSubresourceLayers {
aspect_mask: self.info.aspect,
mip_level: mip_level as u32,
base_array_layer: 0,
layer_count: 1,
},
image_offset: vk::Offset3D { x: 0, y: 0, z: 0 },
image_extent,
});

buffer_offset += dev_size_of(img.data());
}

self.get_device().cmd_copy_buffer_to_image(
cbuf,
**buffer,
**self,
vk::ImageLayout::TRANSFER_DST_OPTIMAL,
&image_copies,
);

Ok(())
})?;
}

Ok(())
}
}

impl Image {
pub fn from_owned(img: OwnedImage) -> Rc<Self> {
Rc::new(Self::Owned(img))
}

pub fn from_indep(img: IndepImage) -> Rc<Self> {
Rc::new(Self::Indep(img))
}

pub const fn info(&self) -> &ImageInfo {
match self {
| Self::Owned(image) => &image.info,
| Self::Indep(image) => &image.info,
}
}
}

impl Drop for IndepImage {
fn drop(&mut self) {
unsafe {
self.get_device().destroy_image(self.handle, None);
self.get_device().free_memory(self.memory, None);
}
}
}