Factor out the GL rendering code into a separate crate
This commit is contained in:
parent
b6432fa47d
commit
dd480feb52
|
@ -162,16 +162,13 @@ dependencies = [
|
||||||
"clap 2.32.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"clap 2.32.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"euclid 0.19.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
"euclid 0.19.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"gl 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
"gl 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"image 0.21.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
|
||||||
"jemallocator 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
"jemallocator 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"pathfinder_geometry 0.3.0",
|
"pathfinder_geometry 0.3.0",
|
||||||
|
"pathfinder_gl 0.1.0",
|
||||||
"pathfinder_renderer 0.1.0",
|
"pathfinder_renderer 0.1.0",
|
||||||
"pathfinder_svg 0.1.0",
|
"pathfinder_svg 0.1.0",
|
||||||
"rayon 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
"rayon 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"sdl2 0.32.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
"sdl2 0.32.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"serde 1.0.84 (registry+https://github.com/rust-lang/crates.io-index)",
|
|
||||||
"serde_derive 1.0.84 (registry+https://github.com/rust-lang/crates.io-index)",
|
|
||||||
"serde_json 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)",
|
|
||||||
"usvg 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"usvg 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -531,6 +528,20 @@ dependencies = [
|
||||||
"euclid 0.19.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
"euclid 0.19.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "pathfinder_gl"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"euclid 0.19.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"gl 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"image 0.21.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"pathfinder_geometry 0.3.0",
|
||||||
|
"pathfinder_renderer 0.1.0",
|
||||||
|
"serde 1.0.84 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"serde_derive 1.0.84 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"serde_json 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "pathfinder_renderer"
|
name = "pathfinder_renderer"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
|
|
|
@ -3,6 +3,7 @@ members = [
|
||||||
"demo3",
|
"demo3",
|
||||||
"geometry",
|
"geometry",
|
||||||
"gfx-utils",
|
"gfx-utils",
|
||||||
|
"gl",
|
||||||
"renderer",
|
"renderer",
|
||||||
"svg",
|
"svg",
|
||||||
"utils/area-lut",
|
"utils/area-lut",
|
||||||
|
|
|
@ -11,19 +11,14 @@ gl = "0.6"
|
||||||
jemallocator = "0.1"
|
jemallocator = "0.1"
|
||||||
rayon = "1.0"
|
rayon = "1.0"
|
||||||
sdl2 = "0.32"
|
sdl2 = "0.32"
|
||||||
serde = "1.0"
|
|
||||||
serde_derive = "1.0"
|
|
||||||
serde_json = "1.0"
|
|
||||||
usvg = "0.4"
|
usvg = "0.4"
|
||||||
|
|
||||||
[dependencies.image]
|
|
||||||
version = "0.21"
|
|
||||||
default-features = false
|
|
||||||
features = ["png_codec"]
|
|
||||||
|
|
||||||
[dependencies.pathfinder_geometry]
|
[dependencies.pathfinder_geometry]
|
||||||
path = "../geometry"
|
path = "../geometry"
|
||||||
|
|
||||||
|
[dependencies.pathfinder_gl]
|
||||||
|
path = "../gl"
|
||||||
|
|
||||||
[dependencies.pathfinder_renderer]
|
[dependencies.pathfinder_renderer]
|
||||||
path = "../renderer"
|
path = "../renderer"
|
||||||
|
|
||||||
|
|
|
@ -8,57 +8,32 @@
|
||||||
// option. This file may not be copied, modified, or distributed
|
// option. This file may not be copied, modified, or distributed
|
||||||
// except according to those terms.
|
// except according to those terms.
|
||||||
|
|
||||||
#[macro_use]
|
|
||||||
extern crate serde_derive;
|
|
||||||
|
|
||||||
use crate::debug_text::DebugRenderer;
|
|
||||||
use crate::device::{Buffer, BufferTarget, BufferUploadMode, Framebuffer, Program, Texture};
|
|
||||||
use crate::device::{TimerQuery, Uniform, VertexAttr};
|
|
||||||
use clap::{App, Arg};
|
use clap::{App, Arg};
|
||||||
use euclid::{Point2D, Rect, Size2D};
|
use euclid::{Point2D, Rect, Size2D};
|
||||||
use gl::types::{GLfloat, GLint, GLuint};
|
|
||||||
use jemallocator;
|
use jemallocator;
|
||||||
use pathfinder_geometry::point::Point4DF32;
|
use pathfinder_geometry::point::Point4DF32;
|
||||||
use pathfinder_geometry::transform3d::{Perspective, Transform3DF32};
|
use pathfinder_geometry::transform3d::{Perspective, Transform3DF32};
|
||||||
|
use pathfinder_gl::renderer::Renderer;
|
||||||
use pathfinder_renderer::builder::SceneBuilder;
|
use pathfinder_renderer::builder::SceneBuilder;
|
||||||
use pathfinder_renderer::gpu_data::{Batch, BuiltScene, SolidTileScenePrimitive};
|
use pathfinder_renderer::gpu_data::BuiltScene;
|
||||||
use pathfinder_renderer::paint::ObjectShader;
|
|
||||||
use pathfinder_renderer::scene::Scene;
|
use pathfinder_renderer::scene::Scene;
|
||||||
use pathfinder_renderer::tiles::{TILE_HEIGHT, TILE_WIDTH};
|
|
||||||
use pathfinder_renderer::z_buffer::ZBuffer;
|
use pathfinder_renderer::z_buffer::ZBuffer;
|
||||||
use pathfinder_svg::SceneExt;
|
use pathfinder_svg::SceneExt;
|
||||||
use rayon::ThreadPoolBuilder;
|
use rayon::ThreadPoolBuilder;
|
||||||
use sdl2::event::Event;
|
use sdl2::event::Event;
|
||||||
use sdl2::keyboard::Keycode;
|
use sdl2::keyboard::Keycode;
|
||||||
use sdl2::video::GLProfile;
|
use sdl2::video::GLProfile;
|
||||||
use std::collections::VecDeque;
|
|
||||||
use std::f32::consts::FRAC_PI_4;
|
use std::f32::consts::FRAC_PI_4;
|
||||||
use std::time::{Duration, Instant};
|
use std::time::Instant;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
use usvg::{Options as UsvgOptions, Tree};
|
use usvg::{Options as UsvgOptions, Tree};
|
||||||
|
|
||||||
mod debug_text;
|
|
||||||
mod device;
|
|
||||||
|
|
||||||
#[global_allocator]
|
#[global_allocator]
|
||||||
static ALLOC: jemallocator::Jemalloc = jemallocator::Jemalloc;
|
static ALLOC: jemallocator::Jemalloc = jemallocator::Jemalloc;
|
||||||
|
|
||||||
static QUAD_VERTEX_POSITIONS: [u8; 8] = [0, 0, 1, 0, 1, 1, 0, 1];
|
|
||||||
|
|
||||||
// TODO(pcwalton): Replace with `mem::size_of` calls?
|
|
||||||
const FILL_INSTANCE_SIZE: GLint = 8;
|
|
||||||
const SOLID_TILE_INSTANCE_SIZE: GLint = 6;
|
|
||||||
const MASK_TILE_INSTANCE_SIZE: GLint = 8;
|
|
||||||
|
|
||||||
const MASK_FRAMEBUFFER_WIDTH: u32 = TILE_WIDTH * 256;
|
|
||||||
const MASK_FRAMEBUFFER_HEIGHT: u32 = TILE_HEIGHT * 256;
|
|
||||||
|
|
||||||
const MAIN_FRAMEBUFFER_WIDTH: u32 = 1067;
|
const MAIN_FRAMEBUFFER_WIDTH: u32 = 1067;
|
||||||
const MAIN_FRAMEBUFFER_HEIGHT: u32 = 800;
|
const MAIN_FRAMEBUFFER_HEIGHT: u32 = 800;
|
||||||
|
|
||||||
const FILL_COLORS_TEXTURE_WIDTH: u32 = 256;
|
|
||||||
const FILL_COLORS_TEXTURE_HEIGHT: u32 = 256;
|
|
||||||
|
|
||||||
const MOUSELOOK_ROTATION_SPEED: f32 = 0.01;
|
const MOUSELOOK_ROTATION_SPEED: f32 = 0.01;
|
||||||
const CAMERA_VELOCITY: f32 = 0.03;
|
const CAMERA_VELOCITY: f32 = 0.03;
|
||||||
|
|
||||||
|
@ -299,420 +274,3 @@ fn build_scene(scene: &Scene, options: &Options) -> BuiltScene {
|
||||||
}
|
}
|
||||||
built_scene
|
built_scene
|
||||||
}
|
}
|
||||||
|
|
||||||
struct Renderer {
|
|
||||||
fill_program: FillProgram,
|
|
||||||
solid_tile_program: SolidTileProgram,
|
|
||||||
mask_tile_program: MaskTileProgram,
|
|
||||||
area_lut_texture: Texture,
|
|
||||||
#[allow(dead_code)]
|
|
||||||
quad_vertex_positions_buffer: Buffer,
|
|
||||||
fill_vertex_array: FillVertexArray,
|
|
||||||
mask_tile_vertex_array: MaskTileVertexArray,
|
|
||||||
solid_tile_vertex_array: SolidTileVertexArray,
|
|
||||||
mask_framebuffer: Framebuffer,
|
|
||||||
fill_colors_texture: Texture,
|
|
||||||
|
|
||||||
pending_timer_queries: VecDeque<TimerQuery>,
|
|
||||||
free_timer_queries: Vec<TimerQuery>,
|
|
||||||
|
|
||||||
debug_renderer: DebugRenderer,
|
|
||||||
|
|
||||||
main_framebuffer_size: Size2D<u32>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Renderer {
|
|
||||||
fn new(main_framebuffer_size: &Size2D<u32>) -> Renderer {
|
|
||||||
let fill_program = FillProgram::new();
|
|
||||||
let solid_tile_program = SolidTileProgram::new();
|
|
||||||
let mask_tile_program = MaskTileProgram::new();
|
|
||||||
|
|
||||||
let area_lut_texture = Texture::from_png("area-lut");
|
|
||||||
|
|
||||||
let quad_vertex_positions_buffer = Buffer::new();
|
|
||||||
quad_vertex_positions_buffer.upload(&QUAD_VERTEX_POSITIONS,
|
|
||||||
BufferTarget::Vertex,
|
|
||||||
BufferUploadMode::Static);
|
|
||||||
|
|
||||||
let fill_vertex_array = FillVertexArray::new(&fill_program, &quad_vertex_positions_buffer);
|
|
||||||
let mask_tile_vertex_array = MaskTileVertexArray::new(&mask_tile_program,
|
|
||||||
&quad_vertex_positions_buffer);
|
|
||||||
let solid_tile_vertex_array = SolidTileVertexArray::new(&solid_tile_program,
|
|
||||||
&quad_vertex_positions_buffer);
|
|
||||||
|
|
||||||
let mask_framebuffer = Framebuffer::new(&Size2D::new(MASK_FRAMEBUFFER_WIDTH,
|
|
||||||
MASK_FRAMEBUFFER_HEIGHT));
|
|
||||||
|
|
||||||
let fill_colors_texture = Texture::new_rgba(&Size2D::new(FILL_COLORS_TEXTURE_WIDTH,
|
|
||||||
FILL_COLORS_TEXTURE_HEIGHT));
|
|
||||||
|
|
||||||
let debug_renderer = DebugRenderer::new(main_framebuffer_size);
|
|
||||||
|
|
||||||
Renderer {
|
|
||||||
fill_program,
|
|
||||||
solid_tile_program,
|
|
||||||
mask_tile_program,
|
|
||||||
area_lut_texture,
|
|
||||||
quad_vertex_positions_buffer,
|
|
||||||
fill_vertex_array,
|
|
||||||
mask_tile_vertex_array,
|
|
||||||
solid_tile_vertex_array,
|
|
||||||
mask_framebuffer,
|
|
||||||
fill_colors_texture,
|
|
||||||
|
|
||||||
pending_timer_queries: VecDeque::new(),
|
|
||||||
free_timer_queries: vec![],
|
|
||||||
|
|
||||||
debug_renderer,
|
|
||||||
|
|
||||||
main_framebuffer_size: *main_framebuffer_size,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn render_scene(&mut self, built_scene: &BuiltScene) {
|
|
||||||
let timer_query = self.free_timer_queries.pop().unwrap_or_else(|| TimerQuery::new());
|
|
||||||
timer_query.begin();
|
|
||||||
|
|
||||||
self.upload_shaders(&built_scene.shaders);
|
|
||||||
|
|
||||||
self.upload_solid_tiles(&built_scene.solid_tiles);
|
|
||||||
self.draw_solid_tiles(&built_scene.solid_tiles);
|
|
||||||
|
|
||||||
for batch in &built_scene.batches {
|
|
||||||
self.upload_batch(batch);
|
|
||||||
self.draw_batch_fills(batch);
|
|
||||||
self.draw_batch_mask_tiles(batch);
|
|
||||||
}
|
|
||||||
|
|
||||||
timer_query.end();
|
|
||||||
self.pending_timer_queries.push_back(timer_query);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn shift_timer_query(&mut self) -> Option<Duration> {
|
|
||||||
let query = self.pending_timer_queries.front()?;
|
|
||||||
if !query.is_available() {
|
|
||||||
return None
|
|
||||||
}
|
|
||||||
let query = self.pending_timer_queries.pop_front().unwrap();
|
|
||||||
let result = Duration::from_nanos(query.get());
|
|
||||||
self.free_timer_queries.push(query);
|
|
||||||
Some(result)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn upload_shaders(&mut self, shaders: &[ObjectShader]) {
|
|
||||||
let size = Size2D::new(FILL_COLORS_TEXTURE_WIDTH, FILL_COLORS_TEXTURE_HEIGHT);
|
|
||||||
let mut fill_colors = vec![0; size.width as usize * size.height as usize * 4];
|
|
||||||
for (shader_index, shader) in shaders.iter().enumerate() {
|
|
||||||
fill_colors[shader_index * 4 + 0] = shader.fill_color.r;
|
|
||||||
fill_colors[shader_index * 4 + 1] = shader.fill_color.g;
|
|
||||||
fill_colors[shader_index * 4 + 2] = shader.fill_color.b;
|
|
||||||
fill_colors[shader_index * 4 + 3] = shader.fill_color.a;
|
|
||||||
}
|
|
||||||
self.fill_colors_texture.upload_rgba(&size, &fill_colors);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn upload_solid_tiles(&mut self, solid_tiles: &[SolidTileScenePrimitive]) {
|
|
||||||
self.solid_tile_vertex_array
|
|
||||||
.vertex_buffer
|
|
||||||
.upload(solid_tiles, BufferTarget::Vertex, BufferUploadMode::Dynamic);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn upload_batch(&mut self, batch: &Batch) {
|
|
||||||
self.fill_vertex_array
|
|
||||||
.vertex_buffer
|
|
||||||
.upload(&batch.fills, BufferTarget::Vertex, BufferUploadMode::Dynamic);
|
|
||||||
self.mask_tile_vertex_array
|
|
||||||
.vertex_buffer
|
|
||||||
.upload(&batch.mask_tiles, BufferTarget::Vertex, BufferUploadMode::Dynamic);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn draw_batch_fills(&mut self, batch: &Batch) {
|
|
||||||
unsafe {
|
|
||||||
gl::BindFramebuffer(gl::FRAMEBUFFER, self.mask_framebuffer.gl_framebuffer);
|
|
||||||
gl::Viewport(0, 0, MASK_FRAMEBUFFER_WIDTH as GLint, MASK_FRAMEBUFFER_HEIGHT as GLint);
|
|
||||||
// TODO(pcwalton): Only clear the appropriate portion?
|
|
||||||
gl::ClearColor(0.0, 0.0, 0.0, 0.0);
|
|
||||||
gl::Clear(gl::COLOR_BUFFER_BIT);
|
|
||||||
|
|
||||||
gl::BindVertexArray(self.fill_vertex_array.gl_vertex_array);
|
|
||||||
gl::UseProgram(self.fill_program.program.gl_program);
|
|
||||||
gl::Uniform2f(self.fill_program.framebuffer_size_uniform.location,
|
|
||||||
MASK_FRAMEBUFFER_WIDTH as GLfloat,
|
|
||||||
MASK_FRAMEBUFFER_HEIGHT as GLfloat);
|
|
||||||
gl::Uniform2f(self.fill_program.tile_size_uniform.location,
|
|
||||||
TILE_WIDTH as GLfloat,
|
|
||||||
TILE_HEIGHT as GLfloat);
|
|
||||||
self.area_lut_texture.bind(0);
|
|
||||||
gl::Uniform1i(self.fill_program.area_lut_uniform.location, 0);
|
|
||||||
gl::BlendEquation(gl::FUNC_ADD);
|
|
||||||
gl::BlendFunc(gl::ONE, gl::ONE);
|
|
||||||
gl::Enable(gl::BLEND);
|
|
||||||
gl::DrawArraysInstanced(gl::TRIANGLE_FAN, 0, 4, batch.fills.len() as GLint);
|
|
||||||
gl::Disable(gl::BLEND);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn draw_batch_mask_tiles(&mut self, batch: &Batch) {
|
|
||||||
unsafe {
|
|
||||||
gl::BindFramebuffer(gl::FRAMEBUFFER, 0);
|
|
||||||
gl::Viewport(0,
|
|
||||||
0,
|
|
||||||
self.main_framebuffer_size.width as GLint,
|
|
||||||
self.main_framebuffer_size.height as GLint);
|
|
||||||
|
|
||||||
gl::BindVertexArray(self.mask_tile_vertex_array.gl_vertex_array);
|
|
||||||
gl::UseProgram(self.mask_tile_program.program.gl_program);
|
|
||||||
gl::Uniform2f(self.mask_tile_program.framebuffer_size_uniform.location,
|
|
||||||
self.main_framebuffer_size.width as GLfloat,
|
|
||||||
self.main_framebuffer_size.height as GLfloat);
|
|
||||||
gl::Uniform2f(self.mask_tile_program.tile_size_uniform.location,
|
|
||||||
TILE_WIDTH as GLfloat,
|
|
||||||
TILE_HEIGHT as GLfloat);
|
|
||||||
self.mask_framebuffer.texture.bind(0);
|
|
||||||
gl::Uniform1i(self.mask_tile_program.stencil_texture_uniform.location, 0);
|
|
||||||
gl::Uniform2f(self.mask_tile_program.stencil_texture_size_uniform.location,
|
|
||||||
MASK_FRAMEBUFFER_WIDTH as GLfloat,
|
|
||||||
MASK_FRAMEBUFFER_HEIGHT as GLfloat);
|
|
||||||
self.fill_colors_texture.bind(1);
|
|
||||||
gl::Uniform1i(self.mask_tile_program.fill_colors_texture_uniform.location, 1);
|
|
||||||
gl::Uniform2f(self.mask_tile_program.fill_colors_texture_size_uniform.location,
|
|
||||||
FILL_COLORS_TEXTURE_WIDTH as GLfloat,
|
|
||||||
FILL_COLORS_TEXTURE_HEIGHT as GLfloat);
|
|
||||||
// FIXME(pcwalton): Fill this in properly!
|
|
||||||
gl::Uniform2f(self.mask_tile_program.view_box_origin_uniform.location, 0.0, 0.0);
|
|
||||||
gl::BlendEquation(gl::FUNC_ADD);
|
|
||||||
gl::BlendFuncSeparate(gl::SRC_ALPHA, gl::ONE_MINUS_SRC_ALPHA, gl::ONE, gl::ONE);
|
|
||||||
gl::Enable(gl::BLEND);
|
|
||||||
gl::DrawArraysInstanced(gl::TRIANGLE_FAN, 0, 4, batch.mask_tiles.len() as GLint);
|
|
||||||
gl::Disable(gl::BLEND);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn draw_solid_tiles(&mut self, solid_tiles: &[SolidTileScenePrimitive]) {
|
|
||||||
unsafe {
|
|
||||||
gl::BindFramebuffer(gl::FRAMEBUFFER, 0);
|
|
||||||
gl::Viewport(0,
|
|
||||||
0,
|
|
||||||
self.main_framebuffer_size.width as GLint,
|
|
||||||
self.main_framebuffer_size.height as GLint);
|
|
||||||
|
|
||||||
gl::BindVertexArray(self.solid_tile_vertex_array.gl_vertex_array);
|
|
||||||
gl::UseProgram(self.solid_tile_program.program.gl_program);
|
|
||||||
gl::Uniform2f(self.solid_tile_program.framebuffer_size_uniform.location,
|
|
||||||
self.main_framebuffer_size.width as GLfloat,
|
|
||||||
self.main_framebuffer_size.height as GLfloat);
|
|
||||||
gl::Uniform2f(self.solid_tile_program.tile_size_uniform.location,
|
|
||||||
TILE_WIDTH as GLfloat,
|
|
||||||
TILE_HEIGHT as GLfloat);
|
|
||||||
self.fill_colors_texture.bind(0);
|
|
||||||
gl::Uniform1i(self.solid_tile_program.fill_colors_texture_uniform.location, 0);
|
|
||||||
gl::Uniform2f(self.solid_tile_program.fill_colors_texture_size_uniform.location,
|
|
||||||
FILL_COLORS_TEXTURE_WIDTH as GLfloat,
|
|
||||||
FILL_COLORS_TEXTURE_HEIGHT as GLfloat);
|
|
||||||
// FIXME(pcwalton): Fill this in properly!
|
|
||||||
gl::Uniform2f(self.solid_tile_program.view_box_origin_uniform.location, 0.0, 0.0);
|
|
||||||
gl::Disable(gl::BLEND);
|
|
||||||
gl::DrawArraysInstanced(gl::TRIANGLE_FAN, 0, 4, solid_tiles.len() as GLint);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
struct FillVertexArray {
|
|
||||||
gl_vertex_array: GLuint,
|
|
||||||
vertex_buffer: Buffer,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl FillVertexArray {
|
|
||||||
fn new(fill_program: &FillProgram, quad_vertex_positions_buffer: &Buffer) -> FillVertexArray {
|
|
||||||
let vertex_buffer = Buffer::new();
|
|
||||||
let mut gl_vertex_array = 0;
|
|
||||||
unsafe {
|
|
||||||
let tess_coord_attr = VertexAttr::new(&fill_program.program, "TessCoord");
|
|
||||||
let from_px_attr = VertexAttr::new(&fill_program.program, "FromPx");
|
|
||||||
let to_px_attr = VertexAttr::new(&fill_program.program, "ToPx");
|
|
||||||
let from_subpx_attr = VertexAttr::new(&fill_program.program, "FromSubpx");
|
|
||||||
let to_subpx_attr = VertexAttr::new(&fill_program.program, "ToSubpx");
|
|
||||||
let tile_index_attr = VertexAttr::new(&fill_program.program, "TileIndex");
|
|
||||||
|
|
||||||
gl::GenVertexArrays(1, &mut gl_vertex_array);
|
|
||||||
gl::BindVertexArray(gl_vertex_array);
|
|
||||||
gl::UseProgram(fill_program.program.gl_program);
|
|
||||||
gl::BindBuffer(gl::ARRAY_BUFFER, quad_vertex_positions_buffer.gl_buffer);
|
|
||||||
tess_coord_attr.configure_float(2, gl::UNSIGNED_BYTE, false, 0, 0, 0);
|
|
||||||
gl::BindBuffer(gl::ARRAY_BUFFER, vertex_buffer.gl_buffer);
|
|
||||||
from_px_attr.configure_int(1, gl::UNSIGNED_BYTE, FILL_INSTANCE_SIZE, 0, 1);
|
|
||||||
to_px_attr.configure_int(1, gl::UNSIGNED_BYTE, FILL_INSTANCE_SIZE, 1, 1);
|
|
||||||
from_subpx_attr.configure_float(2, gl::UNSIGNED_BYTE, true, FILL_INSTANCE_SIZE, 2, 1);
|
|
||||||
to_subpx_attr.configure_float(2, gl::UNSIGNED_BYTE, true, FILL_INSTANCE_SIZE, 4, 1);
|
|
||||||
tile_index_attr.configure_int(1, gl::UNSIGNED_SHORT, FILL_INSTANCE_SIZE, 6, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
FillVertexArray { gl_vertex_array, vertex_buffer }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Drop for FillVertexArray {
|
|
||||||
#[inline]
|
|
||||||
fn drop(&mut self) {
|
|
||||||
unsafe {
|
|
||||||
gl::DeleteVertexArrays(1, &mut self.gl_vertex_array);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
struct MaskTileVertexArray {
|
|
||||||
gl_vertex_array: GLuint,
|
|
||||||
vertex_buffer: Buffer,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl MaskTileVertexArray {
|
|
||||||
fn new(mask_tile_program: &MaskTileProgram, quad_vertex_positions_buffer: &Buffer)
|
|
||||||
-> MaskTileVertexArray {
|
|
||||||
let vertex_buffer = Buffer::new();
|
|
||||||
let mut gl_vertex_array = 0;
|
|
||||||
unsafe {
|
|
||||||
let tess_coord_attr = VertexAttr::new(&mask_tile_program.program, "TessCoord");
|
|
||||||
let tile_origin_attr = VertexAttr::new(&mask_tile_program.program, "TileOrigin");
|
|
||||||
let backdrop_attr = VertexAttr::new(&mask_tile_program.program, "Backdrop");
|
|
||||||
let object_attr = VertexAttr::new(&mask_tile_program.program, "Object");
|
|
||||||
|
|
||||||
gl::GenVertexArrays(1, &mut gl_vertex_array);
|
|
||||||
gl::BindVertexArray(gl_vertex_array);
|
|
||||||
gl::UseProgram(mask_tile_program.program.gl_program);
|
|
||||||
gl::BindBuffer(gl::ARRAY_BUFFER, quad_vertex_positions_buffer.gl_buffer);
|
|
||||||
tess_coord_attr.configure_float(2, gl::UNSIGNED_BYTE, false, 0, 0, 0);
|
|
||||||
gl::BindBuffer(gl::ARRAY_BUFFER, vertex_buffer.gl_buffer);
|
|
||||||
tile_origin_attr.configure_float(2, gl::SHORT, false, MASK_TILE_INSTANCE_SIZE, 0, 1);
|
|
||||||
backdrop_attr.configure_int(1, gl::SHORT, MASK_TILE_INSTANCE_SIZE, 4, 1);
|
|
||||||
object_attr.configure_int(2, gl::UNSIGNED_SHORT, MASK_TILE_INSTANCE_SIZE, 6, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
MaskTileVertexArray { gl_vertex_array, vertex_buffer }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Drop for MaskTileVertexArray {
|
|
||||||
#[inline]
|
|
||||||
fn drop(&mut self) {
|
|
||||||
unsafe {
|
|
||||||
gl::DeleteVertexArrays(1, &mut self.gl_vertex_array);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
struct SolidTileVertexArray {
|
|
||||||
gl_vertex_array: GLuint,
|
|
||||||
vertex_buffer: Buffer,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl SolidTileVertexArray {
|
|
||||||
fn new(solid_tile_program: &SolidTileProgram, quad_vertex_positions_buffer: &Buffer)
|
|
||||||
-> SolidTileVertexArray {
|
|
||||||
let vertex_buffer = Buffer::new();
|
|
||||||
let mut gl_vertex_array = 0;
|
|
||||||
unsafe {
|
|
||||||
let tess_coord_attr = VertexAttr::new(&solid_tile_program.program, "TessCoord");
|
|
||||||
let tile_origin_attr = VertexAttr::new(&solid_tile_program.program, "TileOrigin");
|
|
||||||
let object_attr = VertexAttr::new(&solid_tile_program.program, "Object");
|
|
||||||
|
|
||||||
gl::GenVertexArrays(1, &mut gl_vertex_array);
|
|
||||||
gl::BindVertexArray(gl_vertex_array);
|
|
||||||
gl::UseProgram(solid_tile_program.program.gl_program);
|
|
||||||
gl::BindBuffer(gl::ARRAY_BUFFER, quad_vertex_positions_buffer.gl_buffer);
|
|
||||||
tess_coord_attr.configure_float(2, gl::UNSIGNED_BYTE, false, 0, 0, 0);
|
|
||||||
gl::BindBuffer(gl::ARRAY_BUFFER, vertex_buffer.gl_buffer);
|
|
||||||
tile_origin_attr.configure_float(2, gl::SHORT, false, SOLID_TILE_INSTANCE_SIZE, 0, 1);
|
|
||||||
object_attr.configure_int(1, gl::UNSIGNED_SHORT, SOLID_TILE_INSTANCE_SIZE, 4, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
SolidTileVertexArray { gl_vertex_array, vertex_buffer }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Drop for SolidTileVertexArray {
|
|
||||||
#[inline]
|
|
||||||
fn drop(&mut self) {
|
|
||||||
unsafe {
|
|
||||||
gl::DeleteVertexArrays(1, &mut self.gl_vertex_array);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
struct FillProgram {
|
|
||||||
program: Program,
|
|
||||||
framebuffer_size_uniform: Uniform,
|
|
||||||
tile_size_uniform: Uniform,
|
|
||||||
area_lut_uniform: Uniform,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl FillProgram {
|
|
||||||
fn new() -> FillProgram {
|
|
||||||
let program = Program::new("fill");
|
|
||||||
let framebuffer_size_uniform = Uniform::new(&program, "FramebufferSize");
|
|
||||||
let tile_size_uniform = Uniform::new(&program, "TileSize");
|
|
||||||
let area_lut_uniform = Uniform::new(&program, "AreaLUT");
|
|
||||||
FillProgram { program, framebuffer_size_uniform, tile_size_uniform, area_lut_uniform }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
struct SolidTileProgram {
|
|
||||||
program: Program,
|
|
||||||
framebuffer_size_uniform: Uniform,
|
|
||||||
tile_size_uniform: Uniform,
|
|
||||||
fill_colors_texture_uniform: Uniform,
|
|
||||||
fill_colors_texture_size_uniform: Uniform,
|
|
||||||
view_box_origin_uniform: Uniform,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl SolidTileProgram {
|
|
||||||
fn new() -> SolidTileProgram {
|
|
||||||
let program = Program::new("solid_tile");
|
|
||||||
let framebuffer_size_uniform = Uniform::new(&program, "FramebufferSize");
|
|
||||||
let tile_size_uniform = Uniform::new(&program, "TileSize");
|
|
||||||
let fill_colors_texture_uniform = Uniform::new(&program, "FillColorsTexture");
|
|
||||||
let fill_colors_texture_size_uniform = Uniform::new(&program, "FillColorsTextureSize");
|
|
||||||
let view_box_origin_uniform = Uniform::new(&program, "ViewBoxOrigin");
|
|
||||||
SolidTileProgram {
|
|
||||||
program,
|
|
||||||
framebuffer_size_uniform,
|
|
||||||
tile_size_uniform,
|
|
||||||
fill_colors_texture_uniform,
|
|
||||||
fill_colors_texture_size_uniform,
|
|
||||||
view_box_origin_uniform,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
struct MaskTileProgram {
|
|
||||||
program: Program,
|
|
||||||
framebuffer_size_uniform: Uniform,
|
|
||||||
tile_size_uniform: Uniform,
|
|
||||||
stencil_texture_uniform: Uniform,
|
|
||||||
stencil_texture_size_uniform: Uniform,
|
|
||||||
fill_colors_texture_uniform: Uniform,
|
|
||||||
fill_colors_texture_size_uniform: Uniform,
|
|
||||||
view_box_origin_uniform: Uniform,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl MaskTileProgram {
|
|
||||||
fn new() -> MaskTileProgram {
|
|
||||||
let program = Program::new("mask_tile");
|
|
||||||
let framebuffer_size_uniform = Uniform::new(&program, "FramebufferSize");
|
|
||||||
let tile_size_uniform = Uniform::new(&program, "TileSize");
|
|
||||||
let stencil_texture_uniform = Uniform::new(&program, "StencilTexture");
|
|
||||||
let stencil_texture_size_uniform = Uniform::new(&program, "StencilTextureSize");
|
|
||||||
let fill_colors_texture_uniform = Uniform::new(&program, "FillColorsTexture");
|
|
||||||
let fill_colors_texture_size_uniform = Uniform::new(&program, "FillColorsTextureSize");
|
|
||||||
let view_box_origin_uniform = Uniform::new(&program, "ViewBoxOrigin");
|
|
||||||
MaskTileProgram {
|
|
||||||
program,
|
|
||||||
framebuffer_size_uniform,
|
|
||||||
tile_size_uniform,
|
|
||||||
stencil_texture_uniform,
|
|
||||||
stencil_texture_size_uniform,
|
|
||||||
fill_colors_texture_uniform,
|
|
||||||
fill_colors_texture_size_uniform,
|
|
||||||
view_box_origin_uniform,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -0,0 +1,23 @@
|
||||||
|
[package]
|
||||||
|
name = "pathfinder_gl"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2018"
|
||||||
|
authors = ["Patrick Walton <pcwalton@mimiga.net>"]
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
euclid = "0.19"
|
||||||
|
gl = "0.6"
|
||||||
|
serde = "1.0"
|
||||||
|
serde_derive = "1.0"
|
||||||
|
serde_json = "1.0"
|
||||||
|
|
||||||
|
[dependencies.image]
|
||||||
|
version = "0.21"
|
||||||
|
default-features = false
|
||||||
|
features = ["png_codec"]
|
||||||
|
|
||||||
|
[dependencies.pathfinder_geometry]
|
||||||
|
path = "../geometry"
|
||||||
|
|
||||||
|
[dependencies.pathfinder_renderer]
|
||||||
|
path = "../renderer"
|
|
@ -1,4 +1,4 @@
|
||||||
// pathfinder/demo3/src/debug_text.rs
|
// pathfinder/gl/src/debug.rs
|
||||||
//
|
//
|
||||||
// Copyright © 2019 The Pathfinder Project Developers.
|
// Copyright © 2019 The Pathfinder Project Developers.
|
||||||
//
|
//
|
||||||
|
@ -8,7 +8,7 @@
|
||||||
// option. This file may not be copied, modified, or distributed
|
// option. This file may not be copied, modified, or distributed
|
||||||
// except according to those terms.
|
// except according to those terms.
|
||||||
|
|
||||||
//! Minimal text rendering.
|
//! A debug overlay.
|
||||||
//!
|
//!
|
||||||
//! We don't render the demo UI text using Pathfinder itself so that we can use the debug UI to
|
//! We don't render the demo UI text using Pathfinder itself so that we can use the debug UI to
|
||||||
//! debug Pathfinder if it's totally busted.
|
//! debug Pathfinder if it's totally busted.
|
|
@ -0,0 +1,23 @@
|
||||||
|
// pathfinder/gl/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.
|
||||||
|
|
||||||
|
//! An OpenGL backend for Pathfinder.
|
||||||
|
//!
|
||||||
|
//! It's not necessary to use this crate to render vector graphics with
|
||||||
|
//! Pathfinder; you can use the `pathfinder_renderer` crate and do the GPU
|
||||||
|
//! rendering yourself using the API or engine of your choice. This crate can
|
||||||
|
//! be useful for simple use cases, however.
|
||||||
|
|
||||||
|
#[macro_use]
|
||||||
|
extern crate serde_derive;
|
||||||
|
|
||||||
|
pub mod debug;
|
||||||
|
pub mod device;
|
||||||
|
pub mod renderer;
|
|
@ -0,0 +1,450 @@
|
||||||
|
// pathfinder/gl/src/renderer.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.
|
||||||
|
|
||||||
|
use crate::debug::DebugRenderer;
|
||||||
|
use crate::device::{Buffer, BufferTarget, BufferUploadMode, Framebuffer, Program, Texture};
|
||||||
|
use crate::device::{TimerQuery, Uniform, VertexAttr};
|
||||||
|
use euclid::Size2D;
|
||||||
|
use gl::types::{GLfloat, GLint, GLuint};
|
||||||
|
use pathfinder_renderer::gpu_data::{Batch, BuiltScene, SolidTileScenePrimitive};
|
||||||
|
use pathfinder_renderer::paint::ObjectShader;
|
||||||
|
use pathfinder_renderer::tiles::{TILE_HEIGHT, TILE_WIDTH};
|
||||||
|
use std::collections::VecDeque;
|
||||||
|
use std::time::Duration;
|
||||||
|
|
||||||
|
static QUAD_VERTEX_POSITIONS: [u8; 8] = [0, 0, 1, 0, 1, 1, 0, 1];
|
||||||
|
|
||||||
|
const MASK_FRAMEBUFFER_WIDTH: u32 = TILE_WIDTH * 256;
|
||||||
|
const MASK_FRAMEBUFFER_HEIGHT: u32 = TILE_HEIGHT * 256;
|
||||||
|
|
||||||
|
// TODO(pcwalton): Replace with `mem::size_of` calls?
|
||||||
|
const FILL_INSTANCE_SIZE: GLint = 8;
|
||||||
|
const SOLID_TILE_INSTANCE_SIZE: GLint = 6;
|
||||||
|
const MASK_TILE_INSTANCE_SIZE: GLint = 8;
|
||||||
|
|
||||||
|
const FILL_COLORS_TEXTURE_WIDTH: u32 = 256;
|
||||||
|
const FILL_COLORS_TEXTURE_HEIGHT: u32 = 256;
|
||||||
|
|
||||||
|
pub struct Renderer {
|
||||||
|
fill_program: FillProgram,
|
||||||
|
solid_tile_program: SolidTileProgram,
|
||||||
|
mask_tile_program: MaskTileProgram,
|
||||||
|
area_lut_texture: Texture,
|
||||||
|
#[allow(dead_code)]
|
||||||
|
quad_vertex_positions_buffer: Buffer,
|
||||||
|
fill_vertex_array: FillVertexArray,
|
||||||
|
mask_tile_vertex_array: MaskTileVertexArray,
|
||||||
|
solid_tile_vertex_array: SolidTileVertexArray,
|
||||||
|
mask_framebuffer: Framebuffer,
|
||||||
|
fill_colors_texture: Texture,
|
||||||
|
|
||||||
|
pending_timer_queries: VecDeque<TimerQuery>,
|
||||||
|
free_timer_queries: Vec<TimerQuery>,
|
||||||
|
|
||||||
|
pub debug_renderer: DebugRenderer,
|
||||||
|
|
||||||
|
main_framebuffer_size: Size2D<u32>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Renderer {
|
||||||
|
pub fn new(main_framebuffer_size: &Size2D<u32>) -> Renderer {
|
||||||
|
let fill_program = FillProgram::new();
|
||||||
|
let solid_tile_program = SolidTileProgram::new();
|
||||||
|
let mask_tile_program = MaskTileProgram::new();
|
||||||
|
|
||||||
|
let area_lut_texture = Texture::from_png("area-lut");
|
||||||
|
|
||||||
|
let quad_vertex_positions_buffer = Buffer::new();
|
||||||
|
quad_vertex_positions_buffer.upload(&QUAD_VERTEX_POSITIONS,
|
||||||
|
BufferTarget::Vertex,
|
||||||
|
BufferUploadMode::Static);
|
||||||
|
|
||||||
|
let fill_vertex_array = FillVertexArray::new(&fill_program, &quad_vertex_positions_buffer);
|
||||||
|
let mask_tile_vertex_array = MaskTileVertexArray::new(&mask_tile_program,
|
||||||
|
&quad_vertex_positions_buffer);
|
||||||
|
let solid_tile_vertex_array = SolidTileVertexArray::new(&solid_tile_program,
|
||||||
|
&quad_vertex_positions_buffer);
|
||||||
|
|
||||||
|
let mask_framebuffer = Framebuffer::new(&Size2D::new(MASK_FRAMEBUFFER_WIDTH,
|
||||||
|
MASK_FRAMEBUFFER_HEIGHT));
|
||||||
|
|
||||||
|
let fill_colors_texture = Texture::new_rgba(&Size2D::new(FILL_COLORS_TEXTURE_WIDTH,
|
||||||
|
FILL_COLORS_TEXTURE_HEIGHT));
|
||||||
|
|
||||||
|
let debug_renderer = DebugRenderer::new(main_framebuffer_size);
|
||||||
|
|
||||||
|
Renderer {
|
||||||
|
fill_program,
|
||||||
|
solid_tile_program,
|
||||||
|
mask_tile_program,
|
||||||
|
area_lut_texture,
|
||||||
|
quad_vertex_positions_buffer,
|
||||||
|
fill_vertex_array,
|
||||||
|
mask_tile_vertex_array,
|
||||||
|
solid_tile_vertex_array,
|
||||||
|
mask_framebuffer,
|
||||||
|
fill_colors_texture,
|
||||||
|
|
||||||
|
pending_timer_queries: VecDeque::new(),
|
||||||
|
free_timer_queries: vec![],
|
||||||
|
|
||||||
|
debug_renderer,
|
||||||
|
|
||||||
|
main_framebuffer_size: *main_framebuffer_size,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn render_scene(&mut self, built_scene: &BuiltScene) {
|
||||||
|
let timer_query = self.free_timer_queries.pop().unwrap_or_else(|| TimerQuery::new());
|
||||||
|
timer_query.begin();
|
||||||
|
|
||||||
|
self.upload_shaders(&built_scene.shaders);
|
||||||
|
|
||||||
|
self.upload_solid_tiles(&built_scene.solid_tiles);
|
||||||
|
self.draw_solid_tiles(&built_scene.solid_tiles);
|
||||||
|
|
||||||
|
for batch in &built_scene.batches {
|
||||||
|
self.upload_batch(batch);
|
||||||
|
self.draw_batch_fills(batch);
|
||||||
|
self.draw_batch_mask_tiles(batch);
|
||||||
|
}
|
||||||
|
|
||||||
|
timer_query.end();
|
||||||
|
self.pending_timer_queries.push_back(timer_query);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn shift_timer_query(&mut self) -> Option<Duration> {
|
||||||
|
let query = self.pending_timer_queries.front()?;
|
||||||
|
if !query.is_available() {
|
||||||
|
return None
|
||||||
|
}
|
||||||
|
let query = self.pending_timer_queries.pop_front().unwrap();
|
||||||
|
let result = Duration::from_nanos(query.get());
|
||||||
|
self.free_timer_queries.push(query);
|
||||||
|
Some(result)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn upload_shaders(&mut self, shaders: &[ObjectShader]) {
|
||||||
|
let size = Size2D::new(FILL_COLORS_TEXTURE_WIDTH, FILL_COLORS_TEXTURE_HEIGHT);
|
||||||
|
let mut fill_colors = vec![0; size.width as usize * size.height as usize * 4];
|
||||||
|
for (shader_index, shader) in shaders.iter().enumerate() {
|
||||||
|
fill_colors[shader_index * 4 + 0] = shader.fill_color.r;
|
||||||
|
fill_colors[shader_index * 4 + 1] = shader.fill_color.g;
|
||||||
|
fill_colors[shader_index * 4 + 2] = shader.fill_color.b;
|
||||||
|
fill_colors[shader_index * 4 + 3] = shader.fill_color.a;
|
||||||
|
}
|
||||||
|
self.fill_colors_texture.upload_rgba(&size, &fill_colors);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn upload_solid_tiles(&mut self, solid_tiles: &[SolidTileScenePrimitive]) {
|
||||||
|
self.solid_tile_vertex_array
|
||||||
|
.vertex_buffer
|
||||||
|
.upload(solid_tiles, BufferTarget::Vertex, BufferUploadMode::Dynamic);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn upload_batch(&mut self, batch: &Batch) {
|
||||||
|
self.fill_vertex_array
|
||||||
|
.vertex_buffer
|
||||||
|
.upload(&batch.fills, BufferTarget::Vertex, BufferUploadMode::Dynamic);
|
||||||
|
self.mask_tile_vertex_array
|
||||||
|
.vertex_buffer
|
||||||
|
.upload(&batch.mask_tiles, BufferTarget::Vertex, BufferUploadMode::Dynamic);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn draw_batch_fills(&mut self, batch: &Batch) {
|
||||||
|
unsafe {
|
||||||
|
gl::BindFramebuffer(gl::FRAMEBUFFER, self.mask_framebuffer.gl_framebuffer);
|
||||||
|
gl::Viewport(0, 0, MASK_FRAMEBUFFER_WIDTH as GLint, MASK_FRAMEBUFFER_HEIGHT as GLint);
|
||||||
|
// TODO(pcwalton): Only clear the appropriate portion?
|
||||||
|
gl::ClearColor(0.0, 0.0, 0.0, 0.0);
|
||||||
|
gl::Clear(gl::COLOR_BUFFER_BIT);
|
||||||
|
|
||||||
|
gl::BindVertexArray(self.fill_vertex_array.gl_vertex_array);
|
||||||
|
gl::UseProgram(self.fill_program.program.gl_program);
|
||||||
|
gl::Uniform2f(self.fill_program.framebuffer_size_uniform.location,
|
||||||
|
MASK_FRAMEBUFFER_WIDTH as GLfloat,
|
||||||
|
MASK_FRAMEBUFFER_HEIGHT as GLfloat);
|
||||||
|
gl::Uniform2f(self.fill_program.tile_size_uniform.location,
|
||||||
|
TILE_WIDTH as GLfloat,
|
||||||
|
TILE_HEIGHT as GLfloat);
|
||||||
|
self.area_lut_texture.bind(0);
|
||||||
|
gl::Uniform1i(self.fill_program.area_lut_uniform.location, 0);
|
||||||
|
gl::BlendEquation(gl::FUNC_ADD);
|
||||||
|
gl::BlendFunc(gl::ONE, gl::ONE);
|
||||||
|
gl::Enable(gl::BLEND);
|
||||||
|
gl::DrawArraysInstanced(gl::TRIANGLE_FAN, 0, 4, batch.fills.len() as GLint);
|
||||||
|
gl::Disable(gl::BLEND);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn draw_batch_mask_tiles(&mut self, batch: &Batch) {
|
||||||
|
unsafe {
|
||||||
|
gl::BindFramebuffer(gl::FRAMEBUFFER, 0);
|
||||||
|
gl::Viewport(0,
|
||||||
|
0,
|
||||||
|
self.main_framebuffer_size.width as GLint,
|
||||||
|
self.main_framebuffer_size.height as GLint);
|
||||||
|
|
||||||
|
gl::BindVertexArray(self.mask_tile_vertex_array.gl_vertex_array);
|
||||||
|
gl::UseProgram(self.mask_tile_program.program.gl_program);
|
||||||
|
gl::Uniform2f(self.mask_tile_program.framebuffer_size_uniform.location,
|
||||||
|
self.main_framebuffer_size.width as GLfloat,
|
||||||
|
self.main_framebuffer_size.height as GLfloat);
|
||||||
|
gl::Uniform2f(self.mask_tile_program.tile_size_uniform.location,
|
||||||
|
TILE_WIDTH as GLfloat,
|
||||||
|
TILE_HEIGHT as GLfloat);
|
||||||
|
self.mask_framebuffer.texture.bind(0);
|
||||||
|
gl::Uniform1i(self.mask_tile_program.stencil_texture_uniform.location, 0);
|
||||||
|
gl::Uniform2f(self.mask_tile_program.stencil_texture_size_uniform.location,
|
||||||
|
MASK_FRAMEBUFFER_WIDTH as GLfloat,
|
||||||
|
MASK_FRAMEBUFFER_HEIGHT as GLfloat);
|
||||||
|
self.fill_colors_texture.bind(1);
|
||||||
|
gl::Uniform1i(self.mask_tile_program.fill_colors_texture_uniform.location, 1);
|
||||||
|
gl::Uniform2f(self.mask_tile_program.fill_colors_texture_size_uniform.location,
|
||||||
|
FILL_COLORS_TEXTURE_WIDTH as GLfloat,
|
||||||
|
FILL_COLORS_TEXTURE_HEIGHT as GLfloat);
|
||||||
|
// FIXME(pcwalton): Fill this in properly!
|
||||||
|
gl::Uniform2f(self.mask_tile_program.view_box_origin_uniform.location, 0.0, 0.0);
|
||||||
|
gl::BlendEquation(gl::FUNC_ADD);
|
||||||
|
gl::BlendFuncSeparate(gl::SRC_ALPHA, gl::ONE_MINUS_SRC_ALPHA, gl::ONE, gl::ONE);
|
||||||
|
gl::Enable(gl::BLEND);
|
||||||
|
gl::DrawArraysInstanced(gl::TRIANGLE_FAN, 0, 4, batch.mask_tiles.len() as GLint);
|
||||||
|
gl::Disable(gl::BLEND);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn draw_solid_tiles(&mut self, solid_tiles: &[SolidTileScenePrimitive]) {
|
||||||
|
unsafe {
|
||||||
|
gl::BindFramebuffer(gl::FRAMEBUFFER, 0);
|
||||||
|
gl::Viewport(0,
|
||||||
|
0,
|
||||||
|
self.main_framebuffer_size.width as GLint,
|
||||||
|
self.main_framebuffer_size.height as GLint);
|
||||||
|
|
||||||
|
gl::BindVertexArray(self.solid_tile_vertex_array.gl_vertex_array);
|
||||||
|
gl::UseProgram(self.solid_tile_program.program.gl_program);
|
||||||
|
gl::Uniform2f(self.solid_tile_program.framebuffer_size_uniform.location,
|
||||||
|
self.main_framebuffer_size.width as GLfloat,
|
||||||
|
self.main_framebuffer_size.height as GLfloat);
|
||||||
|
gl::Uniform2f(self.solid_tile_program.tile_size_uniform.location,
|
||||||
|
TILE_WIDTH as GLfloat,
|
||||||
|
TILE_HEIGHT as GLfloat);
|
||||||
|
self.fill_colors_texture.bind(0);
|
||||||
|
gl::Uniform1i(self.solid_tile_program.fill_colors_texture_uniform.location, 0);
|
||||||
|
gl::Uniform2f(self.solid_tile_program.fill_colors_texture_size_uniform.location,
|
||||||
|
FILL_COLORS_TEXTURE_WIDTH as GLfloat,
|
||||||
|
FILL_COLORS_TEXTURE_HEIGHT as GLfloat);
|
||||||
|
// FIXME(pcwalton): Fill this in properly!
|
||||||
|
gl::Uniform2f(self.solid_tile_program.view_box_origin_uniform.location, 0.0, 0.0);
|
||||||
|
gl::Disable(gl::BLEND);
|
||||||
|
gl::DrawArraysInstanced(gl::TRIANGLE_FAN, 0, 4, solid_tiles.len() as GLint);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct FillVertexArray {
|
||||||
|
gl_vertex_array: GLuint,
|
||||||
|
vertex_buffer: Buffer,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FillVertexArray {
|
||||||
|
fn new(fill_program: &FillProgram, quad_vertex_positions_buffer: &Buffer) -> FillVertexArray {
|
||||||
|
let vertex_buffer = Buffer::new();
|
||||||
|
let mut gl_vertex_array = 0;
|
||||||
|
unsafe {
|
||||||
|
let tess_coord_attr = VertexAttr::new(&fill_program.program, "TessCoord");
|
||||||
|
let from_px_attr = VertexAttr::new(&fill_program.program, "FromPx");
|
||||||
|
let to_px_attr = VertexAttr::new(&fill_program.program, "ToPx");
|
||||||
|
let from_subpx_attr = VertexAttr::new(&fill_program.program, "FromSubpx");
|
||||||
|
let to_subpx_attr = VertexAttr::new(&fill_program.program, "ToSubpx");
|
||||||
|
let tile_index_attr = VertexAttr::new(&fill_program.program, "TileIndex");
|
||||||
|
|
||||||
|
gl::GenVertexArrays(1, &mut gl_vertex_array);
|
||||||
|
gl::BindVertexArray(gl_vertex_array);
|
||||||
|
gl::UseProgram(fill_program.program.gl_program);
|
||||||
|
gl::BindBuffer(gl::ARRAY_BUFFER, quad_vertex_positions_buffer.gl_buffer);
|
||||||
|
tess_coord_attr.configure_float(2, gl::UNSIGNED_BYTE, false, 0, 0, 0);
|
||||||
|
gl::BindBuffer(gl::ARRAY_BUFFER, vertex_buffer.gl_buffer);
|
||||||
|
from_px_attr.configure_int(1, gl::UNSIGNED_BYTE, FILL_INSTANCE_SIZE, 0, 1);
|
||||||
|
to_px_attr.configure_int(1, gl::UNSIGNED_BYTE, FILL_INSTANCE_SIZE, 1, 1);
|
||||||
|
from_subpx_attr.configure_float(2, gl::UNSIGNED_BYTE, true, FILL_INSTANCE_SIZE, 2, 1);
|
||||||
|
to_subpx_attr.configure_float(2, gl::UNSIGNED_BYTE, true, FILL_INSTANCE_SIZE, 4, 1);
|
||||||
|
tile_index_attr.configure_int(1, gl::UNSIGNED_SHORT, FILL_INSTANCE_SIZE, 6, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
FillVertexArray { gl_vertex_array, vertex_buffer }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Drop for FillVertexArray {
|
||||||
|
#[inline]
|
||||||
|
fn drop(&mut self) {
|
||||||
|
unsafe {
|
||||||
|
gl::DeleteVertexArrays(1, &mut self.gl_vertex_array);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct MaskTileVertexArray {
|
||||||
|
gl_vertex_array: GLuint,
|
||||||
|
vertex_buffer: Buffer,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl MaskTileVertexArray {
|
||||||
|
fn new(mask_tile_program: &MaskTileProgram, quad_vertex_positions_buffer: &Buffer)
|
||||||
|
-> MaskTileVertexArray {
|
||||||
|
let vertex_buffer = Buffer::new();
|
||||||
|
let mut gl_vertex_array = 0;
|
||||||
|
unsafe {
|
||||||
|
let tess_coord_attr = VertexAttr::new(&mask_tile_program.program, "TessCoord");
|
||||||
|
let tile_origin_attr = VertexAttr::new(&mask_tile_program.program, "TileOrigin");
|
||||||
|
let backdrop_attr = VertexAttr::new(&mask_tile_program.program, "Backdrop");
|
||||||
|
let object_attr = VertexAttr::new(&mask_tile_program.program, "Object");
|
||||||
|
|
||||||
|
gl::GenVertexArrays(1, &mut gl_vertex_array);
|
||||||
|
gl::BindVertexArray(gl_vertex_array);
|
||||||
|
gl::UseProgram(mask_tile_program.program.gl_program);
|
||||||
|
gl::BindBuffer(gl::ARRAY_BUFFER, quad_vertex_positions_buffer.gl_buffer);
|
||||||
|
tess_coord_attr.configure_float(2, gl::UNSIGNED_BYTE, false, 0, 0, 0);
|
||||||
|
gl::BindBuffer(gl::ARRAY_BUFFER, vertex_buffer.gl_buffer);
|
||||||
|
tile_origin_attr.configure_float(2, gl::SHORT, false, MASK_TILE_INSTANCE_SIZE, 0, 1);
|
||||||
|
backdrop_attr.configure_int(1, gl::SHORT, MASK_TILE_INSTANCE_SIZE, 4, 1);
|
||||||
|
object_attr.configure_int(2, gl::UNSIGNED_SHORT, MASK_TILE_INSTANCE_SIZE, 6, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
MaskTileVertexArray { gl_vertex_array, vertex_buffer }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Drop for MaskTileVertexArray {
|
||||||
|
#[inline]
|
||||||
|
fn drop(&mut self) {
|
||||||
|
unsafe {
|
||||||
|
gl::DeleteVertexArrays(1, &mut self.gl_vertex_array);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct SolidTileVertexArray {
|
||||||
|
gl_vertex_array: GLuint,
|
||||||
|
vertex_buffer: Buffer,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SolidTileVertexArray {
|
||||||
|
fn new(solid_tile_program: &SolidTileProgram, quad_vertex_positions_buffer: &Buffer)
|
||||||
|
-> SolidTileVertexArray {
|
||||||
|
let vertex_buffer = Buffer::new();
|
||||||
|
let mut gl_vertex_array = 0;
|
||||||
|
unsafe {
|
||||||
|
let tess_coord_attr = VertexAttr::new(&solid_tile_program.program, "TessCoord");
|
||||||
|
let tile_origin_attr = VertexAttr::new(&solid_tile_program.program, "TileOrigin");
|
||||||
|
let object_attr = VertexAttr::new(&solid_tile_program.program, "Object");
|
||||||
|
|
||||||
|
gl::GenVertexArrays(1, &mut gl_vertex_array);
|
||||||
|
gl::BindVertexArray(gl_vertex_array);
|
||||||
|
gl::UseProgram(solid_tile_program.program.gl_program);
|
||||||
|
gl::BindBuffer(gl::ARRAY_BUFFER, quad_vertex_positions_buffer.gl_buffer);
|
||||||
|
tess_coord_attr.configure_float(2, gl::UNSIGNED_BYTE, false, 0, 0, 0);
|
||||||
|
gl::BindBuffer(gl::ARRAY_BUFFER, vertex_buffer.gl_buffer);
|
||||||
|
tile_origin_attr.configure_float(2, gl::SHORT, false, SOLID_TILE_INSTANCE_SIZE, 0, 1);
|
||||||
|
object_attr.configure_int(1, gl::UNSIGNED_SHORT, SOLID_TILE_INSTANCE_SIZE, 4, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
SolidTileVertexArray { gl_vertex_array, vertex_buffer }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Drop for SolidTileVertexArray {
|
||||||
|
#[inline]
|
||||||
|
fn drop(&mut self) {
|
||||||
|
unsafe {
|
||||||
|
gl::DeleteVertexArrays(1, &mut self.gl_vertex_array);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct FillProgram {
|
||||||
|
program: Program,
|
||||||
|
framebuffer_size_uniform: Uniform,
|
||||||
|
tile_size_uniform: Uniform,
|
||||||
|
area_lut_uniform: Uniform,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FillProgram {
|
||||||
|
fn new() -> FillProgram {
|
||||||
|
let program = Program::new("fill");
|
||||||
|
let framebuffer_size_uniform = Uniform::new(&program, "FramebufferSize");
|
||||||
|
let tile_size_uniform = Uniform::new(&program, "TileSize");
|
||||||
|
let area_lut_uniform = Uniform::new(&program, "AreaLUT");
|
||||||
|
FillProgram { program, framebuffer_size_uniform, tile_size_uniform, area_lut_uniform }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct SolidTileProgram {
|
||||||
|
program: Program,
|
||||||
|
framebuffer_size_uniform: Uniform,
|
||||||
|
tile_size_uniform: Uniform,
|
||||||
|
fill_colors_texture_uniform: Uniform,
|
||||||
|
fill_colors_texture_size_uniform: Uniform,
|
||||||
|
view_box_origin_uniform: Uniform,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SolidTileProgram {
|
||||||
|
fn new() -> SolidTileProgram {
|
||||||
|
let program = Program::new("solid_tile");
|
||||||
|
let framebuffer_size_uniform = Uniform::new(&program, "FramebufferSize");
|
||||||
|
let tile_size_uniform = Uniform::new(&program, "TileSize");
|
||||||
|
let fill_colors_texture_uniform = Uniform::new(&program, "FillColorsTexture");
|
||||||
|
let fill_colors_texture_size_uniform = Uniform::new(&program, "FillColorsTextureSize");
|
||||||
|
let view_box_origin_uniform = Uniform::new(&program, "ViewBoxOrigin");
|
||||||
|
SolidTileProgram {
|
||||||
|
program,
|
||||||
|
framebuffer_size_uniform,
|
||||||
|
tile_size_uniform,
|
||||||
|
fill_colors_texture_uniform,
|
||||||
|
fill_colors_texture_size_uniform,
|
||||||
|
view_box_origin_uniform,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct MaskTileProgram {
|
||||||
|
program: Program,
|
||||||
|
framebuffer_size_uniform: Uniform,
|
||||||
|
tile_size_uniform: Uniform,
|
||||||
|
stencil_texture_uniform: Uniform,
|
||||||
|
stencil_texture_size_uniform: Uniform,
|
||||||
|
fill_colors_texture_uniform: Uniform,
|
||||||
|
fill_colors_texture_size_uniform: Uniform,
|
||||||
|
view_box_origin_uniform: Uniform,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl MaskTileProgram {
|
||||||
|
fn new() -> MaskTileProgram {
|
||||||
|
let program = Program::new("mask_tile");
|
||||||
|
let framebuffer_size_uniform = Uniform::new(&program, "FramebufferSize");
|
||||||
|
let tile_size_uniform = Uniform::new(&program, "TileSize");
|
||||||
|
let stencil_texture_uniform = Uniform::new(&program, "StencilTexture");
|
||||||
|
let stencil_texture_size_uniform = Uniform::new(&program, "StencilTextureSize");
|
||||||
|
let fill_colors_texture_uniform = Uniform::new(&program, "FillColorsTexture");
|
||||||
|
let fill_colors_texture_size_uniform = Uniform::new(&program, "FillColorsTextureSize");
|
||||||
|
let view_box_origin_uniform = Uniform::new(&program, "ViewBoxOrigin");
|
||||||
|
MaskTileProgram {
|
||||||
|
program,
|
||||||
|
framebuffer_size_uniform,
|
||||||
|
tile_size_uniform,
|
||||||
|
stencil_texture_uniform,
|
||||||
|
stencil_texture_size_uniform,
|
||||||
|
fill_colors_texture_uniform,
|
||||||
|
fill_colors_texture_size_uniform,
|
||||||
|
view_box_origin_uniform,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue