2019-03-04 17:55:32 -05:00
|
|
|
// pathfinder/gpu/src/lib.rs
|
|
|
|
//
|
|
|
|
// Copyright © 2019 The Pathfinder Project Developers.
|
|
|
|
//
|
|
|
|
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
|
|
|
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
|
|
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
|
|
|
// option. This file may not be copied, modified, or distributed
|
|
|
|
// except according to those terms.
|
|
|
|
|
|
|
|
//! Minimal abstractions over GPU device capabilities.
|
|
|
|
|
2019-03-08 19:52:47 -05:00
|
|
|
use crate::resources::ResourceLoader;
|
|
|
|
use image::ImageFormat;
|
2019-03-04 17:55:32 -05:00
|
|
|
use pathfinder_geometry::basic::point::Point2DI32;
|
2019-03-13 19:32:39 -04:00
|
|
|
use pathfinder_geometry::basic::rect::RectI32;
|
2019-04-22 16:50:38 -04:00
|
|
|
use pathfinder_geometry::basic::transform3d::Transform3DF32;
|
|
|
|
use pathfinder_geometry::color::ColorF;
|
2019-03-04 17:55:32 -05:00
|
|
|
use pathfinder_simd::default::F32x4;
|
2019-03-19 00:40:10 -04:00
|
|
|
use rustache::HashBuilder;
|
2019-03-04 17:55:32 -05:00
|
|
|
use std::time::Duration;
|
|
|
|
|
2019-03-08 19:52:47 -05:00
|
|
|
pub mod resources;
|
|
|
|
|
2019-03-04 17:55:32 -05:00
|
|
|
pub trait Device {
|
|
|
|
type Buffer;
|
|
|
|
type Framebuffer;
|
|
|
|
type Program;
|
|
|
|
type Shader;
|
|
|
|
type Texture;
|
|
|
|
type TimerQuery;
|
|
|
|
type Uniform;
|
|
|
|
type VertexArray;
|
|
|
|
type VertexAttr;
|
|
|
|
|
|
|
|
fn create_texture(&self, format: TextureFormat, size: Point2DI32) -> Self::Texture;
|
|
|
|
fn create_texture_from_data(&self, size: Point2DI32, data: &[u8]) -> Self::Texture;
|
2019-04-29 19:57:56 -04:00
|
|
|
fn create_shader_from_source(
|
|
|
|
&self,
|
|
|
|
name: &str,
|
|
|
|
source: &[u8],
|
|
|
|
kind: ShaderKind,
|
|
|
|
template_input: HashBuilder,
|
|
|
|
) -> Self::Shader;
|
2019-03-04 17:55:32 -05:00
|
|
|
fn create_vertex_array(&self) -> Self::VertexArray;
|
2019-04-29 19:57:56 -04:00
|
|
|
fn create_program_from_shaders(
|
|
|
|
&self,
|
|
|
|
name: &str,
|
|
|
|
vertex_shader: Self::Shader,
|
|
|
|
fragment_shader: Self::Shader,
|
|
|
|
) -> Self::Program;
|
2019-03-04 17:55:32 -05:00
|
|
|
fn get_vertex_attr(&self, program: &Self::Program, name: &str) -> Self::VertexAttr;
|
|
|
|
fn get_uniform(&self, program: &Self::Program, name: &str) -> Self::Uniform;
|
|
|
|
fn use_program(&self, program: &Self::Program);
|
2019-04-29 19:57:56 -04:00
|
|
|
fn configure_float_vertex_attr(
|
|
|
|
&self,
|
|
|
|
attr: &Self::VertexAttr,
|
|
|
|
size: usize,
|
|
|
|
attr_type: VertexAttrType,
|
|
|
|
normalized: bool,
|
|
|
|
stride: usize,
|
|
|
|
offset: usize,
|
|
|
|
divisor: u32,
|
|
|
|
);
|
|
|
|
fn configure_int_vertex_attr(
|
|
|
|
&self,
|
|
|
|
attr: &Self::VertexAttr,
|
|
|
|
size: usize,
|
|
|
|
attr_type: VertexAttrType,
|
|
|
|
stride: usize,
|
|
|
|
offset: usize,
|
|
|
|
divisor: u32,
|
|
|
|
);
|
2019-03-04 17:55:32 -05:00
|
|
|
fn set_uniform(&self, uniform: &Self::Uniform, data: UniformData);
|
|
|
|
fn create_framebuffer(&self, texture: Self::Texture) -> Self::Framebuffer;
|
|
|
|
fn create_buffer(&self) -> Self::Buffer;
|
2019-04-29 19:57:56 -04:00
|
|
|
fn allocate_buffer<T>(
|
|
|
|
&self,
|
|
|
|
buffer: &Self::Buffer,
|
|
|
|
data: BufferData<T>,
|
|
|
|
target: BufferTarget,
|
|
|
|
mode: BufferUploadMode,
|
|
|
|
);
|
2019-03-04 17:55:32 -05:00
|
|
|
fn framebuffer_texture<'f>(&self, framebuffer: &'f Self::Framebuffer) -> &'f Self::Texture;
|
|
|
|
fn texture_size(&self, texture: &Self::Texture) -> Point2DI32;
|
|
|
|
fn upload_to_texture(&self, texture: &Self::Texture, size: Point2DI32, data: &[u8]);
|
|
|
|
fn read_pixels_from_default_framebuffer(&self, size: Point2DI32) -> Vec<u8>;
|
2019-04-22 16:50:38 -04:00
|
|
|
fn clear(&self, params: &ClearParams);
|
2019-03-04 17:55:32 -05:00
|
|
|
fn draw_arrays(&self, primitive: Primitive, index_count: u32, render_state: &RenderState);
|
|
|
|
fn draw_elements(&self, primitive: Primitive, index_count: u32, render_state: &RenderState);
|
2019-04-29 19:57:56 -04:00
|
|
|
fn draw_arrays_instanced(
|
|
|
|
&self,
|
|
|
|
primitive: Primitive,
|
|
|
|
index_count: u32,
|
|
|
|
instance_count: u32,
|
|
|
|
render_state: &RenderState,
|
|
|
|
);
|
2019-03-04 17:55:32 -05:00
|
|
|
fn create_timer_query(&self) -> Self::TimerQuery;
|
|
|
|
fn begin_timer_query(&self, query: &Self::TimerQuery);
|
|
|
|
fn end_timer_query(&self, query: &Self::TimerQuery);
|
|
|
|
fn timer_query_is_available(&self, query: &Self::TimerQuery) -> bool;
|
|
|
|
fn get_timer_query(&self, query: &Self::TimerQuery) -> Duration;
|
|
|
|
|
|
|
|
// TODO(pcwalton): Go bindless...
|
|
|
|
fn bind_vertex_array(&self, vertex_array: &Self::VertexArray);
|
|
|
|
fn bind_buffer(&self, buffer: &Self::Buffer, target: BufferTarget);
|
2019-03-13 19:32:39 -04:00
|
|
|
fn bind_default_framebuffer(&self, viewport: RectI32);
|
2019-03-04 17:55:32 -05:00
|
|
|
fn bind_framebuffer(&self, framebuffer: &Self::Framebuffer);
|
|
|
|
fn bind_texture(&self, texture: &Self::Texture, unit: u32);
|
|
|
|
|
2019-04-29 19:57:56 -04:00
|
|
|
fn create_texture_from_png(&self, resources: &dyn ResourceLoader, name: &str) -> Self::Texture {
|
2019-03-08 19:52:47 -05:00
|
|
|
let data = resources.slurp(&format!("textures/{}.png", name)).unwrap();
|
2019-04-29 19:57:56 -04:00
|
|
|
let image = image::load_from_memory_with_format(&data, ImageFormat::PNG)
|
|
|
|
.unwrap()
|
|
|
|
.to_luma();
|
2019-03-04 17:55:32 -05:00
|
|
|
let size = Point2DI32::new(image.width() as i32, image.height() as i32);
|
|
|
|
self.create_texture_from_data(size, &image)
|
|
|
|
}
|
|
|
|
|
2019-04-29 19:57:56 -04:00
|
|
|
fn create_shader(
|
|
|
|
&self,
|
|
|
|
resources: &dyn ResourceLoader,
|
|
|
|
name: &str,
|
|
|
|
kind: ShaderKind,
|
|
|
|
) -> Self::Shader {
|
|
|
|
let suffix = match kind {
|
|
|
|
ShaderKind::Vertex => 'v',
|
|
|
|
ShaderKind::Fragment => 'f',
|
|
|
|
};
|
|
|
|
let source = resources
|
|
|
|
.slurp(&format!("shaders/{}.{}s.glsl", name, suffix))
|
|
|
|
.unwrap();
|
2019-03-19 00:40:10 -04:00
|
|
|
|
2019-03-22 17:28:18 -04:00
|
|
|
let mut load_include_tile_alpha_vertex =
|
|
|
|
|_| load_shader_include(resources, "tile_alpha_vertex");
|
|
|
|
let mut load_include_tile_monochrome =
|
|
|
|
|_| load_shader_include(resources, "tile_monochrome");
|
|
|
|
let mut load_include_tile_multicolor =
|
|
|
|
|_| load_shader_include(resources, "tile_multicolor");
|
|
|
|
let mut load_include_tile_solid_vertex =
|
|
|
|
|_| load_shader_include(resources, "tile_solid_vertex");
|
2019-03-19 00:40:10 -04:00
|
|
|
let mut load_include_post_convolve = |_| load_shader_include(resources, "post_convolve");
|
|
|
|
let mut load_include_post_gamma_correct =
|
|
|
|
|_| load_shader_include(resources, "post_gamma_correct");
|
2019-04-29 19:57:56 -04:00
|
|
|
let template_input = HashBuilder::new()
|
|
|
|
.insert_lambda(
|
|
|
|
"include_tile_alpha_vertex",
|
|
|
|
&mut load_include_tile_alpha_vertex,
|
|
|
|
)
|
|
|
|
.insert_lambda("include_tile_monochrome", &mut load_include_tile_monochrome)
|
|
|
|
.insert_lambda("include_tile_multicolor", &mut load_include_tile_multicolor)
|
|
|
|
.insert_lambda(
|
|
|
|
"include_tile_solid_vertex",
|
|
|
|
&mut load_include_tile_solid_vertex,
|
|
|
|
)
|
|
|
|
.insert_lambda("include_post_convolve", &mut load_include_post_convolve)
|
|
|
|
.insert_lambda(
|
|
|
|
"include_post_gamma_correct",
|
|
|
|
&mut load_include_post_gamma_correct,
|
|
|
|
);
|
2019-03-19 00:40:10 -04:00
|
|
|
|
|
|
|
self.create_shader_from_source(name, &source, kind, template_input)
|
2019-03-04 17:55:32 -05:00
|
|
|
}
|
|
|
|
|
2019-04-29 19:57:56 -04:00
|
|
|
fn create_program_from_shader_names(
|
|
|
|
&self,
|
|
|
|
resources: &dyn ResourceLoader,
|
|
|
|
program_name: &str,
|
|
|
|
vertex_shader_name: &str,
|
|
|
|
fragment_shader_name: &str,
|
|
|
|
) -> Self::Program {
|
2019-03-22 17:28:18 -04:00
|
|
|
let vertex_shader = self.create_shader(resources, vertex_shader_name, ShaderKind::Vertex);
|
2019-04-29 19:57:56 -04:00
|
|
|
let fragment_shader =
|
|
|
|
self.create_shader(resources, fragment_shader_name, ShaderKind::Fragment);
|
2019-03-22 17:28:18 -04:00
|
|
|
self.create_program_from_shaders(program_name, vertex_shader, fragment_shader)
|
|
|
|
}
|
|
|
|
|
2019-03-08 19:52:47 -05:00
|
|
|
fn create_program(&self, resources: &dyn ResourceLoader, name: &str) -> Self::Program {
|
2019-03-22 17:28:18 -04:00
|
|
|
self.create_program_from_shader_names(resources, name, name, name)
|
2019-03-04 17:55:32 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Clone, Copy, Debug)]
|
|
|
|
pub enum TextureFormat {
|
2019-03-22 17:28:18 -04:00
|
|
|
R8,
|
2019-03-04 17:55:32 -05:00
|
|
|
R16F,
|
|
|
|
RGBA8,
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Clone, Copy, Debug)]
|
|
|
|
pub enum VertexAttrType {
|
|
|
|
F32,
|
|
|
|
I16,
|
2019-04-15 16:21:24 -04:00
|
|
|
I8,
|
2019-03-04 17:55:32 -05:00
|
|
|
U16,
|
|
|
|
U8,
|
|
|
|
}
|
|
|
|
|
2019-04-15 16:21:24 -04:00
|
|
|
#[derive(Clone, Copy, Debug)]
|
|
|
|
pub enum BufferData<'a, T> {
|
|
|
|
Uninitialized(usize),
|
|
|
|
Memory(&'a [T]),
|
|
|
|
}
|
|
|
|
|
2019-03-04 17:55:32 -05:00
|
|
|
#[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 {
|
2019-03-25 19:13:56 -04:00
|
|
|
Int(i32),
|
2019-04-22 16:50:38 -04:00
|
|
|
Mat2(F32x4),
|
2019-03-05 16:57:28 -05:00
|
|
|
Mat4([F32x4; 4]),
|
2019-03-04 17:55:32 -05:00
|
|
|
Vec2(F32x4),
|
|
|
|
Vec4(F32x4),
|
|
|
|
TextureUnit(u32),
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Clone, Copy)]
|
|
|
|
pub enum Primitive {
|
|
|
|
Triangles,
|
|
|
|
TriangleFan,
|
|
|
|
Lines,
|
|
|
|
}
|
|
|
|
|
2019-04-22 16:50:38 -04:00
|
|
|
#[derive(Clone, Copy, Default)]
|
|
|
|
pub struct ClearParams {
|
|
|
|
pub color: Option<ColorF>,
|
|
|
|
pub rect: Option<RectI32>,
|
|
|
|
pub depth: Option<f32>,
|
|
|
|
pub stencil: Option<u8>,
|
|
|
|
}
|
|
|
|
|
2019-03-05 16:22:11 -05:00
|
|
|
#[derive(Clone, Debug)]
|
2019-03-04 17:55:32 -05:00
|
|
|
pub struct RenderState {
|
|
|
|
pub blend: BlendState,
|
|
|
|
pub depth: Option<DepthState>,
|
|
|
|
pub stencil: Option<StencilState>,
|
|
|
|
pub color_mask: bool,
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Clone, Copy, Debug)]
|
|
|
|
pub enum BlendState {
|
|
|
|
Off,
|
|
|
|
RGBOneAlphaOne,
|
2019-03-05 16:22:11 -05:00
|
|
|
RGBOneAlphaOneMinusSrcAlpha,
|
|
|
|
RGBSrcAlphaAlphaOneMinusSrcAlpha,
|
2019-03-04 17:55:32 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
#[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,
|
2019-03-05 16:22:11 -05:00
|
|
|
pub write: bool,
|
2019-03-04 17:55:32 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Clone, Copy, Debug)]
|
|
|
|
pub enum StencilFunc {
|
|
|
|
Always,
|
|
|
|
Equal,
|
|
|
|
NotEqual,
|
|
|
|
}
|
|
|
|
|
2019-03-05 16:22:11 -05:00
|
|
|
impl Default for RenderState {
|
|
|
|
#[inline]
|
|
|
|
fn default() -> RenderState {
|
2019-04-29 19:57:56 -04:00
|
|
|
RenderState {
|
|
|
|
blend: BlendState::default(),
|
|
|
|
depth: None,
|
|
|
|
stencil: None,
|
|
|
|
color_mask: true,
|
|
|
|
}
|
2019-03-05 16:22:11 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-03-04 17:55:32 -05:00
|
|
|
impl Default for BlendState {
|
|
|
|
#[inline]
|
|
|
|
fn default() -> BlendState {
|
|
|
|
BlendState::Off
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Default for StencilState {
|
|
|
|
#[inline]
|
|
|
|
fn default() -> StencilState {
|
2019-04-29 19:57:56 -04:00
|
|
|
StencilState {
|
|
|
|
func: StencilFunc::default(),
|
|
|
|
reference: 0,
|
|
|
|
mask: !0,
|
|
|
|
write: false,
|
|
|
|
}
|
2019-03-04 17:55:32 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Default for DepthFunc {
|
|
|
|
#[inline]
|
|
|
|
fn default() -> DepthFunc {
|
|
|
|
DepthFunc::Less
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Default for StencilFunc {
|
|
|
|
#[inline]
|
|
|
|
fn default() -> StencilFunc {
|
|
|
|
StencilFunc::Always
|
|
|
|
}
|
|
|
|
}
|
2019-03-19 00:40:10 -04:00
|
|
|
|
2019-04-22 16:50:38 -04:00
|
|
|
impl UniformData {
|
|
|
|
#[inline]
|
|
|
|
pub fn from_transform_3d(transform: &Transform3DF32) -> UniformData {
|
|
|
|
UniformData::Mat4([transform.c0, transform.c1, transform.c2, transform.c3])
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-03-19 00:40:10 -04:00
|
|
|
fn load_shader_include(resources: &dyn ResourceLoader, include_name: &str) -> String {
|
2019-04-29 19:57:56 -04:00
|
|
|
let resource = resources
|
|
|
|
.slurp(&format!("shaders/{}.inc.glsl", include_name))
|
|
|
|
.unwrap();
|
2019-03-19 00:40:10 -04:00
|
|
|
String::from_utf8_lossy(&resource).to_string()
|
|
|
|
}
|