diff --git a/canvas/src/lib.rs b/canvas/src/lib.rs index 7a4ecea8..20705451 100644 --- a/canvas/src/lib.rs +++ b/canvas/src/lib.rs @@ -173,9 +173,11 @@ impl CanvasRenderingContext2D { let mut stroke_style = self.current_state.resolve_stroke_style(); - // the smaller scale is relevant here, as we multiply by it and want to ensure it is always bigger than HAIRLINE_STROKE_WIDTH - let transform_scale = f32::min(self.current_state.transform.m11(), self.current_state.transform.m22()); - // avoid the division in the normal case of sufficient thickness + // The smaller scale is relevant here, as we multiply by it and want to ensure it is always + // bigger than `HAIRLINE_STROKE_WIDTH`. + let transform_scale = f32::min(self.current_state.transform.m11(), + self.current_state.transform.m22()); + // Avoid the division in the normal case of sufficient thickness. if stroke_style.line_width * transform_scale < HAIRLINE_STROKE_WIDTH { stroke_style.line_width = HAIRLINE_STROKE_WIDTH / transform_scale; } diff --git a/export/src/lib.rs b/export/src/lib.rs index d37df9c0..cbd468d9 100644 --- a/export/src/lib.rs +++ b/export/src/lib.rs @@ -81,6 +81,9 @@ fn export_pdf(scene: &Scene, writer: &mut W) -> io::Result<()> { Paint::Gradient(_) => { // TODO(pcwalton): Gradients. } + Paint::Pattern(_) => { + // TODO(pcwalton): Patterns. + } } for contour in outline.contours() { @@ -184,6 +187,9 @@ fn export_ps(scene: &Scene, writer: &mut W) -> io::Result<()> { Paint::Gradient(_) => { // TODO(pcwalton): Gradients. } + Paint::Pattern(_) => { + // TODO(pcwalton): Patterns. + } } writeln!(writer, "fill")?; diff --git a/renderer/src/gpu/mod.rs b/renderer/src/gpu/mod.rs index a5e818e0..9d005dec 100644 --- a/renderer/src/gpu/mod.rs +++ b/renderer/src/gpu/mod.rs @@ -13,3 +13,5 @@ pub mod debug; pub mod options; pub mod renderer; + +pub(crate) mod shaders; diff --git a/renderer/src/gpu/renderer.rs b/renderer/src/gpu/renderer.rs index b4d818b0..afdbde8b 100644 --- a/renderer/src/gpu/renderer.rs +++ b/renderer/src/gpu/renderer.rs @@ -1,6 +1,6 @@ // pathfinder/renderer/src/gpu/renderer.rs // -// Copyright © 2019 The Pathfinder Project Developers. +// Copyright © 2020 The Pathfinder Project Developers. // // Licensed under the Apache License, Version 2.0 or the MIT license @@ -10,6 +10,10 @@ use crate::gpu::debug::DebugUIPresenter; use crate::gpu::options::{DestFramebuffer, RendererOptions}; +use crate::gpu::shaders::{FillProgram, AlphaTileProgram, AlphaTileVertexArray, FillVertexArray}; +use crate::gpu::shaders::{MAX_FILLS_PER_BATCH, PostprocessProgram, PostprocessVertexArray}; +use crate::gpu::shaders::{ReprojectionProgram, ReprojectionVertexArray, SolidTileProgram}; +use crate::gpu::shaders::{SolidTileVertexArray, StencilProgram, StencilVertexArray}; use crate::gpu_data::{AlphaTile, FillBatchPrimitive, PaintData, RenderCommand, SolidTileVertex}; use crate::post::DefringingKernel; use crate::tiles::{TILE_HEIGHT, TILE_WIDTH}; @@ -20,8 +24,8 @@ use pathfinder_geometry::transform3d::Transform4F; use pathfinder_gpu::resources::ResourceLoader; use pathfinder_gpu::{BlendFunc, BlendState, BufferData, BufferTarget, BufferUploadMode, ClearOps}; use pathfinder_gpu::{DepthFunc, DepthState, Device, Primitive, RenderOptions, RenderState}; -use pathfinder_gpu::{RenderTarget, StencilFunc, StencilState, TextureDataRef, TextureFormat}; -use pathfinder_gpu::{UniformData, VertexAttrClass, VertexAttrDescriptor, VertexAttrType}; +use pathfinder_gpu::{RenderTarget, StencilFunc, StencilState, TextureDataRef}; +use pathfinder_gpu::{TextureFormat, UniformData}; use pathfinder_simd::default::{F32x2, F32x4}; use std::cmp; use std::collections::VecDeque; @@ -40,13 +44,6 @@ pub(crate) const MASK_TILES_DOWN: u32 = 256; const MASK_FRAMEBUFFER_WIDTH: i32 = TILE_WIDTH as i32 * MASK_TILES_ACROSS as i32; const MASK_FRAMEBUFFER_HEIGHT: i32 = TILE_HEIGHT as i32 * MASK_TILES_DOWN as i32; -// TODO(pcwalton): Replace with `mem::size_of` calls? -const FILL_INSTANCE_SIZE: usize = 8; -const SOLID_TILE_VERTEX_SIZE: usize = 12; -const MASK_TILE_VERTEX_SIZE: usize = 16; - -const MAX_FILLS_PER_BATCH: usize = 0x4000; - pub struct Renderer where D: Device, @@ -836,8 +833,8 @@ where } fn mask_viewport(&self) -> RectI { - let texture = self.device.framebuffer_texture(&self.mask_framebuffer); - RectI::new(Vector2I::default(), self.device.texture_size(texture)) + RectI::new(Vector2I::default(), + Vector2I::new(MASK_FRAMEBUFFER_WIDTH, MASK_FRAMEBUFFER_HEIGHT)) } fn allocate_timer_query(&mut self) -> D::TimerQuery { @@ -860,512 +857,6 @@ where } } -struct FillVertexArray -where - D: Device, -{ - vertex_array: D::VertexArray, - vertex_buffer: D::Buffer, -} - -impl FillVertexArray -where - D: Device, -{ - fn new( - device: &D, - fill_program: &FillProgram, - quad_vertex_positions_buffer: &D::Buffer, - quad_vertex_indices_buffer: &D::Buffer, - ) -> FillVertexArray { - let vertex_array = device.create_vertex_array(); - - let vertex_buffer = device.create_buffer(); - let vertex_buffer_data: BufferData = - BufferData::Uninitialized(MAX_FILLS_PER_BATCH); - device.allocate_buffer( - &vertex_buffer, - vertex_buffer_data, - BufferTarget::Vertex, - BufferUploadMode::Dynamic, - ); - - let tess_coord_attr = device.get_vertex_attr(&fill_program.program, "TessCoord").unwrap(); - let from_px_attr = device.get_vertex_attr(&fill_program.program, "FromPx").unwrap(); - let to_px_attr = device.get_vertex_attr(&fill_program.program, "ToPx").unwrap(); - let from_subpx_attr = device.get_vertex_attr(&fill_program.program, "FromSubpx").unwrap(); - let to_subpx_attr = device.get_vertex_attr(&fill_program.program, "ToSubpx").unwrap(); - let tile_index_attr = device.get_vertex_attr(&fill_program.program, "TileIndex").unwrap(); - - device.bind_buffer(&vertex_array, quad_vertex_positions_buffer, BufferTarget::Vertex); - device.configure_vertex_attr(&vertex_array, &tess_coord_attr, &VertexAttrDescriptor { - size: 2, - class: VertexAttrClass::Int, - attr_type: VertexAttrType::U16, - stride: 4, - offset: 0, - divisor: 0, - buffer_index: 0, - }); - device.bind_buffer(&vertex_array, &vertex_buffer, BufferTarget::Vertex); - device.configure_vertex_attr(&vertex_array, &from_px_attr, &VertexAttrDescriptor { - size: 1, - class: VertexAttrClass::Int, - attr_type: VertexAttrType::U8, - stride: FILL_INSTANCE_SIZE, - offset: 0, - divisor: 1, - buffer_index: 1, - }); - device.configure_vertex_attr(&vertex_array, &to_px_attr, &VertexAttrDescriptor { - size: 1, - class: VertexAttrClass::Int, - attr_type: VertexAttrType::U8, - stride: FILL_INSTANCE_SIZE, - offset: 1, - divisor: 1, - buffer_index: 1, - }); - device.configure_vertex_attr(&vertex_array, &from_subpx_attr, &VertexAttrDescriptor { - size: 2, - class: VertexAttrClass::FloatNorm, - attr_type: VertexAttrType::U8, - stride: FILL_INSTANCE_SIZE, - offset: 2, - divisor: 1, - buffer_index: 1, - }); - device.configure_vertex_attr(&vertex_array, &to_subpx_attr, &VertexAttrDescriptor { - size: 2, - class: VertexAttrClass::FloatNorm, - attr_type: VertexAttrType::U8, - stride: FILL_INSTANCE_SIZE, - offset: 4, - divisor: 1, - buffer_index: 1, - }); - device.configure_vertex_attr(&vertex_array, &tile_index_attr, &VertexAttrDescriptor { - size: 1, - class: VertexAttrClass::Int, - attr_type: VertexAttrType::U16, - stride: FILL_INSTANCE_SIZE, - offset: 6, - divisor: 1, - buffer_index: 1, - }); - device.bind_buffer(&vertex_array, quad_vertex_indices_buffer, BufferTarget::Index); - - FillVertexArray { vertex_array, vertex_buffer } - } -} - -struct AlphaTileVertexArray -where - D: Device, -{ - vertex_array: D::VertexArray, - vertex_buffer: D::Buffer, -} - -impl AlphaTileVertexArray -where - D: Device, -{ - fn new( - device: &D, - alpha_tile_program: &AlphaTileProgram, - quads_vertex_indices_buffer: &D::Buffer, - ) -> AlphaTileVertexArray { - let (vertex_array, vertex_buffer) = (device.create_vertex_array(), device.create_buffer()); - - let tile_position_attr = - device.get_vertex_attr(&alpha_tile_program.program, "TilePosition").unwrap(); - let color_tex_coord_attr = device.get_vertex_attr(&alpha_tile_program.program, - "ColorTexCoord").unwrap(); - let mask_tex_coord_attr = device.get_vertex_attr(&alpha_tile_program.program, - "MaskTexCoord").unwrap(); - let backdrop_attr = device.get_vertex_attr(&alpha_tile_program.program, "Backdrop") - .unwrap(); - - device.bind_buffer(&vertex_array, &vertex_buffer, BufferTarget::Vertex); - device.configure_vertex_attr(&vertex_array, &tile_position_attr, &VertexAttrDescriptor { - size: 2, - class: VertexAttrClass::Int, - attr_type: VertexAttrType::I16, - stride: MASK_TILE_VERTEX_SIZE, - offset: 0, - divisor: 0, - buffer_index: 0, - }); - device.configure_vertex_attr(&vertex_array, &color_tex_coord_attr, &VertexAttrDescriptor { - size: 2, - class: VertexAttrClass::FloatNorm, - attr_type: VertexAttrType::U16, - stride: MASK_TILE_VERTEX_SIZE, - offset: 4, - divisor: 0, - buffer_index: 0, - }); - device.configure_vertex_attr(&vertex_array, &mask_tex_coord_attr, &VertexAttrDescriptor { - size: 2, - class: VertexAttrClass::FloatNorm, - attr_type: VertexAttrType::U16, - stride: MASK_TILE_VERTEX_SIZE, - offset: 8, - divisor: 0, - buffer_index: 0, - }); - device.configure_vertex_attr(&vertex_array, &backdrop_attr, &VertexAttrDescriptor { - size: 1, - class: VertexAttrClass::Int, - attr_type: VertexAttrType::I16, - stride: MASK_TILE_VERTEX_SIZE, - offset: 12, - divisor: 0, - buffer_index: 0, - }); - device.bind_buffer(&vertex_array, quads_vertex_indices_buffer, BufferTarget::Index); - - AlphaTileVertexArray { vertex_array, vertex_buffer } - } -} - -struct SolidTileVertexArray -where - D: Device, -{ - vertex_array: D::VertexArray, - vertex_buffer: D::Buffer, -} - -impl SolidTileVertexArray -where - D: Device, -{ - fn new( - device: &D, - solid_tile_program: &SolidTileProgram, - quads_vertex_indices_buffer: &D::Buffer, - ) -> SolidTileVertexArray { - let (vertex_array, vertex_buffer) = (device.create_vertex_array(), device.create_buffer()); - - let tile_position_attr = - device.get_vertex_attr(&solid_tile_program.program, "TilePosition").unwrap(); - let color_tex_coord_attr = - device.get_vertex_attr(&solid_tile_program.program, "ColorTexCoord").unwrap(); - - // NB: The tile origin must be of type short, not unsigned short, to work around a macOS - // Radeon driver bug. - device.bind_buffer(&vertex_array, &vertex_buffer, BufferTarget::Vertex); - device.configure_vertex_attr(&vertex_array, &tile_position_attr, &VertexAttrDescriptor { - size: 2, - class: VertexAttrClass::Int, - attr_type: VertexAttrType::I16, - stride: SOLID_TILE_VERTEX_SIZE, - offset: 0, - divisor: 0, - buffer_index: 0, - }); - device.configure_vertex_attr(&vertex_array, - &color_tex_coord_attr, - &VertexAttrDescriptor { - size: 2, - class: VertexAttrClass::FloatNorm, - attr_type: VertexAttrType::U16, - stride: SOLID_TILE_VERTEX_SIZE, - offset: 4, - divisor: 0, - buffer_index: 0, - }); - device.bind_buffer(&vertex_array, quads_vertex_indices_buffer, BufferTarget::Index); - - SolidTileVertexArray { vertex_array, vertex_buffer } - } -} - -struct FillProgram -where - D: Device, -{ - program: D::Program, - framebuffer_size_uniform: D::Uniform, - tile_size_uniform: D::Uniform, - area_lut_uniform: D::Uniform, -} - -impl FillProgram -where - D: Device, -{ - fn new(device: &D, resources: &dyn ResourceLoader) -> FillProgram { - let program = device.create_program(resources, "fill"); - let framebuffer_size_uniform = device.get_uniform(&program, "FramebufferSize"); - let tile_size_uniform = device.get_uniform(&program, "TileSize"); - let area_lut_uniform = device.get_uniform(&program, "AreaLUT"); - FillProgram { - program, - framebuffer_size_uniform, - tile_size_uniform, - area_lut_uniform, - } - } -} - -struct SolidTileProgram where D: Device { - program: D::Program, - transform_uniform: D::Uniform, - tile_size_uniform: D::Uniform, - paint_texture_uniform: D::Uniform, - paint_texture_size_uniform: D::Uniform, -} - -impl SolidTileProgram where D: Device { - fn new(device: &D, resources: &dyn ResourceLoader) -> SolidTileProgram { - let program = device.create_program(resources, "tile_solid"); - let transform_uniform = device.get_uniform(&program, "Transform"); - let tile_size_uniform = device.get_uniform(&program, "TileSize"); - let paint_texture_uniform = device.get_uniform(&program, "PaintTexture"); - let paint_texture_size_uniform = device.get_uniform(&program, "PaintTextureSize"); - SolidTileProgram { - program, - transform_uniform, - tile_size_uniform, - paint_texture_uniform, - paint_texture_size_uniform, - } - } -} - -struct AlphaTileProgram where D: Device { - program: D::Program, - transform_uniform: D::Uniform, - tile_size_uniform: D::Uniform, - stencil_texture_uniform: D::Uniform, - stencil_texture_size_uniform: D::Uniform, - paint_texture_uniform: D::Uniform, - paint_texture_size_uniform: D::Uniform, -} - -impl AlphaTileProgram where D: Device { - fn new(device: &D, resources: &dyn ResourceLoader) -> AlphaTileProgram { - let program = device.create_program(resources, "tile_alpha"); - let transform_uniform = device.get_uniform(&program, "Transform"); - let tile_size_uniform = device.get_uniform(&program, "TileSize"); - let stencil_texture_uniform = device.get_uniform(&program, "StencilTexture"); - let stencil_texture_size_uniform = device.get_uniform(&program, "StencilTextureSize"); - let paint_texture_uniform = device.get_uniform(&program, "PaintTexture"); - let paint_texture_size_uniform = device.get_uniform(&program, "PaintTextureSize"); - AlphaTileProgram { - program, - transform_uniform, - tile_size_uniform, - stencil_texture_uniform, - stencil_texture_size_uniform, - paint_texture_uniform, - paint_texture_size_uniform, - } - } -} - -struct PostprocessProgram -where - D: Device, -{ - program: D::Program, - source_uniform: D::Uniform, - source_size_uniform: D::Uniform, - framebuffer_size_uniform: D::Uniform, - kernel_uniform: D::Uniform, - gamma_lut_uniform: D::Uniform, - gamma_correction_enabled_uniform: D::Uniform, - fg_color_uniform: D::Uniform, - bg_color_uniform: D::Uniform, -} - -impl PostprocessProgram -where - D: Device, -{ - fn new(device: &D, resources: &dyn ResourceLoader) -> PostprocessProgram { - let program = device.create_program(resources, "post"); - let source_uniform = device.get_uniform(&program, "Source"); - let source_size_uniform = device.get_uniform(&program, "SourceSize"); - let framebuffer_size_uniform = device.get_uniform(&program, "FramebufferSize"); - let kernel_uniform = device.get_uniform(&program, "Kernel"); - let gamma_lut_uniform = device.get_uniform(&program, "GammaLUT"); - let gamma_correction_enabled_uniform = device.get_uniform(&program, - "GammaCorrectionEnabled"); - let fg_color_uniform = device.get_uniform(&program, "FGColor"); - let bg_color_uniform = device.get_uniform(&program, "BGColor"); - PostprocessProgram { - program, - source_uniform, - source_size_uniform, - framebuffer_size_uniform, - kernel_uniform, - gamma_lut_uniform, - gamma_correction_enabled_uniform, - fg_color_uniform, - bg_color_uniform, - } - } -} - -struct PostprocessVertexArray -where - D: Device, -{ - vertex_array: D::VertexArray, -} - -impl PostprocessVertexArray -where - D: Device, -{ - fn new( - device: &D, - postprocess_program: &PostprocessProgram, - quad_vertex_positions_buffer: &D::Buffer, - quad_vertex_indices_buffer: &D::Buffer, - ) -> PostprocessVertexArray { - let vertex_array = device.create_vertex_array(); - let position_attr = device.get_vertex_attr(&postprocess_program.program, "Position") - .unwrap(); - - device.bind_buffer(&vertex_array, quad_vertex_positions_buffer, BufferTarget::Vertex); - device.configure_vertex_attr(&vertex_array, &position_attr, &VertexAttrDescriptor { - size: 2, - class: VertexAttrClass::Int, - attr_type: VertexAttrType::I16, - stride: 4, - offset: 0, - divisor: 0, - buffer_index: 0, - }); - device.bind_buffer(&vertex_array, quad_vertex_indices_buffer, BufferTarget::Index); - - PostprocessVertexArray { vertex_array } - } -} - -struct StencilProgram -where - D: Device, -{ - program: D::Program, -} - -impl StencilProgram -where - D: Device, -{ - fn new(device: &D, resources: &dyn ResourceLoader) -> StencilProgram { - let program = device.create_program(resources, "stencil"); - StencilProgram { program } - } -} - -struct StencilVertexArray -where - D: Device, -{ - vertex_array: D::VertexArray, - vertex_buffer: D::Buffer, - index_buffer: D::Buffer, -} - -impl StencilVertexArray -where - D: Device, -{ - fn new(device: &D, stencil_program: &StencilProgram) -> StencilVertexArray { - let vertex_array = device.create_vertex_array(); - let (vertex_buffer, index_buffer) = (device.create_buffer(), device.create_buffer()); - - let position_attr = device.get_vertex_attr(&stencil_program.program, "Position").unwrap(); - - device.bind_buffer(&vertex_array, &vertex_buffer, BufferTarget::Vertex); - device.configure_vertex_attr(&vertex_array, &position_attr, &VertexAttrDescriptor { - size: 3, - class: VertexAttrClass::Float, - attr_type: VertexAttrType::F32, - stride: 4 * 4, - offset: 0, - divisor: 0, - buffer_index: 0, - }); - device.bind_buffer(&vertex_array, &index_buffer, BufferTarget::Index); - - StencilVertexArray { vertex_array, vertex_buffer, index_buffer } - } -} - -struct ReprojectionProgram -where - D: Device, -{ - program: D::Program, - old_transform_uniform: D::Uniform, - new_transform_uniform: D::Uniform, - texture_uniform: D::Uniform, -} - -impl ReprojectionProgram -where - D: Device, -{ - fn new(device: &D, resources: &dyn ResourceLoader) -> ReprojectionProgram { - let program = device.create_program(resources, "reproject"); - let old_transform_uniform = device.get_uniform(&program, "OldTransform"); - let new_transform_uniform = device.get_uniform(&program, "NewTransform"); - let texture_uniform = device.get_uniform(&program, "Texture"); - - ReprojectionProgram { - program, - old_transform_uniform, - new_transform_uniform, - texture_uniform, - } - } -} - -struct ReprojectionVertexArray -where - D: Device, -{ - vertex_array: D::VertexArray, -} - -impl ReprojectionVertexArray -where - D: Device, -{ - fn new( - device: &D, - reprojection_program: &ReprojectionProgram, - quad_vertex_positions_buffer: &D::Buffer, - quad_vertex_indices_buffer: &D::Buffer, - ) -> ReprojectionVertexArray { - let vertex_array = device.create_vertex_array(); - let position_attr = device.get_vertex_attr(&reprojection_program.program, "Position") - .unwrap(); - - device.bind_buffer(&vertex_array, quad_vertex_positions_buffer, BufferTarget::Vertex); - device.configure_vertex_attr(&vertex_array, &position_attr, &VertexAttrDescriptor { - size: 2, - class: VertexAttrClass::Int, - attr_type: VertexAttrType::I16, - stride: 4, - offset: 0, - divisor: 0, - buffer_index: 0, - }); - device.bind_buffer(&vertex_array, quad_vertex_indices_buffer, BufferTarget::Index); - - ReprojectionVertexArray { vertex_array } - } -} - #[derive(Clone, Copy, Default)] pub struct PostprocessOptions { pub fg_color: ColorF, @@ -1374,6 +865,8 @@ pub struct PostprocessOptions { pub gamma_correction: bool, } +// Render stats + #[derive(Clone, Copy, Debug, Default)] pub struct RenderStats { pub path_count: usize, diff --git a/renderer/src/gpu/shaders.rs b/renderer/src/gpu/shaders.rs new file mode 100644 index 00000000..83ac7e39 --- /dev/null +++ b/renderer/src/gpu/shaders.rs @@ -0,0 +1,526 @@ +// pathfinder/renderer/src/gpu/shaders.rs +// +// Copyright © 2020 The Pathfinder Project Developers. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use crate::gpu_data::FillBatchPrimitive; +use pathfinder_gpu::{BufferData, BufferTarget, BufferUploadMode, Device, VertexAttrClass, VertexAttrDescriptor, VertexAttrType}; +use pathfinder_gpu::resources::ResourceLoader; + +// TODO(pcwalton): Replace with `mem::size_of` calls? +const FILL_INSTANCE_SIZE: usize = 8; +const SOLID_TILE_VERTEX_SIZE: usize = 12; +const MASK_TILE_VERTEX_SIZE: usize = 16; + +pub const MAX_FILLS_PER_BATCH: usize = 0x4000; + +pub struct FillVertexArray +where + D: Device, +{ + pub vertex_array: D::VertexArray, + pub vertex_buffer: D::Buffer, +} + +impl FillVertexArray +where + D: Device, +{ + pub fn new( + device: &D, + fill_program: &FillProgram, + quad_vertex_positions_buffer: &D::Buffer, + quad_vertex_indices_buffer: &D::Buffer, + ) -> FillVertexArray { + let vertex_array = device.create_vertex_array(); + + let vertex_buffer = device.create_buffer(); + let vertex_buffer_data: BufferData = + BufferData::Uninitialized(MAX_FILLS_PER_BATCH); + device.allocate_buffer( + &vertex_buffer, + vertex_buffer_data, + BufferTarget::Vertex, + BufferUploadMode::Dynamic, + ); + + let tess_coord_attr = device.get_vertex_attr(&fill_program.program, "TessCoord").unwrap(); + let from_px_attr = device.get_vertex_attr(&fill_program.program, "FromPx").unwrap(); + let to_px_attr = device.get_vertex_attr(&fill_program.program, "ToPx").unwrap(); + let from_subpx_attr = device.get_vertex_attr(&fill_program.program, "FromSubpx").unwrap(); + let to_subpx_attr = device.get_vertex_attr(&fill_program.program, "ToSubpx").unwrap(); + let tile_index_attr = device.get_vertex_attr(&fill_program.program, "TileIndex").unwrap(); + + device.bind_buffer(&vertex_array, quad_vertex_positions_buffer, BufferTarget::Vertex); + device.configure_vertex_attr(&vertex_array, &tess_coord_attr, &VertexAttrDescriptor { + size: 2, + class: VertexAttrClass::Int, + attr_type: VertexAttrType::U16, + stride: 4, + offset: 0, + divisor: 0, + buffer_index: 0, + }); + device.bind_buffer(&vertex_array, &vertex_buffer, BufferTarget::Vertex); + device.configure_vertex_attr(&vertex_array, &from_px_attr, &VertexAttrDescriptor { + size: 1, + class: VertexAttrClass::Int, + attr_type: VertexAttrType::U8, + stride: FILL_INSTANCE_SIZE, + offset: 0, + divisor: 1, + buffer_index: 1, + }); + device.configure_vertex_attr(&vertex_array, &to_px_attr, &VertexAttrDescriptor { + size: 1, + class: VertexAttrClass::Int, + attr_type: VertexAttrType::U8, + stride: FILL_INSTANCE_SIZE, + offset: 1, + divisor: 1, + buffer_index: 1, + }); + device.configure_vertex_attr(&vertex_array, &from_subpx_attr, &VertexAttrDescriptor { + size: 2, + class: VertexAttrClass::FloatNorm, + attr_type: VertexAttrType::U8, + stride: FILL_INSTANCE_SIZE, + offset: 2, + divisor: 1, + buffer_index: 1, + }); + device.configure_vertex_attr(&vertex_array, &to_subpx_attr, &VertexAttrDescriptor { + size: 2, + class: VertexAttrClass::FloatNorm, + attr_type: VertexAttrType::U8, + stride: FILL_INSTANCE_SIZE, + offset: 4, + divisor: 1, + buffer_index: 1, + }); + device.configure_vertex_attr(&vertex_array, &tile_index_attr, &VertexAttrDescriptor { + size: 1, + class: VertexAttrClass::Int, + attr_type: VertexAttrType::U16, + stride: FILL_INSTANCE_SIZE, + offset: 6, + divisor: 1, + buffer_index: 1, + }); + device.bind_buffer(&vertex_array, quad_vertex_indices_buffer, BufferTarget::Index); + + FillVertexArray { vertex_array, vertex_buffer } + } +} + +pub struct AlphaTileVertexArray +where + D: Device, +{ + pub vertex_array: D::VertexArray, + pub vertex_buffer: D::Buffer, +} + +impl AlphaTileVertexArray +where + D: Device, +{ + pub fn new( + device: &D, + alpha_tile_program: &AlphaTileProgram, + quads_vertex_indices_buffer: &D::Buffer, + ) -> AlphaTileVertexArray { + let (vertex_array, vertex_buffer) = (device.create_vertex_array(), device.create_buffer()); + + let tile_position_attr = + device.get_vertex_attr(&alpha_tile_program.program, "TilePosition").unwrap(); + let color_tex_coord_attr = device.get_vertex_attr(&alpha_tile_program.program, + "ColorTexCoord").unwrap(); + let mask_tex_coord_attr = device.get_vertex_attr(&alpha_tile_program.program, + "MaskTexCoord").unwrap(); + let backdrop_attr = device.get_vertex_attr(&alpha_tile_program.program, "Backdrop") + .unwrap(); + + device.bind_buffer(&vertex_array, &vertex_buffer, BufferTarget::Vertex); + device.configure_vertex_attr(&vertex_array, &tile_position_attr, &VertexAttrDescriptor { + size: 2, + class: VertexAttrClass::Int, + attr_type: VertexAttrType::I16, + stride: MASK_TILE_VERTEX_SIZE, + offset: 0, + divisor: 0, + buffer_index: 0, + }); + device.configure_vertex_attr(&vertex_array, &mask_tex_coord_attr, &VertexAttrDescriptor { + size: 2, + class: VertexAttrClass::FloatNorm, + attr_type: VertexAttrType::U16, + stride: MASK_TILE_VERTEX_SIZE, + offset: 4, + divisor: 0, + buffer_index: 0, + }); + device.configure_vertex_attr(&vertex_array, &color_tex_coord_attr, &VertexAttrDescriptor { + size: 2, + class: VertexAttrClass::FloatNorm, + attr_type: VertexAttrType::U16, + stride: MASK_TILE_VERTEX_SIZE, + offset: 8, + divisor: 0, + buffer_index: 0, + }); + device.configure_vertex_attr(&vertex_array, &backdrop_attr, &VertexAttrDescriptor { + size: 1, + class: VertexAttrClass::Int, + attr_type: VertexAttrType::I16, + stride: MASK_TILE_VERTEX_SIZE, + offset: 12, + divisor: 0, + buffer_index: 0, + }); + device.bind_buffer(&vertex_array, quads_vertex_indices_buffer, BufferTarget::Index); + + AlphaTileVertexArray { vertex_array, vertex_buffer } + } +} + +pub struct SolidTileVertexArray +where + D: Device, +{ + pub vertex_array: D::VertexArray, + pub vertex_buffer: D::Buffer, +} + +impl SolidTileVertexArray +where + D: Device, +{ + pub fn new( + device: &D, + solid_tile_program: &SolidTileProgram, + quads_vertex_indices_buffer: &D::Buffer, + ) -> SolidTileVertexArray { + let (vertex_array, vertex_buffer) = (device.create_vertex_array(), device.create_buffer()); + + let tile_position_attr = + device.get_vertex_attr(&solid_tile_program.program, "TilePosition").unwrap(); + let color_tex_coord_attr = + device.get_vertex_attr(&solid_tile_program.program, "ColorTexCoord").unwrap(); + + // NB: The tile origin must be of type short, not unsigned short, to work around a macOS + // Radeon driver bug. + device.bind_buffer(&vertex_array, &vertex_buffer, BufferTarget::Vertex); + device.configure_vertex_attr(&vertex_array, &tile_position_attr, &VertexAttrDescriptor { + size: 2, + class: VertexAttrClass::Int, + attr_type: VertexAttrType::I16, + stride: SOLID_TILE_VERTEX_SIZE, + offset: 0, + divisor: 0, + buffer_index: 0, + }); + device.configure_vertex_attr(&vertex_array, + &color_tex_coord_attr, + &VertexAttrDescriptor { + size: 2, + class: VertexAttrClass::FloatNorm, + attr_type: VertexAttrType::U16, + stride: SOLID_TILE_VERTEX_SIZE, + offset: 4, + divisor: 0, + buffer_index: 0, + }); + device.bind_buffer(&vertex_array, quads_vertex_indices_buffer, BufferTarget::Index); + + SolidTileVertexArray { vertex_array, vertex_buffer } + } +} + +pub struct FillProgram +where + D: Device, +{ + pub program: D::Program, + pub framebuffer_size_uniform: D::Uniform, + pub tile_size_uniform: D::Uniform, + pub area_lut_uniform: D::Uniform, +} + +impl FillProgram +where + D: Device, +{ + pub fn new(device: &D, resources: &dyn ResourceLoader) -> FillProgram { + let program = device.create_program(resources, "fill"); + let framebuffer_size_uniform = device.get_uniform(&program, "FramebufferSize"); + let tile_size_uniform = device.get_uniform(&program, "TileSize"); + let area_lut_uniform = device.get_uniform(&program, "AreaLUT"); + FillProgram { + program, + framebuffer_size_uniform, + tile_size_uniform, + area_lut_uniform, + } + } +} + +pub struct SolidTileProgram where D: Device { + pub program: D::Program, + pub transform_uniform: D::Uniform, + pub tile_size_uniform: D::Uniform, + pub paint_texture_uniform: D::Uniform, + pub paint_texture_size_uniform: D::Uniform, +} + +impl SolidTileProgram where D: Device { + pub fn new(device: &D, resources: &dyn ResourceLoader) -> SolidTileProgram { + let program = device.create_program(resources, "tile_solid"); + let transform_uniform = device.get_uniform(&program, "Transform"); + let tile_size_uniform = device.get_uniform(&program, "TileSize"); + let paint_texture_uniform = device.get_uniform(&program, "PaintTexture"); + let paint_texture_size_uniform = device.get_uniform(&program, "PaintTextureSize"); + SolidTileProgram { + program, + transform_uniform, + tile_size_uniform, + paint_texture_uniform, + paint_texture_size_uniform, + } + } +} + +pub struct AlphaTileProgram where D: Device { + pub program: D::Program, + pub transform_uniform: D::Uniform, + pub tile_size_uniform: D::Uniform, + pub stencil_texture_uniform: D::Uniform, + pub stencil_texture_size_uniform: D::Uniform, + pub paint_texture_uniform: D::Uniform, + pub paint_texture_size_uniform: D::Uniform, +} + +impl AlphaTileProgram where D: Device { + pub fn new(device: &D, resources: &dyn ResourceLoader) -> AlphaTileProgram { + let program = device.create_program(resources, "tile_alpha"); + let transform_uniform = device.get_uniform(&program, "Transform"); + let tile_size_uniform = device.get_uniform(&program, "TileSize"); + let stencil_texture_uniform = device.get_uniform(&program, "StencilTexture"); + let stencil_texture_size_uniform = device.get_uniform(&program, "StencilTextureSize"); + let paint_texture_uniform = device.get_uniform(&program, "PaintTexture"); + let paint_texture_size_uniform = device.get_uniform(&program, "PaintTextureSize"); + AlphaTileProgram { + program, + transform_uniform, + tile_size_uniform, + stencil_texture_uniform, + stencil_texture_size_uniform, + paint_texture_uniform, + paint_texture_size_uniform, + } + } +} + +pub struct PostprocessProgram +where + D: Device, +{ + pub program: D::Program, + pub source_uniform: D::Uniform, + pub source_size_uniform: D::Uniform, + pub framebuffer_size_uniform: D::Uniform, + pub kernel_uniform: D::Uniform, + pub gamma_lut_uniform: D::Uniform, + pub gamma_correction_enabled_uniform: D::Uniform, + pub fg_color_uniform: D::Uniform, + pub bg_color_uniform: D::Uniform, +} + +impl PostprocessProgram +where + D: Device, +{ + pub fn new(device: &D, resources: &dyn ResourceLoader) -> PostprocessProgram { + let program = device.create_program(resources, "post"); + let source_uniform = device.get_uniform(&program, "Source"); + let source_size_uniform = device.get_uniform(&program, "SourceSize"); + let framebuffer_size_uniform = device.get_uniform(&program, "FramebufferSize"); + let kernel_uniform = device.get_uniform(&program, "Kernel"); + let gamma_lut_uniform = device.get_uniform(&program, "GammaLUT"); + let gamma_correction_enabled_uniform = device.get_uniform(&program, + "GammaCorrectionEnabled"); + let fg_color_uniform = device.get_uniform(&program, "FGColor"); + let bg_color_uniform = device.get_uniform(&program, "BGColor"); + PostprocessProgram { + program, + source_uniform, + source_size_uniform, + framebuffer_size_uniform, + kernel_uniform, + gamma_lut_uniform, + gamma_correction_enabled_uniform, + fg_color_uniform, + bg_color_uniform, + } + } +} + +pub struct PostprocessVertexArray +where + D: Device, +{ + pub vertex_array: D::VertexArray, +} + +impl PostprocessVertexArray +where + D: Device, +{ + pub fn new( + device: &D, + postprocess_program: &PostprocessProgram, + quad_vertex_positions_buffer: &D::Buffer, + quad_vertex_indices_buffer: &D::Buffer, + ) -> PostprocessVertexArray { + let vertex_array = device.create_vertex_array(); + let position_attr = device.get_vertex_attr(&postprocess_program.program, "Position") + .unwrap(); + + device.bind_buffer(&vertex_array, quad_vertex_positions_buffer, BufferTarget::Vertex); + device.configure_vertex_attr(&vertex_array, &position_attr, &VertexAttrDescriptor { + size: 2, + class: VertexAttrClass::Int, + attr_type: VertexAttrType::I16, + stride: 4, + offset: 0, + divisor: 0, + buffer_index: 0, + }); + device.bind_buffer(&vertex_array, quad_vertex_indices_buffer, BufferTarget::Index); + + PostprocessVertexArray { vertex_array } + } +} + +pub struct StencilProgram +where + D: Device, +{ + pub program: D::Program, +} + +impl StencilProgram +where + D: Device, +{ + pub fn new(device: &D, resources: &dyn ResourceLoader) -> StencilProgram { + let program = device.create_program(resources, "stencil"); + StencilProgram { program } + } +} + +pub struct StencilVertexArray +where + D: Device, +{ + pub vertex_array: D::VertexArray, + pub vertex_buffer: D::Buffer, + pub index_buffer: D::Buffer, +} + +impl StencilVertexArray +where + D: Device, +{ + pub fn new(device: &D, stencil_program: &StencilProgram) -> StencilVertexArray { + let vertex_array = device.create_vertex_array(); + let (vertex_buffer, index_buffer) = (device.create_buffer(), device.create_buffer()); + + let position_attr = device.get_vertex_attr(&stencil_program.program, "Position").unwrap(); + + device.bind_buffer(&vertex_array, &vertex_buffer, BufferTarget::Vertex); + device.configure_vertex_attr(&vertex_array, &position_attr, &VertexAttrDescriptor { + size: 3, + class: VertexAttrClass::Float, + attr_type: VertexAttrType::F32, + stride: 4 * 4, + offset: 0, + divisor: 0, + buffer_index: 0, + }); + device.bind_buffer(&vertex_array, &index_buffer, BufferTarget::Index); + + StencilVertexArray { vertex_array, vertex_buffer, index_buffer } + } +} + +pub struct ReprojectionProgram +where + D: Device, +{ + pub program: D::Program, + pub old_transform_uniform: D::Uniform, + pub new_transform_uniform: D::Uniform, + pub texture_uniform: D::Uniform, +} + +impl ReprojectionProgram +where + D: Device, +{ + pub fn new(device: &D, resources: &dyn ResourceLoader) -> ReprojectionProgram { + let program = device.create_program(resources, "reproject"); + let old_transform_uniform = device.get_uniform(&program, "OldTransform"); + let new_transform_uniform = device.get_uniform(&program, "NewTransform"); + let texture_uniform = device.get_uniform(&program, "Texture"); + + ReprojectionProgram { + program, + old_transform_uniform, + new_transform_uniform, + texture_uniform, + } + } +} + +pub struct ReprojectionVertexArray +where + D: Device, +{ + pub vertex_array: D::VertexArray, +} + +impl ReprojectionVertexArray +where + D: Device, +{ + pub fn new( + device: &D, + reprojection_program: &ReprojectionProgram, + quad_vertex_positions_buffer: &D::Buffer, + quad_vertex_indices_buffer: &D::Buffer, + ) -> ReprojectionVertexArray { + let vertex_array = device.create_vertex_array(); + let position_attr = device.get_vertex_attr(&reprojection_program.program, "Position") + .unwrap(); + + device.bind_buffer(&vertex_array, quad_vertex_positions_buffer, BufferTarget::Vertex); + device.configure_vertex_attr(&vertex_array, &position_attr, &VertexAttrDescriptor { + size: 2, + class: VertexAttrClass::Int, + attr_type: VertexAttrType::I16, + stride: 4, + offset: 0, + divisor: 0, + buffer_index: 0, + }); + device.bind_buffer(&vertex_array, quad_vertex_indices_buffer, BufferTarget::Index); + + ReprojectionVertexArray { vertex_array } + } +} diff --git a/renderer/src/gpu_data.rs b/renderer/src/gpu_data.rs index 67180634..fa09d83a 100644 --- a/renderer/src/gpu_data.rs +++ b/renderer/src/gpu_data.rs @@ -93,10 +93,10 @@ pub struct AlphaTile { pub struct AlphaTileVertex { pub tile_x: i16, pub tile_y: i16, - pub color_u: u16, - pub color_v: u16, pub mask_u: u16, pub mask_v: u16, + pub color_u: u16, + pub color_v: u16, pub backdrop: i16, pub object_index: u16, }