/ src / gl / mod.rs
mod.rs
   1  use crate::cmd::Axis;
   2  use crate::draw;
   3  use crate::execution::Execution;
   4  use crate::font::TextBatch;
   5  use crate::platform::{self, LogicalSize};
   6  use crate::renderer;
   7  use crate::session::{self, Blending, Effect, Session};
   8  use crate::sprite;
   9  use crate::util;
  10  use crate::view::resource::ViewResource;
  11  use crate::view::{View, ViewId, ViewOp, ViewState};
  12  use crate::{data, data::Assets, image};
  13  
  14  use crate::gfx::{shape2d, sprite2d, Origin, Rgba, Rgba8, ZDepth};
  15  use crate::gfx::{Matrix4, Rect, Repeat, Vector2};
  16  
  17  use luminance::context::GraphicsContext;
  18  use luminance::depth_test::DepthComparison;
  19  use luminance::framebuffer::Framebuffer;
  20  use luminance::pipeline::{PipelineState, TextureBinding};
  21  use luminance::pixel;
  22  use luminance::render_state::RenderState;
  23  use luminance::shader::{Program, Uniform};
  24  use luminance::tess::{Mode, Tess, TessBuilder};
  25  use luminance::texture::{Dim2, GenMipmaps, MagFilter, MinFilter, Sampler, Texture, Wrap};
  26  use luminance::{
  27      blending::{self, Equation, Factor},
  28      pipeline::PipelineError,
  29  };
  30  
  31  use luminance_derive::{Semantics, UniformInterface, Vertex};
  32  use luminance_gl::gl33;
  33  
  34  use std::collections::BTreeMap;
  35  use std::error::Error;
  36  use std::fmt;
  37  use std::io;
  38  use std::mem;
  39  use std::time;
  40  
  41  type Backend = gl33::GL33;
  42  type M44 = [[f32; 4]; 4];
  43  
  44  const SAMPLER: Sampler = Sampler {
  45      wrap_r: Wrap::Repeat,
  46      wrap_s: Wrap::Repeat,
  47      wrap_t: Wrap::Repeat,
  48      min_filter: MinFilter::Nearest,
  49      mag_filter: MagFilter::Nearest,
  50      depth_comparison: None,
  51  };
  52  
  53  #[derive(UniformInterface)]
  54  struct Sprite2dInterface {
  55      tex: Uniform<TextureBinding<Dim2, pixel::NormUnsigned>>,
  56      ortho: Uniform<M44>,
  57      transform: Uniform<M44>,
  58  }
  59  
  60  #[derive(Copy, Clone, Debug, Semantics)]
  61  pub enum VertexSemantics {
  62      #[sem(name = "position", repr = "[f32; 3]", wrapper = "VertexPosition")]
  63      Position,
  64      #[sem(name = "uv", repr = "[f32; 2]", wrapper = "VertexUv")]
  65      Uv,
  66      #[sem(name = "color", repr = "[u8; 4]", wrapper = "VertexColor")]
  67      Color,
  68      #[sem(name = "opacity", repr = "[f32; 1]", wrapper = "VertexOpacity")]
  69      Opacity,
  70      #[sem(name = "angle", repr = "[f32; 1]", wrapper = "VertexAngle")]
  71      Angle,
  72      #[sem(name = "center", repr = "[f32; 2]", wrapper = "VertexCenter")]
  73      Center,
  74  }
  75  
  76  #[repr(C)]
  77  #[derive(Copy, Clone, Vertex)]
  78  #[vertex(sem = "VertexSemantics")]
  79  #[rustfmt::skip]
  80  struct Sprite2dVertex {
  81      #[allow(dead_code)] position: VertexPosition,
  82      #[allow(dead_code)] uv: VertexUv,
  83      #[vertex(normalized = "true")]
  84      #[allow(dead_code)] color: VertexColor,
  85      #[allow(dead_code)] opacity: VertexOpacity,
  86  }
  87  
  88  ////////////////////////////////////////////////////////////
  89  
  90  #[derive(UniformInterface)]
  91  struct Shape2dInterface {
  92      ortho: Uniform<M44>,
  93      transform: Uniform<M44>,
  94  }
  95  
  96  #[repr(C)]
  97  #[derive(Copy, Clone, Vertex)]
  98  #[vertex(sem = "VertexSemantics")]
  99  #[rustfmt::skip]
 100  struct Shape2dVertex {
 101      #[allow(dead_code)] position: VertexPosition,
 102      #[allow(dead_code)] angle: VertexAngle,
 103      #[allow(dead_code)] center: VertexCenter,
 104      #[vertex(normalized = "true")]
 105      #[allow(dead_code)] color: VertexColor,
 106  }
 107  
 108  #[derive(UniformInterface)]
 109  struct Cursor2dInterface {
 110      cursor: Uniform<TextureBinding<Dim2, pixel::NormUnsigned>>,
 111      framebuffer: Uniform<TextureBinding<Dim2, pixel::NormUnsigned>>,
 112      ortho: Uniform<M44>,
 113      scale: Uniform<f32>,
 114  }
 115  
 116  #[repr(C)]
 117  #[derive(Copy, Clone, Vertex)]
 118  #[vertex(sem = "VertexSemantics")]
 119  #[rustfmt::skip]
 120  struct Cursor2dVertex {
 121      #[allow(dead_code)] position: VertexPosition,
 122      #[allow(dead_code)] uv: VertexUv,
 123  }
 124  
 125  #[derive(UniformInterface)]
 126  struct Screen2dInterface {
 127      framebuffer: Uniform<TextureBinding<Dim2, pixel::NormUnsigned>>,
 128  }
 129  
 130  pub struct Renderer {
 131      pub win_size: LogicalSize,
 132  
 133      ctx: Context,
 134      draw_ctx: draw::Context,
 135      scale_factor: f64,
 136      scale: f64,
 137      present_fb: Framebuffer<Backend, Dim2, (), ()>,
 138      screen_fb: Framebuffer<Backend, Dim2, pixel::SRGBA8UI, pixel::Depth32F>,
 139      render_st: RenderState,
 140      pipeline_st: PipelineState,
 141      blending: Blending,
 142  
 143      staging_batch: shape2d::Batch,
 144      final_batch: shape2d::Batch,
 145  
 146      font: Texture<Backend, Dim2, pixel::SRGBA8UI>,
 147      cursors: Texture<Backend, Dim2, pixel::SRGBA8UI>,
 148      checker: Texture<Backend, Dim2, pixel::SRGBA8UI>,
 149      paste: Texture<Backend, Dim2, pixel::SRGBA8UI>,
 150      paste_outputs: Vec<Tess<Backend, Sprite2dVertex>>,
 151  
 152      sprite2d: Program<Backend, VertexSemantics, (), Sprite2dInterface>,
 153      shape2d: Program<Backend, VertexSemantics, (), Shape2dInterface>,
 154      cursor2d: Program<Backend, VertexSemantics, (), Cursor2dInterface>,
 155      screen2d: Program<Backend, VertexSemantics, (), Screen2dInterface>,
 156  
 157      view_data: BTreeMap<ViewId, ViewData>,
 158  }
 159  
 160  struct LayerData {
 161      fb: Framebuffer<Backend, Dim2, pixel::SRGBA8UI, pixel::Depth32F>,
 162      tess: Tess<Backend, Sprite2dVertex>,
 163  }
 164  
 165  impl LayerData {
 166      fn new(w: u32, h: u32, pixels: Option<&[Rgba8]>, ctx: &mut Context) -> Self {
 167          let batch = sprite2d::Batch::singleton(
 168              w,
 169              h,
 170              Rect::origin(w as f32, h as f32),
 171              Rect::origin(w as f32, h as f32),
 172              ZDepth::default(),
 173              Rgba::TRANSPARENT,
 174              1.,
 175              Repeat::default(),
 176          );
 177  
 178          let verts: Vec<Sprite2dVertex> = batch
 179              .vertices()
 180              .iter()
 181              .map(|v| unsafe { mem::transmute(*v) })
 182              .collect();
 183          let tess = TessBuilder::new(ctx)
 184              .set_vertices(verts)
 185              .set_mode(Mode::Triangle)
 186              .build()
 187              .unwrap();
 188  
 189          let mut fb: Framebuffer<Backend, Dim2, pixel::SRGBA8UI, pixel::Depth32F> =
 190              Framebuffer::new(ctx, [w, h], 0, self::SAMPLER).unwrap();
 191  
 192          fb.color_slot().clear(GenMipmaps::No, (0, 0, 0, 0)).unwrap();
 193  
 194          if let Some(pixels) = pixels {
 195              let aligned = util::align_u8(pixels);
 196              fb.color_slot().upload_raw(GenMipmaps::No, aligned).unwrap();
 197          }
 198  
 199          Self { fb, tess }
 200      }
 201  
 202      fn clear(&mut self) -> Result<(), RendererError> {
 203          self.fb
 204              .color_slot()
 205              .clear(GenMipmaps::No, (0, 0, 0, 0))
 206              .map_err(RendererError::Texture)
 207      }
 208  
 209      fn upload_part(
 210          &mut self,
 211          offset: [u32; 2],
 212          size: [u32; 2],
 213          texels: &[u8],
 214      ) -> Result<(), RendererError> {
 215          self.fb
 216              .color_slot()
 217              .upload_part_raw(GenMipmaps::No, offset, size, texels)
 218              .map_err(RendererError::Texture)
 219      }
 220  
 221      fn upload(&mut self, texels: &[u8]) -> Result<(), RendererError> {
 222          self.fb
 223              .color_slot()
 224              .upload_raw(GenMipmaps::No, texels)
 225              .map_err(RendererError::Texture)
 226      }
 227  
 228      fn pixels(&mut self) -> Vec<Rgba8> {
 229          let texels = self
 230              .fb
 231              .color_slot()
 232              .get_raw_texels()
 233              .expect("getting raw texels never fails");
 234          Rgba8::align(&texels).to_vec()
 235      }
 236  }
 237  
 238  struct ViewData {
 239      layer: LayerData,
 240      staging_fb: Framebuffer<Backend, Dim2, pixel::SRGBA8UI, pixel::Depth32F>,
 241      anim_tess: Option<Tess<Backend, Sprite2dVertex>>,
 242      layer_tess: Option<Tess<Backend, Sprite2dVertex>>,
 243  }
 244  
 245  impl ViewData {
 246      fn new(w: u32, h: u32, pixels: Option<&[Rgba8]>, ctx: &mut Context) -> Self {
 247          let mut staging_fb: Framebuffer<Backend, Dim2, pixel::SRGBA8UI, pixel::Depth32F> =
 248              Framebuffer::new(ctx, [w, h], 0, self::SAMPLER).unwrap();
 249  
 250          staging_fb
 251              .color_slot()
 252              .clear(GenMipmaps::No, (0, 0, 0, 0))
 253              .unwrap();
 254  
 255          Self {
 256              layer: LayerData::new(w, h, pixels, ctx),
 257              staging_fb,
 258              anim_tess: None,
 259              layer_tess: None,
 260          }
 261      }
 262  }
 263  
 264  struct Context {
 265      ctx: Backend,
 266  }
 267  
 268  unsafe impl GraphicsContext for Context {
 269      type Backend = self::Backend;
 270  
 271      fn backend(&mut self) -> &mut Self::Backend {
 272          &mut self.ctx
 273      }
 274  }
 275  
 276  impl Context {
 277      fn program<T>(&mut self, vert: &str, frag: &str) -> Program<Backend, VertexSemantics, (), T>
 278      where
 279          T: luminance::shader::UniformInterface<Backend>,
 280      {
 281          self.new_shader_program()
 282              .from_strings(vert, None, None, frag)
 283              .unwrap()
 284              .ignore_warnings()
 285      }
 286  
 287      fn tessellation<T, S>(&mut self, verts: &[T]) -> Tess<Backend, S>
 288      where
 289          S: luminance::vertex::Vertex + Sized,
 290      {
 291          let (head, body, tail) = unsafe { verts.align_to::<S>() };
 292  
 293          assert!(head.is_empty());
 294          assert!(tail.is_empty());
 295  
 296          TessBuilder::new(self)
 297              .set_vertices(body)
 298              .set_mode(Mode::Triangle)
 299              .build()
 300              .unwrap()
 301      }
 302  }
 303  
 304  #[derive(Debug)]
 305  pub enum RendererError {
 306      Initialization,
 307      Texture(luminance::texture::TextureError),
 308      Framebuffer(luminance::framebuffer::FramebufferError),
 309      Pipeline(luminance::pipeline::PipelineError),
 310      State(luminance_gl::gl33::StateQueryError),
 311  }
 312  
 313  impl From<luminance::pipeline::PipelineError> for RendererError {
 314      fn from(other: luminance::pipeline::PipelineError) -> Self {
 315          Self::Pipeline(other)
 316      }
 317  }
 318  
 319  impl From<RendererError> for io::Error {
 320      fn from(err: RendererError) -> io::Error {
 321          io::Error::new(io::ErrorKind::Other, err)
 322      }
 323  }
 324  
 325  impl fmt::Display for RendererError {
 326      fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
 327          match self {
 328              Self::Initialization => write!(f, "initialization error"),
 329              Self::Texture(e) => write!(f, "texture error: {}", e),
 330              Self::Framebuffer(e) => write!(f, "framebuffer error: {}", e),
 331              Self::Pipeline(e) => write!(f, "pipeline error: {}", e),
 332              Self::State(e) => write!(f, "state error: {}", e),
 333          }
 334      }
 335  }
 336  
 337  impl Error for RendererError {
 338      fn description(&self) -> &str {
 339          "Renderer error"
 340      }
 341  
 342      fn cause(&self) -> Option<&dyn Error> {
 343          None
 344      }
 345  }
 346  
 347  impl<'a> renderer::Renderer<'a> for Renderer {
 348      type Error = RendererError;
 349  
 350      fn new(
 351          win: &mut platform::backend::Window,
 352          win_size: LogicalSize,
 353          scale_factor: f64,
 354          assets: Assets<'a>,
 355      ) -> io::Result<Self> {
 356          use RendererError as Error;
 357  
 358          gl::load_with(|s| win.get_proc_address(s) as *const _);
 359  
 360          let ctx = Backend::new().map_err(Error::State)?;
 361          let mut ctx = Context { ctx };
 362  
 363          let (font_img, font_w, font_h) = image::read(assets.glyphs)?;
 364          let (cursors_img, cursors_w, cursors_h) = image::read(data::CURSORS)?;
 365          let (checker_w, checker_h) = (2, 2);
 366          let (paste_w, paste_h) = (8, 8);
 367  
 368          let mut font =
 369              Texture::new(&mut ctx, [font_w, font_h], 0, self::SAMPLER).map_err(Error::Texture)?;
 370          let mut cursors = Texture::new(&mut ctx, [cursors_w, cursors_h], 0, self::SAMPLER)
 371              .map_err(Error::Texture)?;
 372          let paste =
 373              Texture::new(&mut ctx, [paste_w, paste_h], 0, self::SAMPLER).map_err(Error::Texture)?;
 374          let mut checker = Texture::new(&mut ctx, [checker_w, checker_h], 0, self::SAMPLER)
 375              .map_err(Error::Texture)?;
 376  
 377          font.upload_raw(GenMipmaps::No, &font_img)
 378              .map_err(Error::Texture)?;
 379          cursors
 380              .upload_raw(GenMipmaps::No, &cursors_img)
 381              .map_err(Error::Texture)?;
 382          checker
 383              .upload_raw(GenMipmaps::No, &draw::CHECKER)
 384              .map_err(Error::Texture)?;
 385  
 386          let sprite2d = ctx.program::<Sprite2dInterface>(
 387              include_str!("data/sprite.vert"),
 388              include_str!("data/sprite.frag"),
 389          );
 390          let shape2d = ctx.program::<Shape2dInterface>(
 391              include_str!("data/shape.vert"),
 392              include_str!("data/shape.frag"),
 393          );
 394          let cursor2d = ctx.program::<Cursor2dInterface>(
 395              include_str!("data/cursor.vert"),
 396              include_str!("data/cursor.frag"),
 397          );
 398          let screen2d = ctx.program::<Screen2dInterface>(
 399              include_str!("data/screen.vert"),
 400              include_str!("data/screen.frag"),
 401          );
 402  
 403          let physical = win_size.to_physical(scale_factor);
 404          let present_fb =
 405              Framebuffer::back_buffer(&mut ctx, [physical.width as u32, physical.height as u32])
 406                  .map_err(Error::Framebuffer)?;
 407          let screen_fb = Framebuffer::new(
 408              &mut ctx,
 409              [win_size.width as u32, win_size.height as u32],
 410              0,
 411              self::SAMPLER,
 412          )
 413          .map_err(Error::Framebuffer)?;
 414  
 415          let render_st = RenderState::default()
 416              .set_blending(blending::Blending {
 417                  equation: Equation::Additive,
 418                  src: Factor::SrcAlpha,
 419                  dst: Factor::SrcAlphaComplement,
 420              })
 421              .set_depth_test(Some(DepthComparison::LessOrEqual));
 422          let pipeline_st = PipelineState::default()
 423              .set_clear_color([0., 0., 0., 0.])
 424              .enable_srgb(true)
 425              .enable_clear_depth(true)
 426              .enable_clear_color(true);
 427  
 428          let draw_ctx = draw::Context {
 429              ui_batch: shape2d::Batch::new(),
 430              text_batch: self::text_batch(font.size()),
 431              overlay_batch: self::text_batch(font.size()),
 432              cursor_sprite: sprite::Sprite::new(cursors_w, cursors_h),
 433              tool_batch: sprite2d::Batch::new(cursors_w, cursors_h),
 434              paste_batch: sprite2d::Batch::new(paste_w, paste_h),
 435              checker_batch: sprite2d::Batch::new(checker_w, checker_h),
 436          };
 437  
 438          Ok(Renderer {
 439              ctx,
 440              draw_ctx,
 441              win_size,
 442              scale_factor,
 443              scale: 1.0,
 444              blending: Blending::Alpha,
 445              present_fb,
 446              screen_fb,
 447              render_st,
 448              pipeline_st,
 449              sprite2d,
 450              shape2d,
 451              cursor2d,
 452              screen2d,
 453              font,
 454              cursors,
 455              checker,
 456              paste,
 457              paste_outputs: Vec::new(),
 458              staging_batch: shape2d::Batch::new(),
 459              final_batch: shape2d::Batch::new(),
 460              view_data: BTreeMap::new(),
 461          })
 462      }
 463  
 464      fn init(&mut self, effects: Vec<Effect>, session: &Session) {
 465          self.handle_effects(effects, session).unwrap();
 466      }
 467  
 468      fn frame(
 469          &mut self,
 470          session: &mut Session,
 471          execution: &mut Execution,
 472          effects: Vec<session::Effect>,
 473          avg_frametime: &time::Duration,
 474      ) -> Result<(), RendererError> {
 475          if session.state != session::State::Running {
 476              return Ok(());
 477          }
 478          self.staging_batch.clear();
 479          self.final_batch.clear();
 480  
 481          self.handle_effects(effects, session).unwrap();
 482          self.update_view_animations(session);
 483          self.update_view_composites(session);
 484  
 485          let [screen_w, screen_h] = self.screen_fb.size();
 486          let ortho: M44 = Matrix4::ortho(screen_w, screen_h, Origin::TopLeft).into();
 487          let identity: M44 = Matrix4::identity().into();
 488  
 489          let Self {
 490              draw_ctx,
 491              font,
 492              cursors,
 493              checker,
 494              sprite2d,
 495              shape2d,
 496              cursor2d,
 497              screen2d,
 498              scale_factor,
 499              present_fb,
 500              blending,
 501              screen_fb,
 502              render_st,
 503              pipeline_st,
 504              paste,
 505              paste_outputs,
 506              view_data,
 507              ..
 508          } = self;
 509  
 510          draw_ctx.clear();
 511          draw_ctx.draw(session, avg_frametime, execution);
 512  
 513          let text_tess = self
 514              .ctx
 515              .tessellation::<_, Sprite2dVertex>(&draw_ctx.text_batch.vertices());
 516          let overlay_tess = self
 517              .ctx
 518              .tessellation::<_, Sprite2dVertex>(&draw_ctx.overlay_batch.vertices());
 519          let ui_tess = self
 520              .ctx
 521              .tessellation::<_, Shape2dVertex>(&draw_ctx.ui_batch.vertices());
 522          let tool_tess = self
 523              .ctx
 524              .tessellation::<_, Sprite2dVertex>(&draw_ctx.tool_batch.vertices());
 525          let cursor_tess = self
 526              .ctx
 527              .tessellation::<_, Cursor2dVertex>(&draw_ctx.cursor_sprite.vertices());
 528          let checker_tess = self
 529              .ctx
 530              .tessellation::<_, Sprite2dVertex>(&draw_ctx.checker_batch.vertices());
 531          let screen_tess = TessBuilder::<Backend, ()>::new(&mut self.ctx)
 532              .set_vertex_nb(6)
 533              .set_mode(Mode::Triangle)
 534              .build()
 535              .unwrap();
 536  
 537          let paste_tess = if draw_ctx.paste_batch.is_empty() {
 538              None
 539          } else {
 540              Some(
 541                  self.ctx
 542                      .tessellation::<_, Sprite2dVertex>(&draw_ctx.paste_batch.vertices()),
 543              )
 544          };
 545          let staging_tess = if self.staging_batch.is_empty() {
 546              None
 547          } else {
 548              Some(
 549                  self.ctx
 550                      .tessellation::<_, Shape2dVertex>(&self.staging_batch.vertices()),
 551              )
 552          };
 553          let final_tess = if self.final_batch.is_empty() {
 554              None
 555          } else {
 556              Some(
 557                  self.ctx
 558                      .tessellation::<_, Shape2dVertex>(&self.final_batch.vertices()),
 559              )
 560          };
 561  
 562          let help_tess = if session.mode == session::Mode::Help {
 563              let mut win = shape2d::Batch::new();
 564              let mut text = self::text_batch(font.size());
 565              draw::draw_help(session, &mut text, &mut win);
 566  
 567              let win_tess = self
 568                  .ctx
 569                  .tessellation::<_, Shape2dVertex>(win.vertices().as_slice());
 570              let text_tess = self
 571                  .ctx
 572                  .tessellation::<_, Sprite2dVertex>(text.vertices().as_slice());
 573              Some((win_tess, text_tess))
 574          } else {
 575              None
 576          };
 577  
 578          let v = session
 579              .views
 580              .active()
 581              .expect("there must always be an active view");
 582          let v_data = view_data.get(&v.id).unwrap();
 583          let l_data = &v_data.layer;
 584          let view_ortho = Matrix4::ortho(v.width(), v.fh, Origin::TopLeft);
 585  
 586          let mut builder = self.ctx.new_pipeline_gate();
 587  
 588          // Render to view staging buffer.
 589          builder.pipeline::<PipelineError, _, _, _, _>(
 590              &v_data.staging_fb,
 591              pipeline_st,
 592              |pipeline, mut shd_gate| {
 593                  // Render staged brush strokes.
 594                  if let Some(tess) = staging_tess {
 595                      shd_gate.shade(shape2d, |mut iface, uni, mut rdr_gate| {
 596                          iface.set(&uni.ortho, view_ortho.into());
 597                          iface.set(&uni.transform, identity);
 598  
 599                          rdr_gate.render(render_st, |mut tess_gate| tess_gate.render(&tess))
 600                      })?;
 601                  }
 602                  // Render staging paste buffer.
 603                  if let Some(tess) = paste_tess {
 604                      let bound_paste = pipeline
 605                          .bind_texture(paste)
 606                          .expect("binding textures never fails. qed.");
 607                      shd_gate.shade(sprite2d, |mut iface, uni, mut rdr_gate| {
 608                          iface.set(&uni.ortho, view_ortho.into());
 609                          iface.set(&uni.transform, identity);
 610                          iface.set(&uni.tex, bound_paste.binding());
 611  
 612                          rdr_gate.render(render_st, |mut tess_gate| tess_gate.render(&tess))
 613                      })?;
 614                  }
 615                  Ok(())
 616              },
 617          );
 618  
 619          // Render to view final buffer.
 620          builder.pipeline::<PipelineError, _, _, _, _>(
 621              &l_data.fb,
 622              &pipeline_st.clone().enable_clear_color(false),
 623              |pipeline, mut shd_gate| {
 624                  let bound_paste = pipeline
 625                      .bind_texture(paste)
 626                      .expect("binding textures never fails. qed.");
 627  
 628                  // Render final brush strokes.
 629                  if let Some(tess) = final_tess {
 630                      shd_gate.shade(shape2d, |mut iface, uni, mut rdr_gate| {
 631                          iface.set(&uni.ortho, view_ortho.into());
 632                          iface.set(&uni.transform, identity);
 633  
 634                          let render_st = if blending == &Blending::Constant {
 635                              render_st.clone().set_blending(blending::Blending {
 636                                  equation: Equation::Additive,
 637                                  src: Factor::One,
 638                                  dst: Factor::Zero,
 639                              })
 640                          } else {
 641                              render_st.clone()
 642                          };
 643  
 644                          rdr_gate.render(&render_st, |mut tess_gate| tess_gate.render(&tess))
 645                      })?;
 646                  }
 647                  if !paste_outputs.is_empty() {
 648                      shd_gate.shade(sprite2d, |mut iface, uni, mut rdr_gate| {
 649                          iface.set(&uni.ortho, view_ortho.into());
 650                          iface.set(&uni.transform, identity);
 651                          iface.set(&uni.tex, bound_paste.binding());
 652  
 653                          for out in paste_outputs.drain(..) {
 654                              rdr_gate.render(render_st, |mut tess_gate| tess_gate.render(&out))?;
 655                          }
 656                          Ok(())
 657                      })?;
 658                  }
 659                  Ok(())
 660              },
 661          );
 662  
 663          // Render to screen framebuffer.
 664          let bg = Rgba::from(session.settings["background"].to_rgba8());
 665          let screen_st = &pipeline_st
 666              .clone()
 667              .set_clear_color([bg.r, bg.g, bg.b, bg.a]);
 668          builder.pipeline::<PipelineError, _, _, _, _>(
 669              screen_fb,
 670              screen_st,
 671              |pipeline, mut shd_gate| {
 672                  // Draw view checkers to screen framebuffer.
 673                  if session.settings["checker"].is_set() {
 674                      shd_gate.shade(sprite2d, |mut iface, uni, mut rdr_gate| {
 675                          let bound_checker = pipeline
 676                              .bind_texture(checker)
 677                              .expect("binding textures never fails");
 678  
 679                          iface.set(&uni.ortho, ortho);
 680                          iface.set(&uni.transform, identity);
 681                          iface.set(&uni.tex, bound_checker.binding());
 682  
 683                          rdr_gate.render(render_st, |mut tess_gate| tess_gate.render(&checker_tess))
 684                      })?;
 685                  }
 686  
 687                  for (id, v) in view_data.iter_mut() {
 688                      if let Some(view) = session.views.get(*id) {
 689                          let transform =
 690                              Matrix4::from_translation(
 691                                  (session.offset + view.offset).extend(*draw::VIEW_LAYER),
 692                              ) * Matrix4::from_nonuniform_scale(view.zoom, view.zoom, 1.0);
 693  
 694                          // Render views.
 695                          shd_gate.shade(sprite2d, |mut iface, uni, mut rdr_gate| {
 696                              let bound_view = pipeline
 697                                  .bind_texture(v.layer.fb.color_slot())
 698                                  .expect("binding textures never fails");
 699  
 700                              iface.set(&uni.ortho, ortho);
 701                              iface.set(&uni.transform, transform.into());
 702                              iface.set(&uni.tex, bound_view.binding());
 703  
 704                              rdr_gate.render(render_st, |mut tess_gate| {
 705                                  tess_gate.render(&v.layer.tess)
 706                              })?;
 707  
 708                              // TODO: We only need to render this on the active view.
 709                              let staging_texture = v.staging_fb.color_slot();
 710                              let bound_view_staging = pipeline
 711                                  .bind_texture(staging_texture)
 712                                  .expect("binding textures never fails");
 713  
 714                              iface.set(&uni.tex, bound_view_staging.binding());
 715                              rdr_gate.render(render_st, |mut tess_gate| {
 716                                  tess_gate.render(&v.layer.tess)
 717                              })?;
 718  
 719                              Ok(())
 720                          })?;
 721                      }
 722                  }
 723  
 724                  // Render UI.
 725                  shd_gate.shade(shape2d, |mut iface, uni, mut rdr_gate| {
 726                      iface.set(&uni.ortho, ortho);
 727                      iface.set(&uni.transform, identity);
 728  
 729                      rdr_gate.render(render_st, |mut tess_gate| tess_gate.render(&ui_tess))
 730                  })?;
 731  
 732                  // Render text, tool & view animations.
 733                  shd_gate.shade(sprite2d, |mut iface, uni, mut rdr_gate| {
 734                      iface.set(&uni.ortho, ortho);
 735                      iface.set(&uni.transform, identity);
 736  
 737                      // Render view animations.
 738                      if session.settings["animation"].is_set() {
 739                          for (id, v) in view_data.iter_mut() {
 740                              match (&v.anim_tess, session.views.get(*id)) {
 741                                  (Some(tess), Some(view)) if view.animation.len() > 1 => {
 742                                      let bound_layer = pipeline
 743                                          .bind_texture(v.layer.fb.color_slot())
 744                                          .expect("binding textures never fails");
 745                                      let t = Matrix4::from_translation(
 746                                          Vector2::new(0., view.zoom).extend(0.),
 747                                      );
 748  
 749                                      // Render layer animation.
 750                                      iface.set(&uni.tex, bound_layer.binding());
 751                                      iface.set(&uni.transform, t.into());
 752                                      rdr_gate.render(render_st, |mut tess_gate| {
 753                                          tess_gate.render(tess)
 754                                      })?;
 755                                  }
 756                                  _ => (),
 757                              }
 758                          }
 759                      }
 760  
 761                      {
 762                          let bound_font = pipeline
 763                              .bind_texture(font)
 764                              .expect("binding textures never fails");
 765                          iface.set(&uni.tex, bound_font.binding());
 766                          iface.set(&uni.transform, identity);
 767  
 768                          // Render text.
 769                          rdr_gate.render(render_st, |mut tess_gate| tess_gate.render(&text_tess))?;
 770                      }
 771                      {
 772                          let bound_tool = pipeline
 773                              .bind_texture(cursors)
 774                              .expect("binding textures never fails");
 775                          iface.set(&uni.tex, bound_tool.binding());
 776  
 777                          // Render tool.
 778                          rdr_gate.render(render_st, |mut tess_gate| tess_gate.render(&tool_tess))?;
 779                      }
 780                      Ok(())
 781                  })?;
 782  
 783                  // Render help.
 784                  if let Some((win_tess, text_tess)) = help_tess {
 785                      shd_gate.shade(shape2d, |_iface, _uni, mut rdr_gate| {
 786                          rdr_gate.render(render_st, |mut tess_gate| tess_gate.render(&win_tess))
 787                      })?;
 788                      shd_gate.shade(sprite2d, |mut iface, uni, mut rdr_gate| {
 789                          let bound_font = pipeline
 790                              .bind_texture(font)
 791                              .expect("binding textures never fails");
 792  
 793                          iface.set(&uni.tex, bound_font.binding());
 794                          iface.set(&uni.ortho, ortho);
 795                          iface.set(&uni.transform, identity);
 796  
 797                          rdr_gate.render(render_st, |mut tess_gate| tess_gate.render(&text_tess))
 798                      })?;
 799                  }
 800                  Ok(())
 801              },
 802          );
 803  
 804          // Render to back buffer.
 805          builder.pipeline::<PipelineError, _, _, _, _>(
 806              present_fb,
 807              pipeline_st,
 808              |pipeline, mut shd_gate| {
 809                  // Render screen framebuffer.
 810                  let bound_screen = pipeline
 811                      .bind_texture(screen_fb.color_slot())
 812                      .expect("binding textures never fails");
 813                  shd_gate.shade(screen2d, |mut iface, uni, mut rdr_gate| {
 814                      iface.set(&uni.framebuffer, bound_screen.binding());
 815  
 816                      rdr_gate.render(render_st, |mut tess_gate| tess_gate.render(&screen_tess))
 817                  })?;
 818  
 819                  if session.settings["debug"].is_set() || !execution.is_normal() {
 820                      let bound_font = pipeline
 821                          .bind_texture(font)
 822                          .expect("binding textures never fails");
 823  
 824                      shd_gate.shade(sprite2d, |mut iface, uni, mut rdr_gate| {
 825                          iface.set(&uni.tex, bound_font.binding());
 826                          iface.set(
 827                              &uni.ortho,
 828                              Matrix4::ortho(screen_w, screen_h, Origin::BottomLeft).into(),
 829                          );
 830  
 831                          rdr_gate.render(render_st, |mut tess_gate| tess_gate.render(&overlay_tess))
 832                      })?;
 833                  }
 834  
 835                  // Render cursor.
 836                  let bound_cursors = pipeline
 837                      .bind_texture(cursors)
 838                      .expect("binding textures never fails");
 839                  shd_gate.shade(cursor2d, |mut iface, uni, mut rdr_gate| {
 840                      let ui_scale = session.settings["scale"].to_f64();
 841                      let pixel_ratio = platform::pixel_ratio(*scale_factor);
 842  
 843                      iface.set(&uni.cursor, bound_cursors.binding());
 844                      iface.set(&uni.framebuffer, bound_screen.binding());
 845                      iface.set(&uni.ortho, ortho);
 846                      iface.set(&uni.scale, (ui_scale * pixel_ratio) as f32);
 847  
 848                      rdr_gate.render(render_st, |mut tess_gate| tess_gate.render(&cursor_tess))
 849                  })
 850              },
 851          );
 852  
 853          // If active view is dirty, record a snapshot of it.
 854          if v.is_dirty() {
 855              // FIXME: This is ugly.
 856              let id = v.id;
 857              let state = v.state;
 858              let is_resized = v.is_resized();
 859              let extent = v.extent();
 860  
 861              if let Some(vr) = session.views.get_mut(id) {
 862                  let v_data = view_data.get_mut(&id).unwrap();
 863  
 864                  match state {
 865                      ViewState::Dirty(_) if is_resized => {
 866                          vr.record_view_resized(v_data.layer.pixels(), extent);
 867                      }
 868                      ViewState::Dirty(_) => {
 869                          vr.record_view_painted(v_data.layer.pixels());
 870                      }
 871                      ViewState::Okay | ViewState::Damaged(_) => {}
 872                  }
 873              }
 874          }
 875  
 876          if !execution.is_normal() {
 877              let texels = screen_fb
 878                  .color_slot()
 879                  .get_raw_texels()
 880                  .expect("binding textures never fails");
 881              let texels = Rgba8::align(&texels);
 882  
 883              execution.record(texels).ok();
 884          }
 885  
 886          Ok(())
 887      }
 888  
 889      fn handle_scale_factor_changed(&mut self, scale_factor: f64) {
 890          self.scale_factor = scale_factor;
 891          self.handle_resized(self.win_size);
 892      }
 893  }
 894  
 895  impl Renderer {
 896      pub fn handle_resized(&mut self, size: platform::LogicalSize) {
 897          let physical = size.to_physical(self.scale_factor);
 898  
 899          self.present_fb = Framebuffer::back_buffer(
 900              &mut self.ctx,
 901              [physical.width as u32, physical.height as u32],
 902          )
 903          .expect("binding textures never fails");
 904  
 905          self.win_size = size;
 906          self.handle_session_scale_changed(self.scale);
 907      }
 908  
 909      pub fn handle_session_scale_changed(&mut self, scale: f64) {
 910          self.scale = scale;
 911          self.screen_fb = Framebuffer::new(
 912              &mut self.ctx,
 913              [
 914                  (self.win_size.width / scale) as u32,
 915                  (self.win_size.height / scale) as u32,
 916              ],
 917              0,
 918              self::SAMPLER,
 919          )
 920          .unwrap();
 921      }
 922  
 923      fn handle_effects(
 924          &mut self,
 925          mut effects: Vec<Effect>,
 926          session: &Session,
 927      ) -> Result<(), RendererError> {
 928          for eff in effects.drain(..) {
 929              match eff {
 930                  Effect::SessionResized(size) => {
 931                      self.handle_resized(size);
 932                  }
 933                  Effect::SessionScaled(scale) => {
 934                      self.handle_session_scale_changed(scale);
 935                  }
 936                  Effect::ViewActivated(_) => {}
 937                  Effect::ViewAdded(id) => {
 938                      // FIXME: This should be done when the view is added in the ViewManager.
 939                      if let Some((s, pixels)) = session.views.get_snapshot_safe(id) {
 940                          let (w, h) = (s.width(), s.height());
 941  
 942                          self.view_data
 943                              .insert(id, ViewData::new(w, h, Some(pixels), &mut self.ctx));
 944                      }
 945                  }
 946                  Effect::ViewRemoved(id) => {
 947                      self.view_data.remove(&id);
 948                  }
 949                  Effect::ViewOps(id, ops) => {
 950                      self.handle_view_ops(session.view(id), &ops)?;
 951                  }
 952                  Effect::ViewDamaged(id, Some(extent)) => {
 953                      self.handle_view_resized(session.view(id), extent.width(), extent.height())?;
 954                  }
 955                  Effect::ViewDamaged(id, None) => {
 956                      self.handle_view_damaged(session.view(id))?;
 957                  }
 958                  Effect::ViewBlendingChanged(blending) => {
 959                      self.blending = blending;
 960                  }
 961                  Effect::ViewPaintDraft(shapes) => {
 962                      shapes.into_iter().for_each(|s| self.staging_batch.add(s));
 963                  }
 964                  Effect::ViewPaintFinal(shapes) => {
 965                      shapes.into_iter().for_each(|s| self.final_batch.add(s));
 966                  }
 967                  Effect::ViewTouched(_) => {}
 968              }
 969          }
 970          Ok(())
 971      }
 972  
 973      fn handle_view_ops(
 974          &mut self,
 975          v: &View<ViewResource>,
 976          ops: &[ViewOp],
 977      ) -> Result<(), RendererError> {
 978          use RendererError as Error;
 979  
 980          for op in ops {
 981              match op {
 982                  ViewOp::Resize(w, h) => {
 983                      self.resize_view(v, *w, *h)?;
 984                  }
 985                  ViewOp::Clear(color) => {
 986                      let view = self
 987                          .view_data
 988                          .get_mut(&v.id)
 989                          .expect("views must have associated view data");
 990  
 991                      view.layer
 992                          .fb
 993                          .color_slot()
 994                          .clear(GenMipmaps::No, (color.r, color.g, color.b, color.a))
 995                          .map_err(Error::Texture)?;
 996                  }
 997                  ViewOp::Blit(src, dst) => {
 998                      let view = self
 999                          .view_data
1000                          .get_mut(&v.id)
1001                          .expect("views must have associated view data");
1002  
1003                      let (_, texels) = v.layer.get_snapshot_rect(&src.map(|n| n as i32)).unwrap(); // TODO: Handle this nicely?
1004                      let texels = util::align_u8(&texels);
1005  
1006                      view.layer
1007                          .fb
1008                          .color_slot()
1009                          .upload_part_raw(
1010                              GenMipmaps::No,
1011                              [dst.x1 as u32, dst.y1 as u32],
1012                              [src.width() as u32, src.height() as u32],
1013                              texels,
1014                          )
1015                          .map_err(Error::Texture)?;
1016                  }
1017                  ViewOp::Yank(src) => {
1018                      let (_, pixels) = v.layer.get_snapshot_rect(&src.map(|n| n)).unwrap();
1019                      let (w, h) = (src.width() as u32, src.height() as u32);
1020                      let [paste_w, paste_h] = self.paste.size();
1021  
1022                      if paste_w != w || paste_h != h {
1023                          self.paste = Texture::new(&mut self.ctx, [w, h], 0, self::SAMPLER)
1024                              .map_err(Error::Texture)?;
1025                      }
1026                      let body = util::align_u8(&pixels);
1027  
1028                      self.paste
1029                          .upload_raw(GenMipmaps::No, body)
1030                          .map_err(Error::Texture)?;
1031                  }
1032                  ViewOp::Flip(src, dir) => {
1033                      let (_, mut pixels) = v.layer.get_snapshot_rect(&src.map(|n| n)).unwrap();
1034                      let (w, h) = (src.width() as u32, src.height() as u32);
1035                      let [paste_w, paste_h] = self.paste.size();
1036  
1037                      if paste_w != w || paste_h != h {
1038                          self.paste = Texture::new(&mut self.ctx, [w, h], 0, self::SAMPLER)
1039                              .map_err(Error::Texture)?;
1040                      }
1041  
1042                      match dir {
1043                          Axis::Vertical => {
1044                              let len = pixels.len();
1045  
1046                              let (front, back) = pixels.split_at_mut(len / 2);
1047                              for (front_row, back_row) in front
1048                                  .chunks_exact_mut(w as usize)
1049                                  .zip(back.rchunks_exact_mut(w as usize))
1050                              {
1051                                  front_row.swap_with_slice(back_row);
1052                              }
1053                          }
1054                          Axis::Horizontal => {
1055                              pixels
1056                                  .chunks_exact_mut(w as usize)
1057                                  .for_each(|row| row.reverse());
1058                          }
1059                      }
1060  
1061                      let body = util::align_u8(&pixels);
1062  
1063                      self.paste
1064                          .upload_raw(GenMipmaps::No, body)
1065                          .map_err(Error::Texture)?;
1066                  }
1067                  ViewOp::Paste(dst) => {
1068                      let [paste_w, paste_h] = self.paste.size();
1069                      let batch = sprite2d::Batch::singleton(
1070                          paste_w,
1071                          paste_h,
1072                          Rect::origin(paste_w as f32, paste_h as f32),
1073                          dst.map(|n| n as f32),
1074                          ZDepth::default(),
1075                          Rgba::TRANSPARENT,
1076                          1.,
1077                          Repeat::default(),
1078                      );
1079  
1080                      self.paste_outputs.push(
1081                          self.ctx
1082                              .tessellation::<_, Sprite2dVertex>(batch.vertices().as_slice()),
1083                      );
1084                  }
1085                  ViewOp::SetPixel(rgba, x, y) => {
1086                      let fb = &mut self
1087                          .view_data
1088                          .get_mut(&v.id)
1089                          .expect("views must have associated view data")
1090                          .layer
1091                          .fb;
1092                      let texels = &[*rgba];
1093                      let texels = util::align_u8(texels);
1094                      fb.color_slot()
1095                          .upload_part_raw(GenMipmaps::No, [*x as u32, *y as u32], [1, 1], texels)
1096                          .map_err(Error::Texture)?;
1097                  }
1098              }
1099          }
1100          Ok(())
1101      }
1102  
1103      fn handle_view_damaged(&mut self, view: &View<ViewResource>) -> Result<(), RendererError> {
1104          let layer = &mut self
1105              .view_data
1106              .get_mut(&view.id)
1107              .expect("views must have associated view data")
1108              .layer;
1109  
1110          let (_, pixels) = view.layer.current_snapshot();
1111  
1112          layer.clear()?;
1113          layer.upload(util::align_u8(pixels))?;
1114  
1115          Ok(())
1116      }
1117  
1118      fn handle_view_resized(
1119          &mut self,
1120          view: &View<ViewResource>,
1121          vw: u32,
1122          vh: u32,
1123      ) -> Result<(), RendererError> {
1124          self.resize_view(view, vw, vh)
1125      }
1126  
1127      fn resize_view(
1128          &mut self,
1129          view: &View<ViewResource>,
1130          vw: u32,
1131          vh: u32,
1132      ) -> Result<(), RendererError> {
1133          // View size changed. Re-create view resources.
1134          let (ew, eh) = {
1135              let extent = view.resource.extent;
1136              (extent.width(), extent.height())
1137          };
1138  
1139          // Ensure not to transfer more data than can fit in the view buffer.
1140          let tw = u32::min(ew, vw);
1141          let th = u32::min(eh, vh);
1142  
1143          let mut view_data = ViewData::new(vw, vh, None, &mut self.ctx);
1144          let trect = Rect::origin(tw as i32, th as i32);
1145          // The following sequence of commands will try to copy a rect that isn't contained
1146          // in the snapshot, hence we must skip the uploading in that case:
1147          //
1148          //     :f/add
1149          //     :f/remove
1150          //     :undo
1151          //
1152          if let Some((_, texels)) = view.layer.get_snapshot_rect(&trect) {
1153              let texels = util::align_u8(&texels);
1154              let l = &mut view_data.layer;
1155  
1156              l.upload_part([0, vh - th], [tw, th], texels)?;
1157          }
1158  
1159          self.view_data.insert(view.id, view_data);
1160  
1161          Ok(())
1162      }
1163  
1164      fn update_view_animations(&mut self, s: &Session) {
1165          if !s.settings["animation"].is_set() {
1166              return;
1167          }
1168          // TODO: Does this need to run if the view has only one frame?
1169          for v in s.views.iter() {
1170              // FIXME: When `v.animation.val()` doesn't change, we don't need
1171              // to re-create the buffer.
1172              let batch = draw::draw_view_animation(s, v);
1173  
1174              if let Some(vd) = self.view_data.get_mut(&v.id) {
1175                  vd.anim_tess = Some(
1176                      self.ctx
1177                          .tessellation::<_, Sprite2dVertex>(batch.vertices().as_slice()),
1178                  );
1179              }
1180          }
1181      }
1182  
1183      fn update_view_composites(&mut self, s: &Session) {
1184          for v in s.views.iter() {
1185              let batch = draw::draw_view_composites(s, v);
1186  
1187              if let Some(vd) = self.view_data.get_mut(&v.id) {
1188                  vd.layer_tess = Some(
1189                      self.ctx
1190                          .tessellation::<_, Sprite2dVertex>(batch.vertices().as_slice()),
1191                  );
1192              }
1193          }
1194      }
1195  }
1196  
1197  fn text_batch([w, h]: [u32; 2]) -> TextBatch {
1198      TextBatch::new(w, h, draw::GLYPH_WIDTH, draw::GLYPH_HEIGHT)
1199  }