Content-Type: text/x-zim-wiki
Wiki-Format: zim 0.4
Creation-Date: 2020-02-28T22:36:46-08:00

====== PossiblePathfinderPort ======
Created Friday 28 February 2020

So I'm just going to use this space to talk about hooking up vulkano to this backend.
All in all, this seems somewhat simple. This backend expects you to define a dozen or so types which are then passed around and manipulated using this interface.



==== Where I am at currently ====

So I need to figure out how pathfinder is creating and storing the framebuffers. 









RuntimeVertexDef {
	buffers: buffers,
	vertex_buffer_ids: vertex_buffer_ids,
	num_vertices: num_vertices,
	attributes: attributes,
}

buffers [
	(position, size, InputRate::Vertex)
	(position, size, InputRate::Vertex)
	(position, size, InputRate::Vertex)
]

vertex_buffer_ids [
	start and end addresses of buffers?
]

num_vertices : usize

attributes [
	("attribute_name1", position, Format::R32G32Sfloat)
	("attribute_name2", position, Format::R32G32Sfloat)
	("attribute_name3", position, Format::R32G32Sfloat)
]


vertex shader input

attrib loc, buffer id

0,0	rgb
1,1	rgb
2,0	rgba
3,2	rg
4,0 	rg
5,0	rgba
6,0	rgba
7,0	rgba

layout(location = 0) in vec3 i_position;
layout(location = 1) in vec3 i_normal;
layout(location = 2) in vec4 i_tangent;
layout(location = 3) in vec2 i_texcoord_0;
layout(location = 4) in vec2 i_texcoord_1;
layout(location = 5) in vec4 i_color_0;
layout(location = 6) in vec4 i_joints_0;
layout(location = 7) in vec4 i_weights_0;


pub struct RenderState<'a, D> where D: Device 
	pub target: &'a RenderTarget<'a, D>,
	pub program: &'a D::Program,
	pub vertex_array: &'a D::VertexArray,
	pub primitive: Primitive,
	pub uniforms: &'a [(&'a D::Uniform, UniformData)],
	pub textures: &'a [&'a D::Texture],
	pub viewport: RectI,
	pub options: RenderOptions,


**So I need to define the following types in Vulkan syntax**

**The other port uses container classes for these **


	type Buffer;
	type Framebuffer;
	type Program;
		**VulkanProgram**
	type Shader;
	type Texture;
	type TextureDataReceiver;
	type TimerQuery;
	type Uniform;
	type VertexArray;
	type VertexAttr;
 

	
	[*] fn create_texture(&self, format: TextureFormat, size: Vector2I) -> Self::Texture;

	[*] fn create_texture_from_data(&self, 
		format: TextureFormat, 
		size: Vector2I, 
		data: TextureDataRef
		) -> Self::Texture;

	**For now I'm going to create just the shader and not the pipeline**
	[*] fn create_shader(&self, 
		resources: &dyn ResourceLoader, 
		name: &str, 
		kind: ShaderKind)
			 -> Self::Shader;
	
	
	[*] fn create_shader_from_source(&self, 
		name: &str, 
		source: &[u8], 
		kind: ShaderKind) -> Self::Shader;
	

	**This seems to just return a container, but what is the type of the container?**
	[ ] fn create_vertex_array(&self) -> Self::VertexArray;
	
	**This means more in GL as a program is a part of the state machine**
	**In vk and metal this just returns the two shaders in one object**
	[*] fn create_program_from_shaders(
		&self,
		resources: &dyn ResourceLoader,
		name: &str,
		vertex_shader: Self::Shader,
		fragment_shader: Self::Shader,
	) -> Self::Program;
	
	**This one I'm a little shakey on. Where do I get these attributes?**
	[ ] fn get_vertex_attr(&self, program: &Self::Program, name: &str) -> Option<Self::VertexAttr>;
	
	**This first bind_vertex_array()'s **
	**Then it appears to set the instancing using the descriptor and divisor?**
	**Then it configures the vertex attributes for the state. it's push pop it seems in gl**
	fn configure_vertex_attr(&self,
							 vertex_array: &Self::VertexArray,
							 attr: &Self::VertexAttr,
			   descriptor: &VertexAttrDescriptor);

	**This function just looks up the uniform using the name**
	[ ] fn get_uniform(&self, program: &Self::Program, name: &str) -> Self::Uniform;
	
	**Probably just allocating a buffer with data. Target is just usage**
	**See that it passes in a borrow for Buffer, I assume we should do an**
	**uninitialized_buffer type of deal**
	
	**Revising this : In GL all it is doing is assigning the buffer to an index in an array**
	**Probably should do like metal and emulate it (Ended up taking metal impl!)**
	[*] fn bind_buffer(&self,
				   vertex_array: &Self::VertexArray,
				   buffer: &Self::Buffer, 
				   target: BufferTarget);
	

	
	**This creates the framebuffer using render_pass**
		**Since it's single-frame. We don't use the swapchain**
	fn create_framebuffer(&self, texture: Self::Texture) -> Self::Framebuffer;
	
	**This just creates an empty buffer **
	fn create_buffer(&self) -> Self::Buffer;
	
	**Allocates using an empty buffer. target is buffer_usage**
	fn allocate_buffer<T>(
		&self,
		buffer: &Self::Buffer,
		data: BufferData<T>,
		target: BufferTarget,
		mode: BufferUploadMode,
	);
	fn framebuffer_texture<'f>(&self, framebuffer: &'f Self::Framebuffer) -> &'f Self::Texture;
	fn destroy_framebuffer(&self, framebuffer: Self::Framebuffer) -> Self::Texture;
	fn texture_format(&self, texture: &Self::Texture) -> TextureFormat;
	fn texture_size(&self, texture: &Self::Texture) -> Vector2I;
	fn set_texture_sampling_mode(&self, texture: &Self::Texture, flags: TextureSamplingFlags);
	fn upload_to_texture(&self, texture: &Self::Texture, rect: RectI, data: TextureDataRef);

	**Command buffer stuff**
	fn begin_commands(&self);
	fn end_commands(&self);
	
	
	fn draw_arrays(&self, index_count: u32, render_state: &RenderState<Self>);
	fn draw_elements(&self, index_count: u32, render_state: &RenderState<Self>);
	fn draw_elements_instanced(&self,
							   index_count: u32,
							   instance_count: u32,
							   render_state: &RenderState<Self>);
							
	**This is the weird timing stuff**
	fn create_timer_query(&self) -> Self::TimerQuery;
	fn begin_timer_query(&self, query: &Self::TimerQuery);
	fn end_timer_query(&self, query: &Self::TimerQuery);
	fn try_recv_timer_query(&self, query: &Self::TimerQuery) -> Option<Duration>;
	fn recv_timer_query(&self, query: &Self::TimerQuery) -> Duration;

	**And then the GPU reads**
	fn try_recv_texture_data(&self, receiver: &Self::TextureDataReceiver) -> Option<TextureData>;
	fn recv_texture_data(&self, receiver: &Self::TextureDataReceiver) -> TextureData;
    
	**This maybe reads?**
	fn read_pixels(&self, target: &RenderTarget<Self>, viewport: RectI)
				   -> Self::TextureDataReceiver;
	
	**This just creates a texture like I do**
	fn create_texture_from_png(&self, resources: &dyn ResourceLoader, name: &str) -> Self::Texture;

	**This one just **
	fn create_program_from_shader_names(
		&self,
		resources: &dyn ResourceLoader,
		program_name: &str,
		vertex_shader_name: &str,
		fragment_shader_name: &str,
	) -> Self::Program {
		let vertex_shader = self.create_shader(resources, vertex_shader_name, ShaderKind::Vertex);
		let fragment_shader =
			self.create_shader(resources, fragment_shader_name, ShaderKind::Fragment);
		self.create_program_from_shaders(resources, program_name, vertex_shader, fragment_shader)
	}

	fn create_program(&self, resources: &dyn ResourceLoader, name: &str) -> Self::Program {
		self.create_program_from_shader_names(resources, name, name, name)
	}
}

#[derive(Clone, Copy, Debug, PartialEq)]
pub enum TextureFormat {
	R8,
	R16F,
	RGBA8,
	RGBA16F,
	RGBA32F,
}

#[derive(Clone, Copy, Debug)]
pub enum VertexAttrType {
	F32,
	I16,
	I8,
	U16,
	U8,
}

#[derive(Clone, Copy, Debug)]
pub enum BufferData<'a, T> {
	Uninitialized(usize),
	Memory(&'a [T]),
}

#[derive(Clone, Copy, Debug)]
pub enum BufferTarget {
	Vertex,
	Index,
}

#[derive(Clone, Copy, Debug)]
pub enum BufferUploadMode {
	Static,
	Dynamic,
}

#[derive(Clone, Copy, Debug, PartialEq)]
pub enum ShaderKind {
	Vertex,
	Fragment,
}

#[derive(Clone, Copy)]
pub enum UniformData {
	Float(f32),
	IVec3([i32; 3]),
	Int(i32),
	Mat2(F32x4),
	Mat4([F32x4; 4]),
	Vec2(F32x2),
	Vec3([f32; 3]),
	Vec4(F32x4),
	TextureUnit(u32),
}

#[derive(Clone, Copy)]
pub enum Primitive {
	Triangles,
	Lines,
}

#[derive(Clone)]
pub struct RenderState<'a, D> where D: Device {
	pub target: &'a RenderTarget<'a, D>,
	pub program: &'a D::Program,
	pub vertex_array: &'a D::VertexArray,
	pub primitive: Primitive,
	pub uniforms: &'a [(&'a D::Uniform, UniformData)],
	pub textures: &'a [&'a D::Texture],
	pub viewport: RectI,
	pub options: RenderOptions,
}

#[derive(Clone, Debug)]
pub struct RenderOptions {
	pub blend: Option<BlendState>,
	pub depth: Option<DepthState>,
	pub stencil: Option<StencilState>,
	pub clear_ops: ClearOps,
	pub color_mask: bool,
}

#[derive(Clone, Copy, Debug, Default)]
pub struct ClearOps {
	pub color: Option<ColorF>,
	pub depth: Option<f32>,
	pub stencil: Option<u8>,
}

#[derive(Clone, Copy, Debug)]
pub enum RenderTarget<'a, D> where D: Device {
	Default,
	Framebuffer(&'a D::Framebuffer),
}

#[derive(Clone, Copy, Debug, PartialEq)]
pub struct BlendState {
	pub dest_rgb_factor: BlendFactor,
	pub dest_alpha_factor: BlendFactor,
	pub src_rgb_factor: BlendFactor,
	pub src_alpha_factor: BlendFactor,
	pub op: BlendOp,
}

#[derive(Clone, Copy, Debug, PartialEq)]
pub enum BlendFactor {
	Zero,
	One,
	SrcAlpha,
	OneMinusSrcAlpha,
	DestAlpha,
	OneMinusDestAlpha,
	DestColor,
}

#[derive(Clone, Copy, Debug, PartialEq)]
pub enum BlendOp {
	Add,
	Subtract,
	ReverseSubtract,
	Min,
	Max,
}

#[derive(Clone, Copy, Default, Debug)]
pub struct DepthState {
	pub func: DepthFunc,
	pub write: bool,
}

#[derive(Clone, Copy, Debug)]
pub enum DepthFunc {
	Less,
	Always,
}

#[derive(Clone, Copy, Debug)]
pub struct StencilState {
	pub func: StencilFunc,
	pub reference: u32,
	pub mask: u32,
	pub write: bool,
}

#[derive(Clone, Copy, Debug)]
pub enum StencilFunc {
	Always,
	Equal,
}

impl Default for RenderOptions {
	#[inline]
	fn default() -> RenderOptions {
		RenderOptions {
			blend: None,
			depth: None,
			stencil: None,
			clear_ops: ClearOps::default(),
			color_mask: true,
		}
	}
}

impl Default for BlendOp {
	#[inline]
	fn default() -> BlendOp {
		BlendOp::Add
	}
}

impl Default for StencilState {
	#[inline]
	fn default() -> StencilState {
		StencilState {
			func: StencilFunc::default(),
			reference: 0,
			mask: !0,
			write: false,
		}
	}
}

impl Default for DepthFunc {
	#[inline]
	fn default() -> DepthFunc {
		DepthFunc::Less
	}
}

impl Default for StencilFunc {
	#[inline]
	fn default() -> StencilFunc {
		StencilFunc::Always
	}
}

#[derive(Clone, Debug)]
pub enum TextureData {
	U8(Vec<u8>),
	U16(Vec<u16>),
	F16(Vec<f16>),
	F32(Vec<f32>),
}

#[derive(Clone, Copy, Debug)]
pub enum TextureDataRef<'a> {
	U8(&'a [u8]),
	F16(&'a [f16]),
	F32(&'a [f32]),
}

impl UniformData {
	#[inline]
	pub fn from_transform_3d(transform: &Transform4F) -> UniformData {
		UniformData::Mat4([transform.c0, transform.c1, transform.c2, transform.c3])
	}
}

#[derive(Clone, Copy, Debug)]
pub struct VertexAttrDescriptor {
	pub size: usize,
	pub class: VertexAttrClass,
	pub attr_type: VertexAttrType,
	pub stride: usize,
	pub offset: usize,
	pub divisor: u32,
	pub buffer_index: u32,
}

#[derive(Clone, Copy, Debug, PartialEq)]
pub enum VertexAttrClass {
	Float,
	FloatNorm,
	Int,
}

impl TextureFormat {
	#[inline]
	pub fn channels(self) -> usize {
		match self {
			TextureFormat::R8 | TextureFormat::R16F => 1,
			TextureFormat::RGBA8 | TextureFormat::RGBA16F | TextureFormat::RGBA32F => 4,
		}
	}

	#[inline]
	pub fn bytes_per_pixel(self) -> usize {
		match self {
			TextureFormat::R8 => 1,
			TextureFormat::R16F => 2,
			TextureFormat::RGBA8 => 4,
			TextureFormat::RGBA16F => 8,
			TextureFormat::RGBA32F => 16,
		}
	}
}

impl ClearOps {
	#[inline]
	pub fn has_ops(&self) -> bool {
		self.color.is_some() || self.depth.is_some() || self.stencil.is_some()
	}
}

impl Default for BlendState {
	#[inline]
	fn default() -> BlendState {
		BlendState {
			src_rgb_factor: BlendFactor::One,
			dest_rgb_factor: BlendFactor::OneMinusSrcAlpha,
			src_alpha_factor: BlendFactor::One,
			dest_alpha_factor: BlendFactor::One,
			op: BlendOp::Add,
		}
	}
}

bitflags! {
	pub struct TextureSamplingFlags: u8 {
		const REPEAT_U    = 0x01;
		const REPEAT_V    = 0x02;
		const NEAREST_MIN = 0x04;
		const NEAREST_MAG = 0x08;
	}
}

impl<'a> TextureDataRef<'a> {
	#[doc(hidden)]
	pub fn check_and_extract_data_ptr(self, minimum_size: Vector2I, format: TextureFormat)
									  -> *const c_void {
		let channels = match (format, self) {
			(TextureFormat::R8, TextureDataRef::U8(_)) => 1,
			(TextureFormat::RGBA8, TextureDataRef::U8(_)) => 4,
			(TextureFormat::RGBA16F, TextureDataRef::F16(_)) => 4,
			(TextureFormat::RGBA32F, TextureDataRef::F32(_)) => 4,
			_ => panic!("Unimplemented texture format!"),
		};

		let area = minimum_size.x() as usize * minimum_size.y() as usize;

		match self {
			TextureDataRef::U8(data) => {
				assert!(data.len() >= area * channels);
				data.as_ptr() as *const c_void
			}
			TextureDataRef::F16(data) => {
				assert!(data.len() >= area * channels);
				data.as_ptr() as *const c_void
			}
			TextureDataRef::F32(data) => {
				assert!(data.len() >= area * channels);
				data.as_ptr() as *const c_void
			}
		}
	}
}
