// Copyright 2017 The Servo Project Developers. See the COPYRIGHT // file at the top-level directory of this distribution and at // http://rust-lang.org/COPYRIGHT. // // 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. //! An intermediate surface on the GPU used during the rasterization process. use compute_shader::buffer::Protection; use compute_shader::device::Device; use compute_shader::image::{ExternalImage, Format, Image}; use error::InitError; use euclid::size::Size2D; use gl::types::{GLint, GLuint}; use gl; const DEFAULT_COVERAGE_BUFFER_SIZE: u32 = 1024; /// An intermediate surface on the GPU used during the rasterization process. /// /// You can reuse this surface from draw operation to draw operation. It only needs to be at least /// as large as every atlas you will draw into it. /// /// The GPU memory usage of this buffer is `4 * width * height` bytes. pub struct CoverageBuffer { image: Image, framebuffer: GLuint, } impl CoverageBuffer { /// Creates a new coverage buffer with the given options. pub fn new(device: &Device, options: &CoverageBufferOptions) -> Result { let mut size = options.size; if options.subpixel_antialiasing { size.width *= 3 } let image = try!(device.create_image(Format::R32F, Protection::ReadWrite, &size) .map_err(InitError::ComputeError)); let mut framebuffer = 0; unsafe { let mut gl_texture = 0; gl::GenTextures(1, &mut gl_texture); try!(image.bind_to(&ExternalImage::GlTexture(gl_texture)) .map_err(InitError::ComputeError)); gl::BindTexture(gl::TEXTURE_RECTANGLE, gl_texture); gl::TexParameteri(gl::TEXTURE_RECTANGLE, gl::TEXTURE_MIN_FILTER, gl::LINEAR as GLint); gl::TexParameteri(gl::TEXTURE_RECTANGLE, gl::TEXTURE_MAG_FILTER, gl::LINEAR as GLint); gl::TexParameteri(gl::TEXTURE_RECTANGLE, gl::TEXTURE_WRAP_S, gl::CLAMP_TO_EDGE as GLint); gl::TexParameteri(gl::TEXTURE_RECTANGLE, gl::TEXTURE_WRAP_T, gl::CLAMP_TO_EDGE as GLint); gl::GenFramebuffers(1, &mut framebuffer); gl::BindFramebuffer(gl::FRAMEBUFFER, framebuffer); gl::FramebufferTexture2D(gl::FRAMEBUFFER, gl::COLOR_ATTACHMENT0, gl::TEXTURE_RECTANGLE, gl_texture, 0); gl::BindFramebuffer(gl::FRAMEBUFFER, 0); } Ok(CoverageBuffer { image: image, framebuffer: framebuffer, }) } #[doc(hidden)] #[inline] pub fn image(&self) -> &Image { &self.image } #[doc(hidden)] #[inline] pub fn framebuffer(&self) -> GLuint { self.framebuffer } } impl Drop for CoverageBuffer { fn drop(&mut self) { unsafe { let mut gl_texture = 0; gl::BindFramebuffer(gl::FRAMEBUFFER, self.framebuffer); gl::GetFramebufferAttachmentParameteriv(gl::FRAMEBUFFER, gl::COLOR_ATTACHMENT0, gl::FRAMEBUFFER_ATTACHMENT_OBJECT_NAME, &mut gl_texture as *mut GLuint as *mut GLint); gl::DeleteTextures(1, &mut gl_texture); gl::BindFramebuffer(gl::FRAMEBUFFER, 0); gl::DeleteFramebuffers(1, &mut self.framebuffer); } } } /// Options that control the format of the coverage buffer. #[derive(Clone, Copy, Debug)] pub struct CoverageBufferOptions { /// The size of the coverage buffer. /// /// The size must be at least as large as every atlas you will render with the buffer. pub size: Size2D, /// Whether this coverage buffer is intended for subpixel antialiasing. /// /// If this buffer is intended for subpixel AA, all atlas rendered with it must use subpixel /// AA, and vice versa. pub subpixel_antialiasing: bool, } impl Default for CoverageBufferOptions { #[inline] fn default() -> CoverageBufferOptions { CoverageBufferOptions { size: Size2D::new(DEFAULT_COVERAGE_BUFFER_SIZE, DEFAULT_COVERAGE_BUFFER_SIZE), subpixel_antialiasing: false, } } }