<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

#[macro_use]
extern crate clap;
#[macro_use]
extern crate log;
#[macro_use]
extern crate serde;
#[macro_use]
extern crate tracy_rs;

mod angle;
mod blob;
mod egl;
mod parse_function;
mod perf;
mod png;
mod premultiply;
mod rawtest;
mod reftest;
mod test_invalidation;
mod wrench;
mod yaml_frame_reader;
mod yaml_helper;

use gleam::gl;
#[cfg(feature = "software")]
use gleam::gl::Gl;
use crate::perf::PerfHarness;
use crate::png::save_flipped;
use crate::rawtest::RawtestHarness;
use crate::reftest::{ReftestHarness, ReftestOptions};
use std::fs;
#[cfg(feature = "headless")]
use std::ffi::CString;
#[cfg(feature = "headless")]
use std::mem;
use std::os::raw::c_void;
use std::path::{Path, PathBuf};
use std::process;
use std::ptr;
use std::rc::Rc;
#[cfg(feature = "software")]
use std::slice;
use std::sync::mpsc::{channel, Sender, Receiver};
use webrender::DebugFlags;
use webrender::api::*;
use webrender::render_api::*;
use webrender::api::units::*;
use winit::dpi::{LogicalPosition, LogicalSize};
use winit::VirtualKeyCode;
use crate::wrench::{CapturedSequence, Wrench, WrenchThing};
use crate::yaml_frame_reader::YamlFrameReader;

pub const PLATFORM_DEFAULT_FACE_NAME: &str = "Arial";

pub static mut CURRENT_FRAME_NUMBER: u32 = 0;

#[cfg(feature = "headless")]
pub struct HeadlessContext {
    width: i32,
    height: i32,
    _context: osmesa_sys::OSMesaContext,
    _buffer: Vec<u32>,
}

#[cfg(not(feature = "headless"))]
pub struct HeadlessContext {
    width: i32,
    height: i32,
}

impl HeadlessContext {
    #[cfg(feature = "headless")]
    fn new(width: i32, height: i32) -> Self {
        let mut attribs = Vec::new();

        attribs.push(osmesa_sys::OSMESA_PROFILE);
        attribs.push(osmesa_sys::OSMESA_CORE_PROFILE);
        attribs.push(osmesa_sys::OSMESA_CONTEXT_MAJOR_VERSION);
        attribs.push(3);
        attribs.push(osmesa_sys::OSMESA_CONTEXT_MINOR_VERSION);
        attribs.push(3);
        attribs.push(osmesa_sys::OSMESA_DEPTH_BITS);
        attribs.push(24);
        attribs.push(0);

        let context =
            unsafe { osmesa_sys::OSMesaCreateContextAttribs(attribs.as_ptr(), ptr::null_mut()) };

        assert!(!context.is_null());

        let mut buffer = vec![0; (width * height) as usize];

        unsafe {
            let ret = osmesa_sys::OSMesaMakeCurrent(
                context,
                buffer.as_mut_ptr() as *mut _,
                gl::UNSIGNED_BYTE,
                width,
                height,
            );
            assert!(ret != 0);
        };

        HeadlessContext {
            width,
            height,
            _context: context,
            _buffer: buffer,
        }
    }

    #[cfg(not(feature = "headless"))]
    fn new(width: i32, height: i32) -> Self {
        HeadlessContext { width, height }
    }

    #[cfg(feature = "headless")]
    fn get_proc_address(s: &str) -> *const c_void {
        let c_str = CString::new(s).expect("Unable to create CString");
        unsafe { mem::transmute(osmesa_sys::OSMesaGetProcAddress(c_str.as_ptr())) }
    }

    #[cfg(not(feature = "headless"))]
    fn get_proc_address(_: &str) -> *const c_void {
        ptr::null() as *const _
    }
}

#[cfg(not(feature = "software"))]
mod swgl {
    pub struct Context;
}

pub enum WindowWrapper {
    WindowedContext(glutin::WindowedContext<glutin::PossiblyCurrent>, Rc<dyn gl::Gl>, Option<swgl::Context>),
    Angle(winit::Window, angle::Context, Rc<dyn gl::Gl>, Option<swgl::Context>),
    Headless(HeadlessContext, Rc<dyn gl::Gl>, Option<swgl::Context>),
}

pub struct HeadlessEventIterater;

impl WindowWrapper {
    #[cfg(feature = "software")]
    fn upload_software_to_native(&self) {
        match *self {
            WindowWrapper::Headless(..) => return,
            _ => {}
        }
        let swgl = match self.software_gl() {
            Some(swgl) => swgl,
            None => return,
        };
        swgl.finish();
        let gl = self.native_gl();
        let tex = gl.gen_textures(1)[0];
        gl.bind_texture(gl::TEXTURE_2D, tex);
        let (data_ptr, w, h, stride) = swgl.get_color_buffer(0, true);
        assert!(stride == w * 4);
        let buffer = unsafe { slice::from_raw_parts(data_ptr as *const u8, w as usize * h as usize * 4) };
        gl.tex_image_2d(gl::TEXTURE_2D, 0, gl::RGBA8 as gl::GLint, w, h, 0, gl::BGRA, gl::UNSIGNED_BYTE, Some(buffer));
        let fb = gl.gen_framebuffers(1)[0];
        gl.bind_framebuffer(gl::READ_FRAMEBUFFER, fb);
        gl.framebuffer_texture_2d(gl::READ_FRAMEBUFFER, gl::COLOR_ATTACHMENT0, gl::TEXTURE_2D, tex, 0);
        gl.blit_framebuffer(0, 0, w, h, 0, 0, w, h, gl::COLOR_BUFFER_BIT, gl::NEAREST);
        gl.delete_framebuffers(&[fb]);
        gl.delete_textures(&[tex]);
        gl.finish();
    }

    #[cfg(not(feature = "software"))]
    fn upload_software_to_native(&self) {
    }

    fn swap_buffers(&self) {
        match *self {
            WindowWrapper::WindowedContext(ref windowed_context, _, _) => {
                windowed_context.swap_buffers().unwrap()
            }
            WindowWrapper::Angle(_, ref context, _, _) => context.swap_buffers().unwrap(),
            WindowWrapper::Headless(_, _, _) => {}
        }
    }

    fn get_inner_size(&self) -> DeviceIntSize {
        fn inner_size(window: &winit::Window) -> DeviceIntSize {
            let size = window
                .get_inner_size()
                .unwrap()
                .to_physical(window.get_hidpi_factor());
            DeviceIntSize::new(size.width as i32, size.height as i32)
        }
        match *self {
            WindowWrapper::WindowedContext(ref windowed_context, ..) => {
                inner_size(windowed_context.window())
            }
            WindowWrapper::Angle(ref window, ..) => inner_size(window),
            WindowWrapper::Headless(ref context, ..) => DeviceIntSize::new(context.width, context.height),
        }
    }

    fn hidpi_factor(&self) -> f32 {
        match *self {
            WindowWrapper::WindowedContext(ref windowed_context, ..) => {
                windowed_context.window().get_hidpi_factor() as f32
            }
            WindowWrapper::Angle(ref window, ..) => window.get_hidpi_factor() as f32,
            WindowWrapper::Headless(..) => 1.0,
        }
    }

    fn resize(&mut self, size: DeviceIntSize) {
        match *self {
            WindowWrapper::WindowedContext(ref mut windowed_context, ..) => {
                windowed_context.window()
                    .set_inner_size(LogicalSize::new(size.width as f64, size.height as f64))
            },
            WindowWrapper::Angle(ref mut window, ..) => {
                window.set_inner_size(LogicalSize::new(size.width as f64, size.height as f64))
            },
            WindowWrapper::Headless(..) => unimplemented!(), // requites Glutin update
        }
    }

    fn set_title(&mut self, title: &str) {
        match *self {
            WindowWrapper::WindowedContext(ref windowed_context, ..) => {
                windowed_context.window().set_title(title)
            }
            WindowWrapper::Angle(ref window, ..) => window.set_title(title),
            WindowWrapper::Headless(..) => (),
        }
    }

    pub fn software_gl(&self) -> Option<&swgl::Context> {
        match *self {
            WindowWrapper::WindowedContext(_, _, ref swgl) |
            WindowWrapper::Angle(_, _, _, ref swgl) |
            WindowWrapper::Headless(_, _, ref swgl) => swgl.as_ref(),
        }
    }

    pub fn native_gl(&self) -> &dyn gl::Gl {
        match *self {
            WindowWrapper::WindowedContext(_, ref gl, _) |
            WindowWrapper::Angle(_, _, ref gl, _) |
            WindowWrapper::Headless(_, ref gl, _) => &**gl,
        }
    }

    #[cfg(feature = "software")]
    pub fn gl(&self) -> &dyn gl::Gl {
        if let Some(swgl) = self.software_gl() {
            swgl
        } else {
            self.native_gl()
        }
    }

    pub fn is_software(&self) -> bool {
        self.software_gl().is_some()
    }

    #[cfg(not(feature = "software"))]
    pub fn gl(&self) -> &dyn gl::Gl {
        self.native_gl()
    }

    pub fn clone_gl(&self) -> Rc<dyn gl::Gl> {
        match *self {
            WindowWrapper::WindowedContext(_, ref gl, ref swgl) |
            WindowWrapper::Angle(_, _, ref gl, ref swgl) |
            WindowWrapper::Headless(_, ref gl, ref swgl) => {
                match swgl {
                    #[cfg(feature = "software")]
                    Some(ref swgl) => Rc::new(swgl.clone()),
                    None => gl.clone(),
                    #[cfg(not(feature = "software"))]
                    _ => panic!(),
                }
            }
        }
    }


    #[cfg(feature = "software")]
    fn update_software(&self, dim: DeviceIntSize) {
        if let Some(swgl) = self.software_gl() {
            swgl.init_default_framebuffer(dim.width, dim.height, 0, std::ptr::null_mut());
        }
    }

    #[cfg(not(feature = "software"))]
    fn update_software(&self, _dim: DeviceIntSize) {
    }

    fn update(&self, wrench: &mut Wrench) {
        let dim = self.get_inner_size();
        self.update_software(dim);
        wrench.update(dim);
    }
}

#[cfg(feature = "software")]
fn make_software_context() -> Option<swgl::Context> {
    let ctx = swgl::Context::create();
    ctx.make_current();
    Some(ctx)
}

#[cfg(not(feature = "software"))]
fn make_software_context() -> Option<swgl::Context> {
    None
}

fn make_window(
    size: DeviceIntSize,
    dp_ratio: Option<f32>,
    vsync: bool,
    events_loop: &Option<winit::EventsLoop>,
    angle: bool,
    gl_request: glutin::GlRequest,
    software: bool,
) -> WindowWrapper {
    let sw_ctx = if software {<commit_msg>Bug 1678711 - Make running with --software without the "software" feature panic. r=lsalzman<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

#[macro_use]
extern crate clap;
#[macro_use]
extern crate log;
#[macro_use]
extern crate serde;
#[macro_use]
extern crate tracy_rs;

mod angle;
mod blob;
mod egl;
mod parse_function;
mod perf;
mod png;
mod premultiply;
mod rawtest;
mod reftest;
mod test_invalidation;
mod wrench;
mod yaml_frame_reader;
mod yaml_helper;

use gleam::gl;
#[cfg(feature = "software")]
use gleam::gl::Gl;
use crate::perf::PerfHarness;
use crate::png::save_flipped;
use crate::rawtest::RawtestHarness;
use crate::reftest::{ReftestHarness, ReftestOptions};
use std::fs;
#[cfg(feature = "headless")]
use std::ffi::CString;
#[cfg(feature = "headless")]
use std::mem;
use std::os::raw::c_void;
use std::path::{Path, PathBuf};
use std::process;
use std::ptr;
use std::rc::Rc;
#[cfg(feature = "software")]
use std::slice;
use std::sync::mpsc::{channel, Sender, Receiver};
use webrender::DebugFlags;
use webrender::api::*;
use webrender::render_api::*;
use webrender::api::units::*;
use winit::dpi::{LogicalPosition, LogicalSize};
use winit::VirtualKeyCode;
use crate::wrench::{CapturedSequence, Wrench, WrenchThing};
use crate::yaml_frame_reader::YamlFrameReader;

pub const PLATFORM_DEFAULT_FACE_NAME: &str = "Arial";

pub static mut CURRENT_FRAME_NUMBER: u32 = 0;

#[cfg(feature = "headless")]
pub struct HeadlessContext {
    width: i32,
    height: i32,
    _context: osmesa_sys::OSMesaContext,
    _buffer: Vec<u32>,
}

#[cfg(not(feature = "headless"))]
pub struct HeadlessContext {
    width: i32,
    height: i32,
}

impl HeadlessContext {
    #[cfg(feature = "headless")]
    fn new(width: i32, height: i32) -> Self {
        let mut attribs = Vec::new();

        attribs.push(osmesa_sys::OSMESA_PROFILE);
        attribs.push(osmesa_sys::OSMESA_CORE_PROFILE);
        attribs.push(osmesa_sys::OSMESA_CONTEXT_MAJOR_VERSION);
        attribs.push(3);
        attribs.push(osmesa_sys::OSMESA_CONTEXT_MINOR_VERSION);
        attribs.push(3);
        attribs.push(osmesa_sys::OSMESA_DEPTH_BITS);
        attribs.push(24);
        attribs.push(0);

        let context =
            unsafe { osmesa_sys::OSMesaCreateContextAttribs(attribs.as_ptr(), ptr::null_mut()) };

        assert!(!context.is_null());

        let mut buffer = vec![0; (width * height) as usize];

        unsafe {
            let ret = osmesa_sys::OSMesaMakeCurrent(
                context,
                buffer.as_mut_ptr() as *mut _,
                gl::UNSIGNED_BYTE,
                width,
                height,
            );
            assert!(ret != 0);
        };

        HeadlessContext {
            width,
            height,
            _context: context,
            _buffer: buffer,
        }
    }

    #[cfg(not(feature = "headless"))]
    fn new(width: i32, height: i32) -> Self {
        HeadlessContext { width, height }
    }

    #[cfg(feature = "headless")]
    fn get_proc_address(s: &str) -> *const c_void {
        let c_str = CString::new(s).expect("Unable to create CString");
        unsafe { mem::transmute(osmesa_sys::OSMesaGetProcAddress(c_str.as_ptr())) }
    }

    #[cfg(not(feature = "headless"))]
    fn get_proc_address(_: &str) -> *const c_void {
        ptr::null() as *const _
    }
}

#[cfg(not(feature = "software"))]
mod swgl {
    pub struct Context;
}

pub enum WindowWrapper {
    WindowedContext(glutin::WindowedContext<glutin::PossiblyCurrent>, Rc<dyn gl::Gl>, Option<swgl::Context>),
    Angle(winit::Window, angle::Context, Rc<dyn gl::Gl>, Option<swgl::Context>),
    Headless(HeadlessContext, Rc<dyn gl::Gl>, Option<swgl::Context>),
}

pub struct HeadlessEventIterater;

impl WindowWrapper {
    #[cfg(feature = "software")]
    fn upload_software_to_native(&self) {
        match *self {
            WindowWrapper::Headless(..) => return,
            _ => {}
        }
        let swgl = match self.software_gl() {
            Some(swgl) => swgl,
            None => return,
        };
        swgl.finish();
        let gl = self.native_gl();
        let tex = gl.gen_textures(1)[0];
        gl.bind_texture(gl::TEXTURE_2D, tex);
        let (data_ptr, w, h, stride) = swgl.get_color_buffer(0, true);
        assert!(stride == w * 4);
        let buffer = unsafe { slice::from_raw_parts(data_ptr as *const u8, w as usize * h as usize * 4) };
        gl.tex_image_2d(gl::TEXTURE_2D, 0, gl::RGBA8 as gl::GLint, w, h, 0, gl::BGRA, gl::UNSIGNED_BYTE, Some(buffer));
        let fb = gl.gen_framebuffers(1)[0];
        gl.bind_framebuffer(gl::READ_FRAMEBUFFER, fb);
        gl.framebuffer_texture_2d(gl::READ_FRAMEBUFFER, gl::COLOR_ATTACHMENT0, gl::TEXTURE_2D, tex, 0);
        gl.blit_framebuffer(0, 0, w, h, 0, 0, w, h, gl::COLOR_BUFFER_BIT, gl::NEAREST);
        gl.delete_framebuffers(&[fb]);
        gl.delete_textures(&[tex]);
        gl.finish();
    }

    #[cfg(not(feature = "software"))]
    fn upload_software_to_native(&self) {
    }

    fn swap_buffers(&self) {
        match *self {
            WindowWrapper::WindowedContext(ref windowed_context, _, _) => {
                windowed_context.swap_buffers().unwrap()
            }
            WindowWrapper::Angle(_, ref context, _, _) => context.swap_buffers().unwrap(),
            WindowWrapper::Headless(_, _, _) => {}
        }
    }

    fn get_inner_size(&self) -> DeviceIntSize {
        fn inner_size(window: &winit::Window) -> DeviceIntSize {
            let size = window
                .get_inner_size()
                .unwrap()
                .to_physical(window.get_hidpi_factor());
            DeviceIntSize::new(size.width as i32, size.height as i32)
        }
        match *self {
            WindowWrapper::WindowedContext(ref windowed_context, ..) => {
                inner_size(windowed_context.window())
            }
            WindowWrapper::Angle(ref window, ..) => inner_size(window),
            WindowWrapper::Headless(ref context, ..) => DeviceIntSize::new(context.width, context.height),
        }
    }

    fn hidpi_factor(&self) -> f32 {
        match *self {
            WindowWrapper::WindowedContext(ref windowed_context, ..) => {
                windowed_context.window().get_hidpi_factor() as f32
            }
            WindowWrapper::Angle(ref window, ..) => window.get_hidpi_factor() as f32,
            WindowWrapper::Headless(..) => 1.0,
        }
    }

    fn resize(&mut self, size: DeviceIntSize) {
        match *self {
            WindowWrapper::WindowedContext(ref mut windowed_context, ..) => {
                windowed_context.window()
                    .set_inner_size(LogicalSize::new(size.width as f64, size.height as f64))
            },
            WindowWrapper::Angle(ref mut window, ..) => {
                window.set_inner_size(LogicalSize::new(size.width as f64, size.height as f64))
            },
            WindowWrapper::Headless(..) => unimplemented!(), // requites Glutin update
        }
    }

    fn set_title(&mut self, title: &str) {
        match *self {
            WindowWrapper::WindowedContext(ref windowed_context, ..) => {
                windowed_context.window().set_title(title)
            }
            WindowWrapper::Angle(ref window, ..) => window.set_title(title),
            WindowWrapper::Headless(..) => (),
        }
    }

    pub fn software_gl(&self) -> Option<&swgl::Context> {
        match *self {
            WindowWrapper::WindowedContext(_, _, ref swgl) |
            WindowWrapper::Angle(_, _, _, ref swgl) |
            WindowWrapper::Headless(_, _, ref swgl) => swgl.as_ref(),
        }
    }

    pub fn native_gl(&self) -> &dyn gl::Gl {
        match *self {
            WindowWrapper::WindowedContext(_, ref gl, _) |
            WindowWrapper::Angle(_, _, ref gl, _) |
            WindowWrapper::Headless(_, ref gl, _) => &**gl,
        }
    }

    #[cfg(feature = "software")]
    pub fn gl(&self) -> &dyn gl::Gl {
        if let Some(swgl) = self.software_gl() {
            swgl
        } else {
            self.native_gl()
        }
    }

    pub fn is_software(&self) -> bool {
        self.software_gl().is_some()
    }

    #[cfg(not(feature = "software"))]
    pub fn gl(&self) -> &dyn gl::Gl {
        self.native_gl()
    }

    pub fn clone_gl(&self) -> Rc<dyn gl::Gl> {
        match *self {
            WindowWrapper::WindowedContext(_, ref gl, ref swgl) |
            WindowWrapper::Angle(_, _, ref gl, ref swgl) |
            WindowWrapper::Headless(_, ref gl, ref swgl) => {
                match swgl {
                    #[cfg(feature = "software")]
                    Some(ref swgl) => Rc::new(swgl.clone()),
                    None => gl.clone(),
                    #[cfg(not(feature = "software"))]
                    _ => panic!(),
                }
            }
        }
    }


    #[cfg(feature = "software")]
    fn update_software(&self, dim: DeviceIntSize) {
        if let Some(swgl) = self.software_gl() {
            swgl.init_default_framebuffer(dim.width, dim.height, 0, std::ptr::null_mut());
        }
    }

    #[cfg(not(feature = "software"))]
    fn update_software(&self, _dim: DeviceIntSize) {
    }

    fn update(&self, wrench: &mut Wrench) {
        let dim = self.get_inner_size();
        self.update_software(dim);
        wrench.update(dim);
    }
}

#[cfg(feature = "software")]
fn make_software_context() -> swgl::Context {
    let ctx = swgl::Context::create();
    ctx.make_current();
    ctx
}

#[cfg(not(feature = "software"))]
fn make_software_context() -> swgl::Context {
    panic!("software feature not enabled")
}

fn make_window(
    size: DeviceIntSize,
    dp_ratio: Option<f32>,
    vsync: bool,
    events_loop: &Option<winit::EventsLoop>,
    angle: bool,
    gl_request: glutin::GlRequest,
    software: bool,
) -> WindowWrapper {
    let sw_ctx = if software {
{'fraction_non_alphanumeric': 0.14563106796116504, 'fraction_numerical': 0.008057251526373736, 'mean_word_length': 2.500875963559916, 'pattern_counts': {'":': 0, '<': 29, '<?xml version=': 0, '>': 111, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '189239', 'n_tokens_mistral': 6720, 'n_tokens_neox': 6519, 'n_words': 1308}