<commit_before>//! Contains support for user-managed thread pools, represented by the
//! the [`ThreadPool`] type (see that struct for details).
//!
//! [`ThreadPool`]: struct.ThreadPool.html

use join;
use registry::{Registry, WorkerThread};
use spawn;
use std::error::Error;
use std::fmt;
use std::sync::Arc;
#[allow(deprecated)]
use Configuration;
use {scope, Scope};
use {scope_fifo, ScopeFifo};
use {ThreadPoolBuildError, ThreadPoolBuilder};

mod internal;
mod test;

/// Represents a user created [thread-pool].
///
/// Use a [`ThreadPoolBuilder`] to specify the number and/or names of threads
/// in the pool. After calling [`ThreadPoolBuilder::build()`], you can then
/// execute functions explicitly within this [`ThreadPool`] using
/// [`ThreadPool::install()`]. By contrast, top level rayon functions
/// (like `join()`) will execute implicitly within the current thread-pool.
///
///
/// ## Creating a ThreadPool
///
/// ```rust
/// # use rayon_core as rayon;
/// let pool = rayon::ThreadPoolBuilder::new().num_threads(8).build().unwrap();
/// ```
///
/// [`install()`][`ThreadPool::install()`] executes a closure in one of the `ThreadPool`'s
/// threads. In addition, any other rayon operations called inside of `install()` will also
/// execute in the context of the `ThreadPool`.
///
/// When the `ThreadPool` is dropped, that's a signal for the threads it manages to terminate,
/// they will complete executing any remaining work that you have spawned, and automatically
/// terminate.
///
///
/// [thread-pool]: https://en.wikipedia.org/wiki/Thread_pool
/// [`ThreadPool`]: struct.ThreadPool.html
/// [`ThreadPool::new()`]: struct.ThreadPool.html#method.new
/// [`ThreadPoolBuilder`]: struct.ThreadPoolBuilder.html
/// [`ThreadPoolBuilder::build()`]: struct.ThreadPoolBuilder.html#method.build
/// [`ThreadPool::install()`]: struct.ThreadPool.html#method.install
pub struct ThreadPool {
    registry: Arc<Registry>,
}

pub fn build(builder: ThreadPoolBuilder) -> Result<ThreadPool, ThreadPoolBuildError> {
    let registry = try!(Registry::new(builder));
    Ok(ThreadPool { registry: registry })
}

impl ThreadPool {
    #[deprecated(note = "Use `ThreadPoolBuilder::build`")]
    #[allow(deprecated)]
    /// Deprecated in favor of `ThreadPoolBuilder::build`.
    pub fn new(configuration: Configuration) -> Result<ThreadPool, Box<Error>> {
        build(configuration.into_builder()).map_err(|e| e.into())
    }

    /// Returns a handle to the global thread pool. This is the pool
    /// that Rayon will use by default when you perform a `join()` or
    /// `scope()` operation, if no other thread-pool is installed. If
    /// no global thread-pool has yet been started when this function
    /// is called, then the global thread-pool will be created (with
    /// the default configuration). If you wish to configure the
    /// global thread-pool differently, then you can use [the
    /// `rayon::initialize()` function][f] to do so.
    ///
    /// [f]: fn.initialize.html
    #[cfg(rayon_unstable)]
    pub fn global() -> &'static Arc<ThreadPool> {
        lazy_static! {
            static ref DEFAULT_THREAD_POOL: Arc<ThreadPool> = Arc::new(ThreadPool {
                registry: Registry::global()
            });
        }

        &DEFAULT_THREAD_POOL
    }

    /// Executes `op` within the threadpool. Any attempts to use
    /// `join`, `scope`, or parallel iterators will then operate
    /// within that threadpool.
    ///
    /// # Warning: thread-local data
    ///
    /// Because `op` is executing within the Rayon thread-pool,
    /// thread-local data from the current thread will not be
    /// accessible.
    ///
    /// # Panics
    ///
    /// If `op` should panic, that panic will be propagated.
    ///
    /// ## Using `install()`
    ///
    /// ```rust
    ///    # use rayon_core as rayon;
    ///    fn main() {
    ///         let pool = rayon::ThreadPoolBuilder::new().num_threads(8).build().unwrap();
    ///         let n = pool.install(|| fib(20));
    ///         println!("{}", n);
    ///    }
    ///
    ///    fn fib(n: usize) -> usize {
    ///         if n == 0 || n == 1 {
    ///             return n;
    ///         }
    ///         let (a, b) = rayon::join(|| fib(n - 1), || fib(n - 2)); // runs inside of `pool`
    ///         return a + b;
    ///     }
    /// ```
    pub fn install<OP, R>(&self, op: OP) -> R
    where
        OP: FnOnce() -> R + Send,
        R: Send,
    {
        self.registry.in_worker(|_, _| op())
    }

    /// Returns the (current) number of threads in the thread pool.
    ///
    /// # Future compatibility note
    ///
    /// Note that unless this thread-pool was created with a
    /// [`ThreadPoolBuilder`] that specifies the number of threads,
    /// then this number may vary over time in future versions (see [the
    /// `num_threads()` method for details][snt]).
    ///
    /// [snt]: struct.ThreadPoolBuilder.html#method.num_threads
    /// [`ThreadPoolBuilder`]: struct.ThreadPoolBuilder.html
    #[inline]
    pub fn current_num_threads(&self) -> usize {
        self.registry.num_threads()
    }

    /// If called from a Rayon worker thread in this thread-pool,
    /// returns the index of that thread; if not called from a Rayon
    /// thread, or called from a Rayon thread that belongs to a
    /// different thread-pool, returns `None`.
    ///
    /// The index for a given thread will not change over the thread's
    /// lifetime. However, multiple threads may share the same index if
    /// they are in distinct thread-pools.
    ///
    /// # Future compatibility note
    ///
    /// Currently, every thread-pool (including the global
    /// thread-pool) has a fixed number of threads, but this may
    /// change in future Rayon versions (see [the `num_threads()` method
    /// for details][snt]). In that case, the index for a
    /// thread would not change during its lifetime, but thread
    /// indices may wind up being reused if threads are terminated and
    /// restarted.
    ///
    /// [snt]: struct.ThreadPoolBuilder.html#method.num_threads
    #[inline]
    pub fn current_thread_index(&self) -> Option<usize> {
        unsafe {
            let curr = WorkerThread::current();
            if curr.is_null() {
                None
            } else if (*curr).registry().id() != self.registry.id() {
                None
            } else {
                Some((*curr).index())
            }
        }
    }

    /// Returns true if the current worker thread currently has "local
    /// tasks" pending. This can be useful as part of a heuristic for
    /// deciding whether to spawn a new task or execute code on the
    /// current thread, particularly in breadth-first
    /// schedulers. However, keep in mind that this is an inherently
    /// racy check, as other worker threads may be actively "stealing"
    /// tasks from our local deque.
    ///
    /// **Background:** Rayon's uses a [work-stealing] scheduler. The
    /// key idea is that each thread has its own [deque] of
    /// tasks. Whenever a new task is spawned -- whether through
    /// `join()`, `Scope::spawn()`, or some other means -- that new
    /// task is pushed onto the thread's *local* deque. Worker threads
    /// have a preference for executing their own tasks; if however
    /// they run out of tasks, they will go try to "steal" tasks from
    /// other threads. This function therefore has an inherent race
    /// with other active worker threads, which may be removing items
    /// from the local deque.
    ///
    /// [work-stealing]: https://en.wikipedia.org/wiki/Work_stealing
    /// [deque]: https://en.wikipedia.org/wiki/Double-ended_queue
    #[inline]
    pub fn current_thread_has_pending_tasks(&self) -> Option<bool> {
        unsafe {
            let curr = WorkerThread::current();
            if curr.is_null() {
                None
            } else if (*curr).registry().id() != self.registry.id() {
                None
            } else {
                Some(!(*curr).local_deque_is_empty())
            }
        }
    }

    /// Execute `oper_a` and `oper_b` in the thread-pool and return
    /// the results. Equivalent to `self.install(|| join(oper_a,
    /// oper_b))`.
    pub fn join<A, B, RA, RB>(&self, oper_a: A, oper_b: B) -> (RA, RB)
    where
        A: FnOnce() -> RA + Send,
        B: FnOnce() -> RB + Send,
        RA: Send,
        RB: Send,
    {
        self.install(|| join(oper_a, oper_b))
    }

    /// Creates a scope that executes within this thread-pool.
    /// Equivalent to `self.install(|| scope(...))`.
    ///
    /// See also: [the `scope()` function][scope].
    ///
    /// [scope]: fn.scope.html
    pub fn scope<'scope, OP, R>(&self, op: OP) -> R
    where
        OP: for<'s> FnOnce(&'s Scope<'scope>) -> R + 'scope + Send,
        R: Send,
    {
        self.install(|| scope(op))
    }

    /// Creates a scope that executes within this thread-pool.
    /// Spawns from the same thread are prioritized in relative FIFO order.
    /// Equivalent to `self.install(|| scope_fifo(...))`.
    ///
    /// See also: [the `scope_fifo()` function][scope_fifo].
    ///
    /// [scope_fifo]: fn.scope_fifo.html
    pub fn scope_fifo<'scope, OP, R>(&self, op: OP) -> R
    where
        OP: for<'s> FnOnce(&'s ScopeFifo<'scope>) -> R + 'scope + Send,
        R: Send,
    {
        self.install(|| scope_fifo(op))
    }

    /// Spawns an asynchronous task in this thread-pool. This task will
    /// run in the implicit, global scope, which means that it may outlast
    /// the current stack frame -- therefore, it cannot capture any references
    /// onto the stack (you will likely need a `move` closure).
    ///
    /// See also: [the `spawn()` function defined on scopes][spawn].
    ///
    /// [spawn]: struct.Scope.html#method.spawn
    pub fn spawn<OP>(&self, op: OP)
    where
        OP: FnOnce() + Send + 'static,
    {
        // We assert that `self.registry` has not terminated.
        unsafe { spawn::spawn_in(op, &self.registry) }
    }

    /// TODO: like `spawn`, but FIFO
    pub fn spawn_fifo<OP>(&self, op: OP)
    where
        OP: FnOnce() + Send + 'static,
    {
        // We assert that `self.registry` has not terminated.
        unsafe { spawn::spawn_fifo_in(op, &self.registry) }
    }
}

impl Drop for ThreadPool {
    fn drop(&mut self) {
        self.registry.terminate();
    }
}

impl fmt::Debug for ThreadPool {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        fmt.debug_struct("ThreadPool")
            .field("num_threads", &self.current_num_threads())
            .field("id", &self.registry.id())
            .finish()
    }
}

/// If called from a Rayon worker thread, returns the index of that
/// thread within its current pool; if not called from a Rayon thread,
/// returns `None`.
///
/// The index for a given thread will not change over the thread's
/// lifetime. However, multiple threads may share the same index if
/// they are in distinct thread-pools.
///
/// See also: [the `ThreadPool::current_thread_index()` method].
///
/// [m]: struct.ThreadPool.html#method.current_thread_index
///
/// # Future compatibility note
///
/// Currently, every thread-pool (including the global
/// thread-pool) has a fixed number of threads, but this may
/// change in future Rayon versions (see [the `num_threads()` method
/// for details][snt]). In that case, the index for a
/// thread would not change during its lifetime, but thread
/// indices may wind up being reused if threads are terminated and
/// restarted.
///
/// [snt]: struct.ThreadPoolBuilder.html#method.num_threads
#[inline]
pub fn current_thread_index() -> Option<usize> {
    unsafe {
        let curr = WorkerThread::current();
        if curr.is_null() {
            None
        } else {
            Some((*curr).index())
        }
    }
}

/// If called from a Rayon worker thread, indicates whether that
/// thread's local deque still has pending tasks. Otherwise, returns
/// `None`. For more information, see [the
/// `ThreadPool::current_thread_has_pending_tasks()` method][m].
///
/// [m]: struct.ThreadPool.html#method.current_thread_has_pending_tasks
#[inline]
pub fn current_thread_has_pending_tasks() -> Option<bool> {
    unsafe {
        let curr = WorkerThread::current();
        if curr.is_null() {
            None
        } else {
            Some(!(*curr).local_deque_is_empty())
        }
    }
}
<commit_msg>Document `ThreadPool::spawn_fifo`<commit_after>//! Contains support for user-managed thread pools, represented by the
//! the [`ThreadPool`] type (see that struct for details).
//!
//! [`ThreadPool`]: struct.ThreadPool.html

use join;
use registry::{Registry, WorkerThread};
use spawn;
use std::error::Error;
use std::fmt;
use std::sync::Arc;
#[allow(deprecated)]
use Configuration;
use {scope, Scope};
use {scope_fifo, ScopeFifo};
use {ThreadPoolBuildError, ThreadPoolBuilder};

mod internal;
mod test;

/// Represents a user created [thread-pool].
///
/// Use a [`ThreadPoolBuilder`] to specify the number and/or names of threads
/// in the pool. After calling [`ThreadPoolBuilder::build()`], you can then
/// execute functions explicitly within this [`ThreadPool`] using
/// [`ThreadPool::install()`]. By contrast, top level rayon functions
/// (like `join()`) will execute implicitly within the current thread-pool.
///
///
/// ## Creating a ThreadPool
///
/// ```rust
/// # use rayon_core as rayon;
/// let pool = rayon::ThreadPoolBuilder::new().num_threads(8).build().unwrap();
/// ```
///
/// [`install()`][`ThreadPool::install()`] executes a closure in one of the `ThreadPool`'s
/// threads. In addition, any other rayon operations called inside of `install()` will also
/// execute in the context of the `ThreadPool`.
///
/// When the `ThreadPool` is dropped, that's a signal for the threads it manages to terminate,
/// they will complete executing any remaining work that you have spawned, and automatically
/// terminate.
///
///
/// [thread-pool]: https://en.wikipedia.org/wiki/Thread_pool
/// [`ThreadPool`]: struct.ThreadPool.html
/// [`ThreadPool::new()`]: struct.ThreadPool.html#method.new
/// [`ThreadPoolBuilder`]: struct.ThreadPoolBuilder.html
/// [`ThreadPoolBuilder::build()`]: struct.ThreadPoolBuilder.html#method.build
/// [`ThreadPool::install()`]: struct.ThreadPool.html#method.install
pub struct ThreadPool {
    registry: Arc<Registry>,
}

pub fn build(builder: ThreadPoolBuilder) -> Result<ThreadPool, ThreadPoolBuildError> {
    let registry = try!(Registry::new(builder));
    Ok(ThreadPool { registry: registry })
}

impl ThreadPool {
    #[deprecated(note = "Use `ThreadPoolBuilder::build`")]
    #[allow(deprecated)]
    /// Deprecated in favor of `ThreadPoolBuilder::build`.
    pub fn new(configuration: Configuration) -> Result<ThreadPool, Box<Error>> {
        build(configuration.into_builder()).map_err(|e| e.into())
    }

    /// Returns a handle to the global thread pool. This is the pool
    /// that Rayon will use by default when you perform a `join()` or
    /// `scope()` operation, if no other thread-pool is installed. If
    /// no global thread-pool has yet been started when this function
    /// is called, then the global thread-pool will be created (with
    /// the default configuration). If you wish to configure the
    /// global thread-pool differently, then you can use [the
    /// `rayon::initialize()` function][f] to do so.
    ///
    /// [f]: fn.initialize.html
    #[cfg(rayon_unstable)]
    pub fn global() -> &'static Arc<ThreadPool> {
        lazy_static! {
            static ref DEFAULT_THREAD_POOL: Arc<ThreadPool> = Arc::new(ThreadPool {
                registry: Registry::global()
            });
        }

        &DEFAULT_THREAD_POOL
    }

    /// Executes `op` within the threadpool. Any attempts to use
    /// `join`, `scope`, or parallel iterators will then operate
    /// within that threadpool.
    ///
    /// # Warning: thread-local data
    ///
    /// Because `op` is executing within the Rayon thread-pool,
    /// thread-local data from the current thread will not be
    /// accessible.
    ///
    /// # Panics
    ///
    /// If `op` should panic, that panic will be propagated.
    ///
    /// ## Using `install()`
    ///
    /// ```rust
    ///    # use rayon_core as rayon;
    ///    fn main() {
    ///         let pool = rayon::ThreadPoolBuilder::new().num_threads(8).build().unwrap();
    ///         let n = pool.install(|| fib(20));
    ///         println!("{}", n);
    ///    }
    ///
    ///    fn fib(n: usize) -> usize {
    ///         if n == 0 || n == 1 {
    ///             return n;
    ///         }
    ///         let (a, b) = rayon::join(|| fib(n - 1), || fib(n - 2)); // runs inside of `pool`
    ///         return a + b;
    ///     }
    /// ```
    pub fn install<OP, R>(&self, op: OP) -> R
    where
        OP: FnOnce() -> R + Send,
        R: Send,
    {
        self.registry.in_worker(|_, _| op())
    }

    /// Returns the (current) number of threads in the thread pool.
    ///
    /// # Future compatibility note
    ///
    /// Note that unless this thread-pool was created with a
    /// [`ThreadPoolBuilder`] that specifies the number of threads,
    /// then this number may vary over time in future versions (see [the
    /// `num_threads()` method for details][snt]).
    ///
    /// [snt]: struct.ThreadPoolBuilder.html#method.num_threads
    /// [`ThreadPoolBuilder`]: struct.ThreadPoolBuilder.html
    #[inline]
    pub fn current_num_threads(&self) -> usize {
        self.registry.num_threads()
    }

    /// If called from a Rayon worker thread in this thread-pool,
    /// returns the index of that thread; if not called from a Rayon
    /// thread, or called from a Rayon thread that belongs to a
    /// different thread-pool, returns `None`.
    ///
    /// The index for a given thread will not change over the thread's
    /// lifetime. However, multiple threads may share the same index if
    /// they are in distinct thread-pools.
    ///
    /// # Future compatibility note
    ///
    /// Currently, every thread-pool (including the global
    /// thread-pool) has a fixed number of threads, but this may
    /// change in future Rayon versions (see [the `num_threads()` method
    /// for details][snt]). In that case, the index for a
    /// thread would not change during its lifetime, but thread
    /// indices may wind up being reused if threads are terminated and
    /// restarted.
    ///
    /// [snt]: struct.ThreadPoolBuilder.html#method.num_threads
    #[inline]
    pub fn current_thread_index(&self) -> Option<usize> {
        unsafe {
            let curr = WorkerThread::current();
            if curr.is_null() {
                None
            } else if (*curr).registry().id() != self.registry.id() {
                None
            } else {
                Some((*curr).index())
            }
        }
    }

    /// Returns true if the current worker thread currently has "local
    /// tasks" pending. This can be useful as part of a heuristic for
    /// deciding whether to spawn a new task or execute code on the
    /// current thread, particularly in breadth-first
    /// schedulers. However, keep in mind that this is an inherently
    /// racy check, as other worker threads may be actively "stealing"
    /// tasks from our local deque.
    ///
    /// **Background:** Rayon's uses a [work-stealing] scheduler. The
    /// key idea is that each thread has its own [deque] of
    /// tasks. Whenever a new task is spawned -- whether through
    /// `join()`, `Scope::spawn()`, or some other means -- that new
    /// task is pushed onto the thread's *local* deque. Worker threads
    /// have a preference for executing their own tasks; if however
    /// they run out of tasks, they will go try to "steal" tasks from
    /// other threads. This function therefore has an inherent race
    /// with other active worker threads, which may be removing items
    /// from the local deque.
    ///
    /// [work-stealing]: https://en.wikipedia.org/wiki/Work_stealing
    /// [deque]: https://en.wikipedia.org/wiki/Double-ended_queue
    #[inline]
    pub fn current_thread_has_pending_tasks(&self) -> Option<bool> {
        unsafe {
            let curr = WorkerThread::current();
            if curr.is_null() {
                None
            } else if (*curr).registry().id() != self.registry.id() {
                None
            } else {
                Some(!(*curr).local_deque_is_empty())
            }
        }
    }

    /// Execute `oper_a` and `oper_b` in the thread-pool and return
    /// the results. Equivalent to `self.install(|| join(oper_a,
    /// oper_b))`.
    pub fn join<A, B, RA, RB>(&self, oper_a: A, oper_b: B) -> (RA, RB)
    where
        A: FnOnce() -> RA + Send,
        B: FnOnce() -> RB + Send,
        RA: Send,
        RB: Send,
    {
        self.install(|| join(oper_a, oper_b))
    }

    /// Creates a scope that executes within this thread-pool.
    /// Equivalent to `self.install(|| scope(...))`.
    ///
    /// See also: [the `scope()` function][scope].
    ///
    /// [scope]: fn.scope.html
    pub fn scope<'scope, OP, R>(&self, op: OP) -> R
    where
        OP: for<'s> FnOnce(&'s Scope<'scope>) -> R + 'scope + Send,
        R: Send,
    {
        self.install(|| scope(op))
    }

    /// Creates a scope that executes within this thread-pool.
    /// Spawns from the same thread are prioritized in relative FIFO order.
    /// Equivalent to `self.install(|| scope_fifo(...))`.
    ///
    /// See also: [the `scope_fifo()` function][scope_fifo].
    ///
    /// [scope_fifo]: fn.scope_fifo.html
    pub fn scope_fifo<'scope, OP, R>(&self, op: OP) -> R
    where
        OP: for<'s> FnOnce(&'s ScopeFifo<'scope>) -> R + 'scope + Send,
        R: Send,
    {
        self.install(|| scope_fifo(op))
    }

    /// Spawns an asynchronous task in this thread-pool. This task will
    /// run in the implicit, global scope, which means that it may outlast
    /// the current stack frame -- therefore, it cannot capture any references
    /// onto the stack (you will likely need a `move` closure).
    ///
    /// See also: [the `spawn()` function defined on scopes][spawn].
    ///
    /// [spawn]: struct.Scope.html#method.spawn
    pub fn spawn<OP>(&self, op: OP)
    where
        OP: FnOnce() + Send + 'static,
    {
        // We assert that `self.registry` has not terminated.
        unsafe { spawn::spawn_in(op, &self.registry) }
    }

    /// Spawns an asynchronous task in this thread-pool. This task will
    /// run in the implicit, global scope, which means that it may outlast
    /// the current stack frame -- therefore, it cannot capture any references
    /// onto the stack (you will likely need a `move` closure).
    ///
    /// See also: [the `spawn_fifo()` function defined on scopes][spawn_fifo].
    ///
    /// [spawn_fifo]: struct.ScopeFifo.html#method.spawn_fifo
    pub fn spawn_fifo<OP>(&self, op: OP)
    where
        OP: FnOnce() + Send + 'static,
    {
        // We assert that `self.registry` has not terminated.
        unsafe { spawn::spawn_fifo_in(op, &self.registry) }
    }
}

impl Drop for ThreadPool {
    fn drop(&mut self) {
        self.registry.terminate();
    }
}

impl fmt::Debug for ThreadPool {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        fmt.debug_struct("ThreadPool")
            .field("num_threads", &self.current_num_threads())
            .field("id", &self.registry.id())
            .finish()
    }
}

/// If called from a Rayon worker thread, returns the index of that
/// thread within its current pool; if not called from a Rayon thread,
/// returns `None`.
///
/// The index for a given thread will not change over the thread's
/// lifetime. However, multiple threads may share the same index if
/// they are in distinct thread-pools.
///
/// See also: [the `ThreadPool::current_thread_index()` method].
///
/// [m]: struct.ThreadPool.html#method.current_thread_index
///
/// # Future compatibility note
///
/// Currently, every thread-pool (including the global
/// thread-pool) has a fixed number of threads, but this may
/// change in future Rayon versions (see [the `num_threads()` method
/// for details][snt]). In that case, the index for a
/// thread would not change during its lifetime, but thread
/// indices may wind up being reused if threads are terminated and
/// restarted.
///
/// [snt]: struct.ThreadPoolBuilder.html#method.num_threads
#[inline]
pub fn current_thread_index() -> Option<usize> {
    unsafe {
        let curr = WorkerThread::current();
        if curr.is_null() {
            None
        } else {
            Some((*curr).index())
        }
    }
}

/// If called from a Rayon worker thread, indicates whether that
/// thread's local deque still has pending tasks. Otherwise, returns
/// `None`. For more information, see [the
/// `ThreadPool::current_thread_has_pending_tasks()` method][m].
///
/// [m]: struct.ThreadPool.html#method.current_thread_has_pending_tasks
#[inline]
pub fn current_thread_has_pending_tasks() -> Option<bool> {
    unsafe {
        let curr = WorkerThread::current();
        if curr.is_null() {
            None
        } else {
            Some(!(*curr).local_deque_is_empty())
        }
    }
}
<|endoftext|>


<commit_before>use std::{iter, fs, path};

use image::ImageFormat;
use criterion::{Criterion, criterion_group, criterion_main};

#[derive(Clone, Copy)]
struct BenchDef {
    dir: &'static [&'static str],
    files: &'static [&'static str],
    format: ImageFormat,
}

fn load_all(c: &mut Criterion) {
    const BENCH_DEFS: &'static [BenchDef] = &[
        BenchDef {
            dir: &["bmp", "images"],
            files: &[
                "Core_1_Bit.bmp",
                "Core_4_Bit.bmp",
                "Core_8_Bit.bmp",
                "rgb16.bmp",
                "rgb24.bmp",
                "rgb32.bmp",
                "pal4rle.bmp",
                "pal8rle.bmp",
                "rgb16-565.bmp",
                "rgb32bf.bmp",
            ],
            format: ImageFormat::Bmp,
        },
    ];

    for bench in BENCH_DEFS {
        bench_load(c, bench);
    }
}

criterion_group!(benches, load_all);
criterion_main!(benches);

fn bench_load(c: &mut Criterion, def: &BenchDef) {
    let group_name = format!("load-{:?}", def.format);
    let mut group = c.benchmark_group(&group_name);
    let paths = IMAGE_DIR.iter().chain(def.dir);

    for file_name in def.files {
        let path: path::PathBuf = paths.clone().chain(iter::once(file_name)).collect();
        let buf = fs::read(path).unwrap();
        group.bench_function(file_name.to_owned(), |b| b.iter(|| {
            image::load_from_memory_with_format(&buf, def.format).unwrap();
        }));
    }
}

const IMAGE_DIR: [&'static str; 3] = [".", "tests", "images"];

<commit_msg>Add benchmarks based on test images<commit_after>use std::{iter, fs, path};

use image::ImageFormat;
use criterion::{Criterion, criterion_group, criterion_main};

#[derive(Clone, Copy)]
struct BenchDef {
    dir: &'static [&'static str],
    files: &'static [&'static str],
    format: ImageFormat,
}

fn load_all(c: &mut Criterion) {
    const BENCH_DEFS: &'static [BenchDef] = &[
        BenchDef {
            dir: &["bmp", "images"],
            files: &[
                "Core_1_Bit.bmp",
                "Core_4_Bit.bmp",
                "Core_8_Bit.bmp",
                "rgb16.bmp",
                "rgb24.bmp",
                "rgb32.bmp",
                "pal4rle.bmp",
                "pal8rle.bmp",
                "rgb16-565.bmp",
                "rgb32bf.bmp",
            ],
            format: ImageFormat::Bmp,
        },
        BenchDef {
            dir: &["gif", "simple"],
            files: &[
                "alpha_gif_a.gif",
                "sample_1.gif",
            ],
            format: ImageFormat::Gif,
        },
        BenchDef {
            dir: &["hdr", "images"],
            files: &[
                "image1.hdr",
                "rgbr4x4.hdr",
            ],
            format: ImageFormat::Hdr,
        },
        BenchDef {
            dir: &["ico", "images"],
            files: &[
                "bmp-24bpp-mask.ico",
                "bmp-32bpp-alpha.ico",
                "png-32bpp-alpha.ico",
                "smile.ico",
            ],
            format: ImageFormat::Ico,
        },
        BenchDef {
            dir: &["jpg", "progressive"],
            files: &[
                "3.jpg",
                "cat.jpg",
                "test.jpg",
            ],
            format: ImageFormat::Jpeg,
        },
        // TODO: pnm
        // TODO: png
        BenchDef {
            dir: &["tga", "testsuite"],
            files: &[
                "cbw8.tga",
                "ctc24.tga",
                "ubw8.tga",
                "utc24.tga",
            ],
            format: ImageFormat::Tga,
        },
        BenchDef {
            dir: &["tiff", "testsuite"],
            files: &[
                "hpredict.tiff",
                "hpredict_packbits.tiff",
                "mandrill.tiff",
                "rgb-3c-16b.tiff",
            ],
            format: ImageFormat::Tiff,
        },
        BenchDef {
            dir: &["webp", "images"],
            files: &[
                "simple-gray.webp",
                "simple-rgb.webp",
                "vp8x-gray.webp",
                "vp8x-rgb.webp",
            ],
            format: ImageFormat::WebP,
        },
    ];

    for bench in BENCH_DEFS {
        bench_load(c, bench);
    }
}

criterion_group!(benches, load_all);
criterion_main!(benches);

fn bench_load(c: &mut Criterion, def: &BenchDef) {
    let group_name = format!("load-{:?}", def.format);
    let mut group = c.benchmark_group(&group_name);
    let paths = IMAGE_DIR.iter().chain(def.dir);

    for file_name in def.files {
        let path: path::PathBuf = paths.clone().chain(iter::once(file_name)).collect();
        let buf = fs::read(path).unwrap();
        group.bench_function(file_name.to_owned(), |b| b.iter(|| {
            image::load_from_memory_with_format(&buf, def.format).unwrap();
        }));
    }
}

const IMAGE_DIR: [&'static str; 3] = [".", "tests", "images"];

<|endoftext|>


<commit_before>// Copyright 2021 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

//! vulkano_gralloc: Implements swapchain allocation and memory mapping
//! using Vulkano.
//!
//! External code found at https://github.com/vulkano-rs/vulkano.

#![cfg(feature = "vulkano")]

use std::collections::BTreeMap as Map;
use std::convert::TryInto;
use std::iter::Empty;
use std::sync::Arc;

use base::MappedRegion;

use crate::rutabaga_gralloc::gralloc::{Gralloc, ImageAllocationInfo, ImageMemoryRequirements};
use crate::rutabaga_utils::*;

use vulkano::device::physical::{MemoryType, PhysicalDevice, PhysicalDeviceType};
use vulkano::device::{Device, DeviceCreationError, DeviceExtensions};
use vulkano::image::{
    sys, ImageCreateFlags, ImageCreationError, ImageDimensions, ImageUsage, SampleCount,
};

use vulkano::instance::{Instance, InstanceCreationError, InstanceExtensions, Version};

use vulkano::memory::{
    DedicatedAlloc, DeviceMemoryAllocError, DeviceMemoryBuilder, DeviceMemoryMapping,
    ExternalMemoryHandleType, MemoryRequirements,
};

use vulkano::memory::pool::AllocFromRequirementsFilter;
use vulkano::sync::Sharing;

/// A gralloc implementation capable of allocation `VkDeviceMemory`.
pub struct VulkanoGralloc {
    devices: Map<PhysicalDeviceType, Arc<Device>>,
    has_integrated_gpu: bool,
}

struct VulkanoMapping {
    mapping: DeviceMemoryMapping,
    size: usize,
}

impl VulkanoMapping {
    pub fn new(mapping: DeviceMemoryMapping, size: usize) -> VulkanoMapping {
        VulkanoMapping { mapping, size }
    }
}

unsafe impl MappedRegion for VulkanoMapping {
    /// Used for passing this region for hypervisor memory mappings.  We trust crosvm to use this
    /// safely.
    fn as_ptr(&self) -> *mut u8 {
        unsafe { self.mapping.as_ptr() }
    }

    /// Returns the size of the memory region in bytes.
    fn size(&self) -> usize {
        self.size
    }
}

impl VulkanoGralloc {
    /// Returns a new `VulkanGralloc' instance upon success.
    pub fn init() -> RutabagaResult<Box<dyn Gralloc>> {
        // Initialization copied from triangle.rs in Vulkano.  Look there for a more detailed
        // explanation of VK initialization.
        let instance = Instance::new(None, Version::V1_1, &InstanceExtensions::none(), None)?;

        let mut devices: Map<PhysicalDeviceType, Arc<Device>> = Default::default();
        let mut has_integrated_gpu = false;

        for physical in PhysicalDevice::enumerate(&instance) {
            let queue_family = physical
                .queue_families()
                .find(|&q| {
                    // We take the first queue family that supports graphics.
                    q.supports_graphics()
                })
                .ok_or(RutabagaError::SpecViolation(
                    "need graphics queue family to proceed",
                ))?;

            let supported_extensions = physical.supported_extensions();

            let desired_extensions = DeviceExtensions {
                khr_dedicated_allocation: true,
                khr_get_memory_requirements2: true,
                khr_external_memory: true,
                khr_external_memory_fd: true,
                ext_external_memory_dma_buf: true,
                ..DeviceExtensions::none()
            };

            let intersection = supported_extensions.intersection(&desired_extensions);

            let (device, mut _queues) = Device::new(
                physical,
                physical.supported_features(),
                &intersection,
                [(queue_family, 0.5)].iter().cloned(),
            )?;

            let device_type = device.physical_device().properties().device_type;
            if device_type == PhysicalDeviceType::IntegratedGpu {
                has_integrated_gpu = true
            }

            // If we have two devices of the same type (two integrated GPUs), the old value is
            // dropped.  Vulkano is verbose enough such that a keener selection algorithm may
            // be used, but the need for such complexity does not seem to exist now.
            devices.insert(device_type, device);
        }

        Ok(Box::new(VulkanoGralloc {
            devices,
            has_integrated_gpu,
        }))
    }

    // This function is used safely in this module because gralloc does not:
    //
    //  (1) bind images to any memory.
    //  (2) transition the layout of images.
    //  (3) transfer ownership of images between queues.
    //
    // In addition, we trust Vulkano to validate image parameters are within the Vulkan spec.
    unsafe fn create_image(
        &mut self,
        info: ImageAllocationInfo,
    ) -> RutabagaResult<(sys::UnsafeImage, MemoryRequirements)> {
        let device = if self.has_integrated_gpu {
            self.devices
                .get(&PhysicalDeviceType::IntegratedGpu)
                .ok_or(RutabagaError::InvalidGrallocGpuType)?
        } else {
            self.devices
                .get(&PhysicalDeviceType::DiscreteGpu)
                .ok_or(RutabagaError::InvalidGrallocGpuType)?
        };

        let usage = match info.flags.uses_rendering() {
            true => ImageUsage {
                color_attachment: true,
                ..ImageUsage::none()
            },
            false => ImageUsage {
                sampled: true,
                ..ImageUsage::none()
            },
        };

        // Reasonable bounds on image width.
        if info.width == 0 || info.width > 4096 {
            return Err(RutabagaError::InvalidGrallocDimensions);
        }

        // Reasonable bounds on image height.
        if info.height == 0 || info.height > 4096 {
            return Err(RutabagaError::InvalidGrallocDimensions);
        }

        let vulkan_format = info.drm_format.vulkan_format()?;
        let (unsafe_image, memory_requirements) = sys::UnsafeImage::new(
            device.clone(),
            usage,
            vulkan_format,
            ImageCreateFlags::none(),
            ImageDimensions::Dim2d {
                width: info.width,
                height: info.height,
                array_layers: 1,
            },
            SampleCount::Sample1,
            1, /* mipmap count */
            Sharing::Exclusive::<Empty<_>>,
            true,  /* linear images only currently */
            false, /* not preinitialized */
        )?;

        Ok((unsafe_image, memory_requirements))
    }
}

impl Gralloc for VulkanoGralloc {
    fn supports_external_gpu_memory(&self) -> bool {
        for device in self.devices.values() {
            if !device.enabled_extensions().khr_external_memory {
                return false;
            }
        }

        true
    }

    fn supports_dmabuf(&self) -> bool {
        for device in self.devices.values() {
            if !device.enabled_extensions().ext_external_memory_dma_buf {
                return false;
            }
        }

        true
    }

    fn get_image_memory_requirements(
        &mut self,
        info: ImageAllocationInfo,
    ) -> RutabagaResult<ImageMemoryRequirements> {
        let mut reqs: ImageMemoryRequirements = Default::default();

        let (unsafe_image, memory_requirements) = unsafe { self.create_image(info)? };

        let device = if self.has_integrated_gpu {
            self.devices
                .get(&PhysicalDeviceType::IntegratedGpu)
                .ok_or(RutabagaError::InvalidGrallocGpuType)?
        } else {
            self.devices
                .get(&PhysicalDeviceType::DiscreteGpu)
                .ok_or(RutabagaError::InvalidGrallocGpuType)?
        };

        let planar_layout = info.drm_format.planar_layout()?;

        // Safe because we created the image with the linear bit set and verified the format is
        // not a depth or stencil format.  We are also using the correct image aspect.  Vulkano
        // will panic if we are not.
        for plane in 0..planar_layout.num_planes {
            let aspect = info.drm_format.vulkan_image_aspect(plane)?;
            let layout = unsafe { unsafe_image.multiplane_color_layout(aspect) };
            reqs.strides[plane] = layout.row_pitch as u32;
            reqs.offsets[plane] = layout.offset as u32;
        }

        let need_visible = info.flags.host_visible();
        let want_cached = info.flags.host_cached();

        let memory_type = {
            let filter = |current_type: MemoryType| {
                if need_visible && !current_type.is_host_visible() {
                    return AllocFromRequirementsFilter::Forbidden;
                }

                if !need_visible && current_type.is_device_local() {
                    return AllocFromRequirementsFilter::Preferred;
                }

                if need_visible && want_cached && current_type.is_host_cached() {
                    return AllocFromRequirementsFilter::Preferred;
                }

                if need_visible
                    && !want_cached
                    && current_type.is_host_coherent()
                    && !current_type.is_host_cached()
                {
                    return AllocFromRequirementsFilter::Preferred;
                }

                AllocFromRequirementsFilter::Allowed
            };

            let first_loop = device
                .physical_device()
                .memory_types()
                .map(|t| (t, AllocFromRequirementsFilter::Preferred));
            let second_loop = device
                .physical_device()
                .memory_types()
                .map(|t| (t, AllocFromRequirementsFilter::Allowed));
            first_loop
                .chain(second_loop)
                .filter(|&(t, _)| (memory_requirements.memory_type_bits & (1 << t.id())) != 0)
                .find(|&(t, rq)| filter(t) == rq)
                .ok_or(RutabagaError::SpecViolation(
                    "unable to find required memory type",
                ))?
                .0
        };

        reqs.info = info;
        reqs.size = memory_requirements.size as u64;

        if memory_type.is_host_visible() {
            if memory_type.is_host_cached() {
                reqs.map_info = RUTABAGA_MAP_CACHE_CACHED;
            } else if memory_type.is_host_coherent() {
                reqs.map_info = RUTABAGA_MAP_CACHE_WC;
            }
        }

        reqs.vulkan_info = Some(VulkanInfo {
            memory_idx: memory_type.id() as u32,
            physical_device_idx: device.physical_device().index() as u32,
        });

        Ok(reqs)
    }

    fn allocate_memory(&mut self, reqs: ImageMemoryRequirements) -> RutabagaResult<RutabagaHandle> {
        let (unsafe_image, memory_requirements) = unsafe { self.create_image(reqs.info)? };

        let vulkan_info = reqs.vulkan_info.ok_or(RutabagaError::InvalidVulkanInfo)?;

        let device = if self.has_integrated_gpu {
            self.devices
                .get(&PhysicalDeviceType::IntegratedGpu)
                .ok_or(RutabagaError::InvalidGrallocGpuType)?
        } else {
            self.devices
                .get(&PhysicalDeviceType::DiscreteGpu)
                .ok_or(RutabagaError::InvalidGrallocGpuType)?
        };

        let memory_type = device
            .physical_device()
            .memory_type_by_id(vulkan_info.memory_idx)
            .ok_or(RutabagaError::InvalidVulkanInfo)?;

        let (handle_type, rutabaga_type) =
            match device.enabled_extensions().ext_external_memory_dma_buf {
                true => (
                    ExternalMemoryHandleType {
                        dma_buf: true,
                        ..ExternalMemoryHandleType::none()
                    },
                    RUTABAGA_MEM_HANDLE_TYPE_DMABUF,
                ),
                false => (
                    ExternalMemoryHandleType {
                        opaque_fd: true,
                        ..ExternalMemoryHandleType::none()
                    },
                    RUTABAGA_MEM_HANDLE_TYPE_OPAQUE_FD,
                ),
            };

        let dedicated = match device.enabled_extensions().khr_dedicated_allocation {
            true => {
                if memory_requirements.prefer_dedicated {
                    DedicatedAlloc::Image(&unsafe_image)
                } else {
                    DedicatedAlloc::None
                }
            }
            false => DedicatedAlloc::None,
        };

        let device_memory = DeviceMemoryBuilder::new(device.clone(), memory_type.id(), reqs.size)
            .dedicated_info(dedicated)
            .export_info(handle_type)
            .build()?;

        let descriptor = device_memory.export_fd(handle_type)?.into();

        Ok(RutabagaHandle {
            os_handle: descriptor,
            handle_type: rutabaga_type,
        })
    }

    /// Implementations must map the memory associated with the `resource_id` upon success.
    fn import_and_map(
        &mut self,
        handle: RutabagaHandle,
        vulkan_info: VulkanInfo,
        size: u64,
    ) -> RutabagaResult<Box<dyn MappedRegion>> {
        let device = self
            .devices
            .values()
            .find(|device| {
                device.physical_device().index() as u32 == vulkan_info.physical_device_idx
            })
            .ok_or(RutabagaError::InvalidVulkanInfo)?;

        let handle_type = match handle.handle_type {
            RUTABAGA_MEM_HANDLE_TYPE_DMABUF => ExternalMemoryHandleType {
                dma_buf: true,
                ..ExternalMemoryHandleType::none()
            },
            RUTABAGA_MEM_HANDLE_TYPE_OPAQUE_FD => ExternalMemoryHandleType {
                opaque_fd: true,
                ..ExternalMemoryHandleType::none()
            },
            _ => return Err(RutabagaError::InvalidRutabagaHandle),
        };

        let device_memory = DeviceMemoryBuilder::new(device.clone(), vulkan_info.memory_idx, size)
            .import_info(handle.os_handle.into(), handle_type)
            .build()?;
        let mapping = DeviceMemoryMapping::new(device.clone(), device_memory.clone(), 0, size, 0)?;

        Ok(Box::new(VulkanoMapping::new(mapping, size.try_into()?)))
    }
}

// Vulkano should really define an universal type that wraps all these errors, say
// "VulkanoError(e)".
impl From<InstanceCreationError> for RutabagaError {
    fn from(e: InstanceCreationError) -> RutabagaError {
        RutabagaError::VkInstanceCreationError(e)
    }
}

impl From<ImageCreationError> for RutabagaError {
    fn from(e: ImageCreationError) -> RutabagaError {
        RutabagaError::VkImageCreationError(e)
    }
}

impl From<DeviceCreationError> for RutabagaError {
    fn from(e: DeviceCreationError) -> RutabagaError {
        RutabagaError::VkDeviceCreationError(e)
    }
}

impl From<DeviceMemoryAllocError> for RutabagaError {
    fn from(e: DeviceMemoryAllocError) -> RutabagaError {
        RutabagaError::VkDeviceMemoryAllocError(e)
    }
}
<commit_msg>rutabaga_gfx: rutabaga_gralloc: Request instance extensions<commit_after>// Copyright 2021 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

//! vulkano_gralloc: Implements swapchain allocation and memory mapping
//! using Vulkano.
//!
//! External code found at https://github.com/vulkano-rs/vulkano.

#![cfg(feature = "vulkano")]

use std::collections::BTreeMap as Map;
use std::convert::TryInto;
use std::iter::Empty;
use std::sync::Arc;

use base::MappedRegion;

use crate::rutabaga_gralloc::gralloc::{Gralloc, ImageAllocationInfo, ImageMemoryRequirements};
use crate::rutabaga_utils::*;

use vulkano::device::physical::{MemoryType, PhysicalDevice, PhysicalDeviceType};
use vulkano::device::{Device, DeviceCreationError, DeviceExtensions};
use vulkano::image::{
    sys, ImageCreateFlags, ImageCreationError, ImageDimensions, ImageUsage, SampleCount,
};

use vulkano::instance::{Instance, InstanceCreationError, InstanceExtensions, Version};

use vulkano::memory::{
    DedicatedAlloc, DeviceMemoryAllocError, DeviceMemoryBuilder, DeviceMemoryMapping,
    ExternalMemoryHandleType, MemoryRequirements,
};

use vulkano::memory::pool::AllocFromRequirementsFilter;
use vulkano::sync::Sharing;

/// A gralloc implementation capable of allocation `VkDeviceMemory`.
pub struct VulkanoGralloc {
    devices: Map<PhysicalDeviceType, Arc<Device>>,
    has_integrated_gpu: bool,
}

struct VulkanoMapping {
    mapping: DeviceMemoryMapping,
    size: usize,
}

impl VulkanoMapping {
    pub fn new(mapping: DeviceMemoryMapping, size: usize) -> VulkanoMapping {
        VulkanoMapping { mapping, size }
    }
}

unsafe impl MappedRegion for VulkanoMapping {
    /// Used for passing this region for hypervisor memory mappings.  We trust crosvm to use this
    /// safely.
    fn as_ptr(&self) -> *mut u8 {
        unsafe { self.mapping.as_ptr() }
    }

    /// Returns the size of the memory region in bytes.
    fn size(&self) -> usize {
        self.size
    }
}

impl VulkanoGralloc {
    /// Returns a new `VulkanGralloc' instance upon success.
    pub fn init() -> RutabagaResult<Box<dyn Gralloc>> {
        // Initialization copied from triangle.rs in Vulkano.  Look there for a more detailed
        // explanation of VK initialization.
        let instance_extensions = InstanceExtensions {
            khr_external_memory_capabilities: true,
            khr_get_physical_device_properties2: true,
            ..InstanceExtensions::none()
        };
        let instance = Instance::new(None, Version::V1_1, &instance_extensions, None)?;

        let mut devices: Map<PhysicalDeviceType, Arc<Device>> = Default::default();
        let mut has_integrated_gpu = false;

        for physical in PhysicalDevice::enumerate(&instance) {
            let queue_family = physical
                .queue_families()
                .find(|&q| {
                    // We take the first queue family that supports graphics.
                    q.supports_graphics()
                })
                .ok_or(RutabagaError::SpecViolation(
                    "need graphics queue family to proceed",
                ))?;

            let supported_extensions = physical.supported_extensions();

            let desired_extensions = DeviceExtensions {
                khr_dedicated_allocation: true,
                khr_get_memory_requirements2: true,
                khr_external_memory: true,
                khr_external_memory_fd: true,
                ext_external_memory_dma_buf: true,
                ..DeviceExtensions::none()
            };

            let intersection = supported_extensions.intersection(&desired_extensions);

            let (device, mut _queues) = Device::new(
                physical,
                physical.supported_features(),
                &intersection,
                [(queue_family, 0.5)].iter().cloned(),
            )?;

            let device_type = device.physical_device().properties().device_type;
            if device_type == PhysicalDeviceType::IntegratedGpu {
                has_integrated_gpu = true
            }

            // If we have two devices of the same type (two integrated GPUs), the old value is
            // dropped.  Vulkano is verbose enough such that a keener selection algorithm may
            // be used, but the need for such complexity does not seem to exist now.
            devices.insert(device_type, device);
        }

        Ok(Box::new(VulkanoGralloc {
            devices,
            has_integrated_gpu,
        }))
    }

    // This function is used safely in this module because gralloc does not:
    //
    //  (1) bind images to any memory.
    //  (2) transition the layout of images.
    //  (3) transfer ownership of images between queues.
    //
    // In addition, we trust Vulkano to validate image parameters are within the Vulkan spec.
    unsafe fn create_image(
        &mut self,
        info: ImageAllocationInfo,
    ) -> RutabagaResult<(sys::UnsafeImage, MemoryRequirements)> {
        let device = if self.has_integrated_gpu {
            self.devices
                .get(&PhysicalDeviceType::IntegratedGpu)
                .ok_or(RutabagaError::InvalidGrallocGpuType)?
        } else {
            self.devices
                .get(&PhysicalDeviceType::DiscreteGpu)
                .ok_or(RutabagaError::InvalidGrallocGpuType)?
        };

        let usage = match info.flags.uses_rendering() {
            true => ImageUsage {
                color_attachment: true,
                ..ImageUsage::none()
            },
            false => ImageUsage {
                sampled: true,
                ..ImageUsage::none()
            },
        };

        // Reasonable bounds on image width.
        if info.width == 0 || info.width > 4096 {
            return Err(RutabagaError::InvalidGrallocDimensions);
        }

        // Reasonable bounds on image height.
        if info.height == 0 || info.height > 4096 {
            return Err(RutabagaError::InvalidGrallocDimensions);
        }

        let vulkan_format = info.drm_format.vulkan_format()?;
        let (unsafe_image, memory_requirements) = sys::UnsafeImage::new(
            device.clone(),
            usage,
            vulkan_format,
            ImageCreateFlags::none(),
            ImageDimensions::Dim2d {
                width: info.width,
                height: info.height,
                array_layers: 1,
            },
            SampleCount::Sample1,
            1, /* mipmap count */
            Sharing::Exclusive::<Empty<_>>,
            true,  /* linear images only currently */
            false, /* not preinitialized */
        )?;

        Ok((unsafe_image, memory_requirements))
    }
}

impl Gralloc for VulkanoGralloc {
    fn supports_external_gpu_memory(&self) -> bool {
        for device in self.devices.values() {
            if !device.enabled_extensions().khr_external_memory {
                return false;
            }
        }

        true
    }

    fn supports_dmabuf(&self) -> bool {
        for device in self.devices.values() {
            if !device.enabled_extensions().ext_external_memory_dma_buf {
                return false;
            }
        }

        true
    }

    fn get_image_memory_requirements(
        &mut self,
        info: ImageAllocationInfo,
    ) -> RutabagaResult<ImageMemoryRequirements> {
        let mut reqs: ImageMemoryRequirements = Default::default();

        let (unsafe_image, memory_requirements) = unsafe { self.create_image(info)? };

        let device = if self.has_integrated_gpu {
            self.devices
                .get(&PhysicalDeviceType::IntegratedGpu)
                .ok_or(RutabagaError::InvalidGrallocGpuType)?
        } else {
            self.devices
                .get(&PhysicalDeviceType::DiscreteGpu)
                .ok_or(RutabagaError::InvalidGrallocGpuType)?
        };

        let planar_layout = info.drm_format.planar_layout()?;

        // Safe because we created the image with the linear bit set and verified the format is
        // not a depth or stencil format.  We are also using the correct image aspect.  Vulkano
        // will panic if we are not.
        for plane in 0..planar_layout.num_planes {
            let aspect = info.drm_format.vulkan_image_aspect(plane)?;
            let layout = unsafe { unsafe_image.multiplane_color_layout(aspect) };
            reqs.strides[plane] = layout.row_pitch as u32;
            reqs.offsets[plane] = layout.offset as u32;
        }

        let need_visible = info.flags.host_visible();
        let want_cached = info.flags.host_cached();

        let memory_type = {
            let filter = |current_type: MemoryType| {
                if need_visible && !current_type.is_host_visible() {
                    return AllocFromRequirementsFilter::Forbidden;
                }

                if !need_visible && current_type.is_device_local() {
                    return AllocFromRequirementsFilter::Preferred;
                }

                if need_visible && want_cached && current_type.is_host_cached() {
                    return AllocFromRequirementsFilter::Preferred;
                }

                if need_visible
                    && !want_cached
                    && current_type.is_host_coherent()
                    && !current_type.is_host_cached()
                {
                    return AllocFromRequirementsFilter::Preferred;
                }

                AllocFromRequirementsFilter::Allowed
            };

            let first_loop = device
                .physical_device()
                .memory_types()
                .map(|t| (t, AllocFromRequirementsFilter::Preferred));
            let second_loop = device
                .physical_device()
                .memory_types()
                .map(|t| (t, AllocFromRequirementsFilter::Allowed));
            first_loop
                .chain(second_loop)
                .filter(|&(t, _)| (memory_requirements.memory_type_bits & (1 << t.id())) != 0)
                .find(|&(t, rq)| filter(t) == rq)
                .ok_or(RutabagaError::SpecViolation(
                    "unable to find required memory type",
                ))?
                .0
        };

        reqs.info = info;
        reqs.size = memory_requirements.size as u64;

        if memory_type.is_host_visible() {
            if memory_type.is_host_cached() {
                reqs.map_info = RUTABAGA_MAP_CACHE_CACHED;
            } else if memory_type.is_host_coherent() {
                reqs.map_info = RUTABAGA_MAP_CACHE_WC;
            }
        }

        reqs.vulkan_info = Some(VulkanInfo {
            memory_idx: memory_type.id() as u32,
            physical_device_idx: device.physical_device().index() as u32,
        });

        Ok(reqs)
    }

    fn allocate_memory(&mut self, reqs: ImageMemoryRequirements) -> RutabagaResult<RutabagaHandle> {
        let (unsafe_image, memory_requirements) = unsafe { self.create_image(reqs.info)? };

        let vulkan_info = reqs.vulkan_info.ok_or(RutabagaError::InvalidVulkanInfo)?;

        let device = if self.has_integrated_gpu {
            self.devices
                .get(&PhysicalDeviceType::IntegratedGpu)
                .ok_or(RutabagaError::InvalidGrallocGpuType)?
        } else {
            self.devices
                .get(&PhysicalDeviceType::DiscreteGpu)
                .ok_or(RutabagaError::InvalidGrallocGpuType)?
        };

        let memory_type = device
            .physical_device()
            .memory_type_by_id(vulkan_info.memory_idx)
            .ok_or(RutabagaError::InvalidVulkanInfo)?;

        let (handle_type, rutabaga_type) =
            match device.enabled_extensions().ext_external_memory_dma_buf {
                true => (
                    ExternalMemoryHandleType {
                        dma_buf: true,
                        ..ExternalMemoryHandleType::none()
                    },
                    RUTABAGA_MEM_HANDLE_TYPE_DMABUF,
                ),
                false => (
                    ExternalMemoryHandleType {
                        opaque_fd: true,
                        ..ExternalMemoryHandleType::none()
                    },
                    RUTABAGA_MEM_HANDLE_TYPE_OPAQUE_FD,
                ),
            };

        let dedicated = match device.enabled_extensions().khr_dedicated_allocation {
            true => {
                if memory_requirements.prefer_dedicated {
                    DedicatedAlloc::Image(&unsafe_image)
                } else {
                    DedicatedAlloc::None
                }
            }
            false => DedicatedAlloc::None,
        };

        let device_memory = DeviceMemoryBuilder::new(device.clone(), memory_type.id(), reqs.size)
            .dedicated_info(dedicated)
            .export_info(handle_type)
            .build()?;

        let descriptor = device_memory.export_fd(handle_type)?.into();

        Ok(RutabagaHandle {
            os_handle: descriptor,
            handle_type: rutabaga_type,
        })
    }

    /// Implementations must map the memory associated with the `resource_id` upon success.
    fn import_and_map(
        &mut self,
        handle: RutabagaHandle,
        vulkan_info: VulkanInfo,
        size: u64,
    ) -> RutabagaResult<Box<dyn MappedRegion>> {
        let device = self
            .devices
            .values()
            .find(|device| {
                device.physical_device().index() as u32 == vulkan_info.physical_device_idx
            })
            .ok_or(RutabagaError::InvalidVulkanInfo)?;

        let handle_type = match handle.handle_type {
            RUTABAGA_MEM_HANDLE_TYPE_DMABUF => ExternalMemoryHandleType {
                dma_buf: true,
                ..ExternalMemoryHandleType::none()
            },
            RUTABAGA_MEM_HANDLE_TYPE_OPAQUE_FD => ExternalMemoryHandleType {
                opaque_fd: true,
                ..ExternalMemoryHandleType::none()
            },
            _ => return Err(RutabagaError::InvalidRutabagaHandle),
        };

        let device_memory = DeviceMemoryBuilder::new(device.clone(), vulkan_info.memory_idx, size)
            .import_info(handle.os_handle.into(), handle_type)
            .build()?;
        let mapping = DeviceMemoryMapping::new(device.clone(), device_memory.clone(), 0, size, 0)?;

        Ok(Box::new(VulkanoMapping::new(mapping, size.try_into()?)))
    }
}

// Vulkano should really define an universal type that wraps all these errors, say
// "VulkanoError(e)".
impl From<InstanceCreationError> for RutabagaError {
    fn from(e: InstanceCreationError) -> RutabagaError {
        RutabagaError::VkInstanceCreationError(e)
    }
}

impl From<ImageCreationError> for RutabagaError {
    fn from(e: ImageCreationError) -> RutabagaError {
        RutabagaError::VkImageCreationError(e)
    }
}

impl From<DeviceCreationError> for RutabagaError {
    fn from(e: DeviceCreationError) -> RutabagaError {
        RutabagaError::VkDeviceCreationError(e)
    }
}

impl From<DeviceMemoryAllocError> for RutabagaError {
    fn from(e: DeviceMemoryAllocError) -> RutabagaError {
        RutabagaError::VkDeviceMemoryAllocError(e)
    }
}
<|endoftext|>


<commit_before>//! A partially ordered measure of progress at each timely dataflow location.

use std::fmt::Debug;
use std::any::Any;
use std::default::Default;
use std::fmt::Formatter;
use std::fmt::Error;

use progress::nested::product::Product;

use abomonation::Abomonation;

// TODO : Change Copy requirement to Clone;
/// A composite trait for types that serve as timestamps in timely dataflow.
pub trait Timestamp: Copy+Eq+PartialOrd+Default+Debug+Send+Any+Abomonation {
    type Summary : PathSummary<Self> + 'static;   // summarizes cumulative action of Timestamp along a path
}

// TODO : Change Copy requirement to Clone
// TODO : Change `results_in` and perhaps `followed_by` to return an `Option`, indicating no path.
// TODO : This can be important when a summary would "overflow", as we want neither to overflow,
// TODO : nor wrap around, nor saturate.
/// A summary of how a timestamp advances along a timely dataflow path.
pub trait PathSummary<T> : 'static+Copy+Eq+PartialOrd+Debug+Default {
    /// Advances a timestamp according to the timestamp actions on the path.
    fn results_in(&self, src: &T) -> T;
    /// Composes this path summary with another path summary.
    fn followed_by(&self, other: &Self) -> Self;
}

/// An empty timestamp used by the root scope.
#[derive(Copy, Clone, Hash, Eq, Ord, PartialOrd, PartialEq, Default)]
pub struct RootTimestamp;
impl Timestamp for RootTimestamp { type Summary = RootSummary; }
impl Debug for RootTimestamp {
    #[inline]
    fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
        f.write_str("Root")
    }
}

impl Abomonation for RootTimestamp { }
impl RootTimestamp {
    /// Constructs a new `Product<RootTimestamp,T>`.
    #[inline]
    pub fn new<T: Timestamp>(t: T) -> Product<RootTimestamp, T> {
        Product::new(RootTimestamp, t)
    }
}

/// An empty path summary for root timestamps.
#[derive(Copy, Clone, Eq, Ord, PartialOrd, PartialEq, Debug, Default)]
pub struct RootSummary;
impl PathSummary<RootTimestamp> for RootSummary {
    #[inline]
    fn results_in(&self, _: &RootTimestamp) -> RootTimestamp { RootTimestamp }
    #[inline]
    fn followed_by(&self, _: &RootSummary) -> RootSummary { RootSummary }
}

impl Timestamp for usize { type Summary = usize; }
impl PathSummary<usize> for usize {
    #[inline]
    fn results_in(&self, src: &usize) -> usize { *self + *src }
    #[inline]
    fn followed_by(&self, other: &usize) -> usize { *self + *other }
}

impl Timestamp for u64 { type Summary = u64; }
impl PathSummary<u64> for u64 {
    #[inline]
    fn results_in(&self, src: &u64) -> u64 { *self + *src }
    #[inline]
    fn followed_by(&self, other: &u64) -> u64 { *self + *other }
}

impl Timestamp for u32 { type Summary = u32; }
impl PathSummary<u32> for u32 {
    #[inline]
    fn results_in(&self, src: &u32) -> u32 { *self + *src }
    #[inline]
    fn followed_by(&self, other: &u32) -> u32 { *self + *other }
}

impl Timestamp for i32 { type Summary = i32; }
impl PathSummary<i32> for i32 {
    #[inline]
    fn results_in(&self, src: &i32) -> i32 { *self + *src }
    #[inline]
    fn followed_by(&self, other: &i32) -> i32 { *self + *other }
}
<commit_msg>added () as a timestamp and summary<commit_after>//! A partially ordered measure of progress at each timely dataflow location.

use std::fmt::Debug;
use std::any::Any;
use std::default::Default;
use std::fmt::Formatter;
use std::fmt::Error;

use progress::nested::product::Product;

use abomonation::Abomonation;

// TODO : Change Copy requirement to Clone;
/// A composite trait for types that serve as timestamps in timely dataflow.
pub trait Timestamp: Copy+Eq+PartialOrd+Default+Debug+Send+Any+Abomonation {
    type Summary : PathSummary<Self> + 'static;   // summarizes cumulative action of Timestamp along a path
}

// TODO : Change Copy requirement to Clone
// TODO : Change `results_in` and perhaps `followed_by` to return an `Option`, indicating no path.
// TODO : This can be important when a summary would "overflow", as we want neither to overflow,
// TODO : nor wrap around, nor saturate.
/// A summary of how a timestamp advances along a timely dataflow path.
pub trait PathSummary<T> : 'static+Copy+Eq+PartialOrd+Debug+Default {
    /// Advances a timestamp according to the timestamp actions on the path.
    fn results_in(&self, src: &T) -> T;
    /// Composes this path summary with another path summary.
    fn followed_by(&self, other: &Self) -> Self;
}

/// An empty timestamp used by the root scope.
#[derive(Copy, Clone, Hash, Eq, Ord, PartialOrd, PartialEq, Default)]
pub struct RootTimestamp;
impl Timestamp for RootTimestamp { type Summary = RootSummary; }
impl Debug for RootTimestamp {
    #[inline]
    fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
        f.write_str("Root")
    }
}

impl Abomonation for RootTimestamp { }
impl RootTimestamp {
    /// Constructs a new `Product<RootTimestamp,T>`.
    #[inline]
    pub fn new<T: Timestamp>(t: T) -> Product<RootTimestamp, T> {
        Product::new(RootTimestamp, t)
    }
}

/// An empty path summary for root timestamps.
#[derive(Copy, Clone, Eq, Ord, PartialOrd, PartialEq, Debug, Default)]
pub struct RootSummary;
impl PathSummary<RootTimestamp> for RootSummary {
    #[inline]
    fn results_in(&self, _: &RootTimestamp) -> RootTimestamp { RootTimestamp }
    #[inline]
    fn followed_by(&self, _: &RootSummary) -> RootSummary { RootSummary }
}

impl Timestamp for () { type Summary = (); }
impl PathSummary<()> for () {
    fn results_in(&self, _src: &()) -> () { () }
    fn followed_by(&self, _other: &()) -> () { () }
}

impl Timestamp for usize { type Summary = usize; }
impl PathSummary<usize> for usize {
    #[inline]
    fn results_in(&self, src: &usize) -> usize { *self + *src }
    #[inline]
    fn followed_by(&self, other: &usize) -> usize { *self + *other }
}

impl Timestamp for u64 { type Summary = u64; }
impl PathSummary<u64> for u64 {
    #[inline]
    fn results_in(&self, src: &u64) -> u64 { *self + *src }
    #[inline]
    fn followed_by(&self, other: &u64) -> u64 { *self + *other }
}

impl Timestamp for u32 { type Summary = u32; }
impl PathSummary<u32> for u32 {
    #[inline]
    fn results_in(&self, src: &u32) -> u32 { *self + *src }
    #[inline]
    fn followed_by(&self, other: &u32) -> u32 { *self + *other }
}

impl Timestamp for i32 { type Summary = i32; }
impl PathSummary<i32> for i32 {
    #[inline]
    fn results_in(&self, src: &i32) -> i32 { *self + *src }
    #[inline]
    fn followed_by(&self, other: &i32) -> i32 { *self + *other }
}
<|endoftext|>


<commit_before>#[derive(Debug)]
struct Tree {
    enter: Node,
    left: Option<Box<Tree>>,
    right: Option<Box<Tree>>,
}

//for red-black tree
#[derive(Debug)]
enum Color {
    Black,
    Red,
    White,
}

#[derive(Debug)]
struct Node {
    val: i32,
    color: Color,
}

impl Node {
    fn new(v: &i32) -> Node {
        Node {
            val: *v,
            color: Color::White,
        }
    }
}

impl Tree {
    fn new(v: &i32) -> Tree {
        Tree {
            enter: Node::new(v),
            left: None,
            right: None,
        }
    }

    fn insert(&mut self, v: &i32) {
        let target = if *v > self.enter.val {
            &mut self.right
        } else {
            &mut self.left
        };
        //println!("target is -> {:?}", target);
        match target {
            Some(next) => {
                //println!("next is -> {:?}", &next);
                next.insert(v)
            }
            None => {
                let new_node = Node::new(v);
                let new_tree = Tree {
                    enter: new_node,
                    left: None,
                    right: None,
                };
                *target = Some(Box::new(new_tree));
            }
        }
    }

    fn look_up(&mut self, v: &i32) -> Result<&mut Self, String> {
        if *v == self.enter.val {
            return Ok(self);
        } else if *v > self.enter.val {
            if let Some(_) = self.right {
                let next = self.right.as_mut().unwrap();
                return next.look_up(v);
            } else {
                Err("not find".to_string())
            }
        } else {
            if let Some(_) = self.left {
                let next = self.left.as_mut().unwrap();
                return next.look_up(v);
            } else {
                Err("not find".to_string())
            }
        }
    }

    fn look_up_while(&mut self, v: &i32) -> Result<&mut Self, String> {
        let mut this: &mut Self = self;
        loop {
            if *v == this.enter.val {
                return Ok(this);
            } else if *v > this.enter.val {
                if let None = this.right {
                    return Err("not find".to_string());
                }
                this = { this }.right.as_mut().unwrap();
            } else {
                if let None = this.left {
                    return Err("not find".to_string());
                }
                this = { this }.left.as_mut().unwrap();
            }
        }
    }
}

fn main() {
    let mut a = Tree::new(&3);
    a.insert(&2);
    a.insert(&1);

    //println!("{:?}", a);
    //println!("{:?}", a.look_up(&1));
    println!("{:?}", a.look_up_while(&1));
}
<commit_msg>switch function name<commit_after>#[derive(Debug)]
struct Tree {
    enter: Node,
    left: Option<Box<Tree>>,
    right: Option<Box<Tree>>,
}

//for red-black tree
#[derive(Debug)]
enum Color {
    Black,
    Red,
    White,
}

#[derive(Debug)]
struct Node {
    val: i32,
    color: Color,
}

impl Node {
    fn new(v: &i32) -> Node {
        Node {
            val: *v,
            color: Color::White,
        }
    }
}

impl Tree {
    fn new(v: &i32) -> Tree {
        Tree {
            enter: Node::new(v),
            left: None,
            right: None,
        }
    }

    fn insert(&mut self, v: &i32) {
        let target = if *v > self.enter.val {
            &mut self.right
        } else {
            &mut self.left
        };
        //println!("target is -> {:?}", target);
        match target {
            Some(next) => {
                //println!("next is -> {:?}", &next);
                next.insert(v)
            }
            None => {
                let new_node = Node::new(v);
                let new_tree = Tree {
                    enter: new_node,
                    left: None,
                    right: None,
                };
                *target = Some(Box::new(new_tree));
            }
        }
    }

    fn look_up_recursive(&mut self, v: &i32) -> Result<&mut Self, String> {
        if *v == self.enter.val {
            return Ok(self);
        } else if *v > self.enter.val {
            if let Some(_) = self.right {
                let next = self.right.as_mut().unwrap();
                return next.look_up(v);
            } else {
                Err("not find".to_string())
            }
        } else {
            if let Some(_) = self.left {
                let next = self.left.as_mut().unwrap();
                return next.look_up(v);
            } else {
                Err("not find".to_string())
            }
        }
    }

    fn look_up(&mut self, v: &i32) -> Result<&mut Self, String> {
        let mut this: &mut Self = self;
        loop {
            if *v == this.enter.val {
                return Ok(this);
            } else if *v > this.enter.val {
                if let None = this.right {
                    return Err("not find".to_string());
                }
                this = { this }.right.as_mut().unwrap();
            } else {
                if let None = this.left {
                    return Err("not find".to_string());
                }
                this = { this }.left.as_mut().unwrap();
            }
        }
    }

    fn left_shift(&mut self, v: &i32) {}
}

fn main() {
    let mut a = Tree::new(&3);
    a.insert(&2);
    a.insert(&1);

    //println!("{:?}", a);
    //println!("{:?}", a.look_up(&1));
    println!("{:?}", a.look_up(&1));
    println!("{:?}", a);
}
<|endoftext|>


<commit_before>// Copyright (c) 2016 The vulkano developers
// Licensed under the Apache License, Version 2.0
// <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT
// license <LICENSE-MIT or http://opensource.org/licenses/MIT>,
// at your option. All files in the project carrying such
// notice may not be copied, modified, or distributed except
// according to those terms.

use std::mem;
use std::ptr;
use std::sync::Arc;
use smallvec::SmallVec;

use check_errors;
use OomError;
use VulkanObject;
use VulkanPointers;
use vk;

use descriptor::descriptor_set::UnsafeDescriptorSetLayout;
use device::Device;

/// Low-level struct that represents the layout of the resources available to your shaders.
// TODO: push constants.
pub struct UnsafePipelineLayout {
    device: Arc<Device>,
    layout: vk::PipelineLayout,
    layouts: SmallVec<[Arc<UnsafeDescriptorSetLayout>; 16]>,
}

impl UnsafePipelineLayout {
    /// Creates a new `UnsafePipelineLayout`.
    // TODO: is this function unsafe?
    #[inline]
    pub unsafe fn new<'a, I>(device: &Arc<Device>, layouts: I)
                             -> Result<UnsafePipelineLayout, OomError>
        where I: IntoIterator<Item = &'a Arc<UnsafeDescriptorSetLayout>>
    {
        UnsafePipelineLayout::new_inner(device, layouts.into_iter().map(|e| e.clone()).collect())
    }

    // TODO: is this function unsafe?
    unsafe fn new_inner(device: &Arc<Device>,
                        layouts: SmallVec<[Arc<UnsafeDescriptorSetLayout>; 16]>)
                        -> Result<UnsafePipelineLayout, OomError>
    {
        let vk = device.pointers();

        // FIXME: check that they belong to the right device
        let layouts_ids = layouts.iter().map(|l| l.internal_object())
                                 .collect::<SmallVec<[_; 16]>>();

        let layout = {
            let infos = vk::PipelineLayoutCreateInfo {
                sType: vk::STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO,
                pNext: ptr::null(),
                flags: 0,   // reserved
                setLayoutCount: layouts_ids.len() as u32,
                pSetLayouts: layouts_ids.as_ptr(),
                pushConstantRangeCount: 0,      // TODO: unimplemented
                pPushConstantRanges: ptr::null(),    // TODO: unimplemented
            };

            let mut output = mem::uninitialized();
            try!(check_errors(vk.CreatePipelineLayout(device.internal_object(), &infos,
                                                      ptr::null(), &mut output)));
            output
        };

        Ok(UnsafePipelineLayout {
            device: device.clone(),
            layout: layout,
            layouts: layouts,
        })
    }

    /// Returns the `UnsafeDescriptorSetLayout` object of the specified set index.
    ///
    /// Returns `None` if out of range.
    #[inline]
    pub fn descriptor_set_layout(&self, index: usize) -> Option<&Arc<UnsafeDescriptorSetLayout>> {
        self.layouts.get(index)
    }
}

unsafe impl VulkanObject for UnsafePipelineLayout {
    type Object = vk::PipelineLayout;

    #[inline]
    fn internal_object(&self) -> vk::PipelineLayout {
        self.layout
    }
}

impl Drop for UnsafePipelineLayout {
    #[inline]
    fn drop(&mut self) {
        unsafe {
            let vk = self.device.pointers();
            vk.DestroyPipelineLayout(self.device.internal_object(), self.layout, ptr::null());
        }
    }
}
<commit_msg>Add small test for UnsafePipelineLayout<commit_after>// Copyright (c) 2016 The vulkano developers
// Licensed under the Apache License, Version 2.0
// <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT
// license <LICENSE-MIT or http://opensource.org/licenses/MIT>,
// at your option. All files in the project carrying such
// notice may not be copied, modified, or distributed except
// according to those terms.

use std::mem;
use std::ptr;
use std::sync::Arc;
use smallvec::SmallVec;

use check_errors;
use OomError;
use VulkanObject;
use VulkanPointers;
use vk;

use descriptor::descriptor_set::UnsafeDescriptorSetLayout;
use device::Device;

/// Low-level struct that represents the layout of the resources available to your shaders.
// TODO: push constants.
pub struct UnsafePipelineLayout {
    device: Arc<Device>,
    layout: vk::PipelineLayout,
    layouts: SmallVec<[Arc<UnsafeDescriptorSetLayout>; 16]>,
}

impl UnsafePipelineLayout {
    /// Creates a new `UnsafePipelineLayout`.
    // TODO: is this function unsafe?
    #[inline]
    pub unsafe fn new<'a, I>(device: &Arc<Device>, layouts: I)
                             -> Result<UnsafePipelineLayout, OomError>
        where I: IntoIterator<Item = &'a Arc<UnsafeDescriptorSetLayout>>
    {
        UnsafePipelineLayout::new_inner(device, layouts.into_iter().map(|e| e.clone()).collect())
    }

    // TODO: is this function unsafe?
    unsafe fn new_inner(device: &Arc<Device>,
                        layouts: SmallVec<[Arc<UnsafeDescriptorSetLayout>; 16]>)
                        -> Result<UnsafePipelineLayout, OomError>
    {
        let vk = device.pointers();

        // FIXME: check that they belong to the right device
        let layouts_ids = layouts.iter().map(|l| l.internal_object())
                                 .collect::<SmallVec<[_; 16]>>();

        let layout = {
            let infos = vk::PipelineLayoutCreateInfo {
                sType: vk::STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO,
                pNext: ptr::null(),
                flags: 0,   // reserved
                setLayoutCount: layouts_ids.len() as u32,
                pSetLayouts: layouts_ids.as_ptr(),
                pushConstantRangeCount: 0,      // TODO: unimplemented
                pPushConstantRanges: ptr::null(),    // TODO: unimplemented
            };

            let mut output = mem::uninitialized();
            try!(check_errors(vk.CreatePipelineLayout(device.internal_object(), &infos,
                                                      ptr::null(), &mut output)));
            output
        };

        Ok(UnsafePipelineLayout {
            device: device.clone(),
            layout: layout,
            layouts: layouts,
        })
    }

    /// Returns the `UnsafeDescriptorSetLayout` object of the specified set index.
    ///
    /// Returns `None` if out of range.
    #[inline]
    pub fn descriptor_set_layout(&self, index: usize) -> Option<&Arc<UnsafeDescriptorSetLayout>> {
        self.layouts.get(index)
    }
}

unsafe impl VulkanObject for UnsafePipelineLayout {
    type Object = vk::PipelineLayout;

    #[inline]
    fn internal_object(&self) -> vk::PipelineLayout {
        self.layout
    }
}

impl Drop for UnsafePipelineLayout {
    #[inline]
    fn drop(&mut self) {
        unsafe {
            let vk = self.device.pointers();
            vk.DestroyPipelineLayout(self.device.internal_object(), self.layout, ptr::null());
        }
    }
}

#[cfg(test)]
mod tests {
    use std::iter;
    use descriptor::pipeline_layout::sys::UnsafePipelineLayout;

    #[test]
    fn empty() {
        let (device, _) = gfx_dev_and_queue!();
        let _layout = unsafe { UnsafePipelineLayout::new(&device, iter::empty()) };
    }
}
<|endoftext|>


<commit_before>//! Defines a series of convenience modifiers for editing Responses
//!
//! Modifiers can be used to edit Responses through the owning
//! method `set` or the mutating `set_mut`, both of which are
//! defined in the `Set` trait.
//!
//! Instead of having a combinatorial explosion of Response methods
//! and constructors, this provides a series of modifiers that
//! can be used through the `Set` trait.
//!
//! For instance, instead of `Response::redirect` constructing a
//! redirect response, we provide a `Redirect` modifier, so you
//! can just do:
//!
//! ```rust,ignore
//! Response::new()
//!     .set(Status(status))
//!     .set(Redirect(url));
//! ```
//!
//! This is more extensible as it allows you to combine
//! arbitrary modifiers without having a massive number of
//! Response constructors.
//!
//! For more information about the modifier system, see
//! [rust-modifier](https://github.com/reem/rust-modifier).

use std::str::StrAllocating;
use std::io::{File, MemReader};
use std::path::Path;

use modifier::Modifier;
use http::headers::content_type::MediaType;
use content_type::get_content_type;
use {status, Response, Url};

/// A response modifier for setting the content-type header.
pub struct ContentType(pub MediaType);

impl ContentType {
    /// Create a new ContentType modifier from the parts of a content-type header value.
    #[inline]
    pub fn new<S: StrAllocating, S1: StrAllocating>(type_: S, subtype: S1) -> ContentType {
        ContentType(MediaType::new(type_.into_string(), subtype.into_string(), vec![]))
    }
}

impl Modifier<Response> for ContentType {
    #[inline]
    fn modify(self, mut res: Response) -> Response {
        let ContentType(media) = self;
        res.headers.content_type = Some(media);
        res
    }
}

/// A response modifier for setting the body of a response.
pub struct Body<B: Bodyable>(pub B);

impl<B: Bodyable> Modifier<Response> for Body<B> {
    #[inline]
    fn modify(self, mut res: Response) -> Response {
        let Body(b) = self;
        b.set_body(&mut res);
        res
    }
}

/// Something that can be used to set the body of a response.
pub trait Bodyable {
    /// Set the body of this response, possibly also setting headers.
    fn set_body(self, res: &mut Response);
}

impl Bodyable for Box<Reader + Send> {
    #[inline]
    fn set_body(self, res: &mut Response) {
        res.body = Some(self);
    }
}

impl Bodyable for String {
    #[inline]
    fn set_body(self, res: &mut Response) {
        self.into_bytes().set_body(res);
    }
}

impl Bodyable for Vec<u8> {
    #[inline]
    fn set_body(self, res: &mut Response) {
        res.headers.content_length = Some(self.len());
        res.body = Some(box MemReader::new(self) as Box<Reader + Send>);
    }
}

impl<'a> Bodyable for &'a str {
    #[inline]
    fn set_body(self, res: &mut Response) {
        self.into_string().set_body(res);
    }
}

impl<'a> Bodyable for &'a [u8] {
    #[inline]
    fn set_body(self, res: &mut Response) {
        self.to_vec().set_body(res);
    }
}

impl Bodyable for File {
    #[inline]
    fn set_body(self, res: &mut Response) {
        // Also set the content type.
        res.headers.content_type = self.path().extension_str().and_then(get_content_type);
        res.body = Some(box self as Box<Reader + Send>);
    }
}

impl Bodyable for Path {
    /// Set the body to the contents of the File at this path.
    ///
    /// ## Panics
    ///
    /// Panics if there is no file at the passed-in Path.
    fn set_body(self, res: &mut Response) {
        File::open(&self)
            .ok().expect(format!("No such file: {}", self.display()).as_slice())
            .set_body(res);
    }
}

/// A modifier for setting the status of a response.
pub struct Status(pub status::Status);

impl Modifier<Response> for Status {
    fn modify(self, mut res: Response) -> Response {
        let Status(status) = self;
        res.status = Some(status);
        res
    }
}

/// A modifier for creating redirect responses.
pub struct Redirect(pub Url);

impl Modifier<Response> for Redirect {
    fn modify(self, mut res: Response) -> Response {
        let Redirect(url) = self;
        res.headers.location = Some(url.into_generic_url());
        res
    }
}

<commit_msg>(fix) Update Modifier::modify for safety reasons.<commit_after>//! Defines a series of convenience modifiers for editing Responses
//!
//! Modifiers can be used to edit Responses through the owning
//! method `set` or the mutating `set_mut`, both of which are
//! defined in the `Set` trait.
//!
//! Instead of having a combinatorial explosion of Response methods
//! and constructors, this provides a series of modifiers that
//! can be used through the `Set` trait.
//!
//! For instance, instead of `Response::redirect` constructing a
//! redirect response, we provide a `Redirect` modifier, so you
//! can just do:
//!
//! ```rust,ignore
//! Response::new()
//!     .set(Status(status))
//!     .set(Redirect(url));
//! ```
//!
//! This is more extensible as it allows you to combine
//! arbitrary modifiers without having a massive number of
//! Response constructors.
//!
//! For more information about the modifier system, see
//! [rust-modifier](https://github.com/reem/rust-modifier).

use std::str::StrAllocating;
use std::io::{File, MemReader};
use std::path::Path;

use modifier::Modifier;
use http::headers::content_type::MediaType;
use content_type::get_content_type;
use {status, Response, Url};

/// A response modifier for setting the content-type header.
pub struct ContentType(pub MediaType);

impl ContentType {
    /// Create a new ContentType modifier from the parts of a content-type header value.
    #[inline]
    pub fn new<S: StrAllocating, S1: StrAllocating>(type_: S, subtype: S1) -> ContentType {
        ContentType(MediaType::new(type_.into_string(), subtype.into_string(), vec![]))
    }
}

impl Modifier<Response> for ContentType {
    #[inline]
    fn modify(self, res: &mut Response) {
        let ContentType(media) = self;
        res.headers.content_type = Some(media);
    }
}

/// A response modifier for setting the body of a response.
pub struct Body<B: Bodyable>(pub B);

impl<B: Bodyable> Modifier<Response> for Body<B> {
    #[inline]
    fn modify(self, res: &mut Response) {
        let Body(b) = self;
        b.set_body(res);
    }
}

/// Something that can be used to set the body of a response.
pub trait Bodyable {
    /// Set the body of this response, possibly also setting headers.
    fn set_body(self, res: &mut Response);
}

impl Bodyable for Box<Reader + Send> {
    #[inline]
    fn set_body(self, res: &mut Response) {
        res.body = Some(self);
    }
}

impl Bodyable for String {
    #[inline]
    fn set_body(self, res: &mut Response) {
        self.into_bytes().set_body(res);
    }
}

impl Bodyable for Vec<u8> {
    #[inline]
    fn set_body(self, res: &mut Response) {
        res.headers.content_length = Some(self.len());
        res.body = Some(box MemReader::new(self) as Box<Reader + Send>);
    }
}

impl<'a> Bodyable for &'a str {
    #[inline]
    fn set_body(self, res: &mut Response) {
        self.into_string().set_body(res);
    }
}

impl<'a> Bodyable for &'a [u8] {
    #[inline]
    fn set_body(self, res: &mut Response) {
        self.to_vec().set_body(res);
    }
}

impl Bodyable for File {
    #[inline]
    fn set_body(self, res: &mut Response) {
        // Also set the content type.
        res.headers.content_type = self.path().extension_str().and_then(get_content_type);
        res.body = Some(box self as Box<Reader + Send>);
    }
}

impl Bodyable for Path {
    /// Set the body to the contents of the File at this path.
    ///
    /// ## Panics
    ///
    /// Panics if there is no file at the passed-in Path.
    fn set_body(self, res: &mut Response) {
        File::open(&self)
            .ok().expect(format!("No such file: {}", self.display()).as_slice())
            .set_body(res);
    }
}

/// A modifier for setting the status of a response.
pub struct Status(pub status::Status);

impl Modifier<Response> for Status {
    fn modify(self, res: &mut Response) {
        let Status(status) = self;
        res.status = Some(status);
    }
}

/// A modifier for creating redirect responses.
pub struct Redirect(pub Url);

impl Modifier<Response> for Redirect {
    fn modify(self, res: &mut Response) {
        let Redirect(url) = self;
        res.headers.location = Some(url.into_generic_url());
    }
}

<|endoftext|>


<commit_before>//! Framerate control

use libc;
use libc::{c_void, uint32_t, size_t};
use std::mem;
use ::get_error;
use sys::gfx;

/// Structure holding the state and timing information of the framerate controller.
pub struct FPSManager {
    raw: *mut gfx::framerate::FPSmanager,
}

impl FPSManager {
    /// Create the framerate manager.
    pub fn new() -> FPSManager {
        unsafe {
            let size = mem::size_of::<gfx::framerate::FPSmanager>() as size_t;
            let raw = libc::malloc(size) as *mut gfx::framerate::FPSmanager;
            gfx::framerate::SDL_initFramerate(raw);
            FPSManager { raw: raw }
        }
    }

    /// Set the framerate in Hz.
    pub fn set_framerate(&mut self, rate: u32) -> Result<(), String> {
        let ret = unsafe { gfx::framerate::SDL_setFramerate(self.raw, rate as uint32_t) };
        match ret {
            0 => Ok(()),
            _ => Err(get_error())
        }
    }

    /// Return the current target framerate in Hz.
    pub fn get_framerate(&self) -> i32 {
        // will not get an error
        unsafe { gfx::framerate::SDL_getFramerate(self.raw) as i32 }
    }

    /// Return the current framecount.
    pub fn get_frame_count(&self) -> i32 {
        // will not get an error
        unsafe { gfx::framerate::SDL_getFramecount(self.raw) as i32 }
    }

    /// Delay execution to maintain a constant framerate and calculate fps.
    pub fn delay(&mut self) -> u32 {
        unsafe { gfx::framerate::SDL_framerateDelay(self.raw) as u32 }
    }
}

impl Drop for FPSManager {
    fn drop(&mut self) {
        unsafe { libc::free(self.raw as *mut c_void) }
    }
}
<commit_msg>Use u32 instead of deprecated item 'libc::uint32_t'<commit_after>//! Framerate control

use libc;
use libc::{c_void, size_t};
use std::mem;
use ::get_error;
use sys::gfx;

/// Structure holding the state and timing information of the framerate controller.
pub struct FPSManager {
    raw: *mut gfx::framerate::FPSmanager,
}

impl FPSManager {
    /// Create the framerate manager.
    pub fn new() -> FPSManager {
        unsafe {
            let size = mem::size_of::<gfx::framerate::FPSmanager>() as size_t;
            let raw = libc::malloc(size) as *mut gfx::framerate::FPSmanager;
            gfx::framerate::SDL_initFramerate(raw);
            FPSManager { raw: raw }
        }
    }

    /// Set the framerate in Hz.
    pub fn set_framerate(&mut self, rate: u32) -> Result<(), String> {
        let ret = unsafe { gfx::framerate::SDL_setFramerate(self.raw, rate as u32) };
        match ret {
            0 => Ok(()),
            _ => Err(get_error())
        }
    }

    /// Return the current target framerate in Hz.
    pub fn get_framerate(&self) -> i32 {
        // will not get an error
        unsafe { gfx::framerate::SDL_getFramerate(self.raw) as i32 }
    }

    /// Return the current framecount.
    pub fn get_frame_count(&self) -> i32 {
        // will not get an error
        unsafe { gfx::framerate::SDL_getFramecount(self.raw) as i32 }
    }

    /// Delay execution to maintain a constant framerate and calculate fps.
    pub fn delay(&mut self) -> u32 {
        unsafe { gfx::framerate::SDL_framerateDelay(self.raw) as u32 }
    }
}

impl Drop for FPSManager {
    fn drop(&mut self) {
        unsafe { libc::free(self.raw as *mut c_void) }
    }
}
<|endoftext|>


<commit_before>use super::*;
use crate::StrError;

impl Shape {
    /// Selects a set of integrations points
    pub fn select_int_points(&mut self, nip: usize) -> Result<(), StrError> {
        match self.class {
            GeoClass::Lin => match nip {
                1 => self.ip_data = &IP_LIN_LEGENDRE_1,
                2 => self.ip_data = &IP_LIN_LEGENDRE_2,
                3 => self.ip_data = &IP_LIN_LEGENDRE_3,
                4 => self.ip_data = &IP_LIN_LEGENDRE_4,
                5 => self.ip_data = &IP_LIN_LEGENDRE_5,
                _ => return Err("integration points set is not available for this GeoClass"),
            },
            GeoClass::Tri => match nip {
                1 => self.ip_data = &IP_TRI_INTERNAL_1,
                3 => self.ip_data = &IP_TRI_INTERNAL_3,
                _ => return Err("integration points set is not available for this GeoClass"),
            },
            GeoClass::Qua => match nip {
                1 => self.ip_data = &IP_QUA_LEGENDRE_1,
                4 => self.ip_data = &IP_QUA_LEGENDRE_4,
                9 => self.ip_data = &IP_QUA_LEGENDRE_9,
                16 => self.ip_data = &IP_QUA_LEGENDRE_16,
                _ => return Err("integration points set is not available for this GeoClass"),
            },
            GeoClass::Tet => match nip {
                1 => self.ip_data = &IP_TET_INTERNAL_1,
                4 => self.ip_data = &IP_TET_INTERNAL_4,
                5 => self.ip_data = &IP_TET_INTERNAL_5,
                6 => self.ip_data = &IP_TET_INTERNAL_6,
                _ => return Err("integration points set is not available for this GeoClass"),
            },
            GeoClass::Hex => match nip {
                8 => self.ip_data = &IP_HEX_LEGENDRE_8,
                9 => self.ip_data = &IP_HEX_WILSON_CORNER_9,
                6 => self.ip_data = &IP_HEX_IRONS_6,
                14 => self.ip_data = &IP_HEX_IRONS_14,
                27 => self.ip_data = &IP_HEX_LEGENDRE_27,
                _ => return Err("integration points set is not available for this GeoClass"),
            },
        }
        Ok(())
    }

    pub fn integrate_fx(&mut self) -> Result<f64, StrError> {
        Ok(0.0)
    }
}
<commit_msg>[wip] Impl select_int_points method<commit_after>use super::*;
use crate::StrError;

/// Defines options to select integration points
#[derive(Eq, PartialEq)]
pub enum OptionIntPoint {
    /// Option for Tri (points on edge)
    Edge,

    /// Option for Qua and Hex (Wilson formula)
    WilsonStable,
}

impl Shape {
    /// Selects integrations points and weights
    ///
    /// # Options
    ///
    /// ## nip for Lin class
    ///
    /// * `1` -- Legendre points
    /// * `2` -- Legendre points
    /// * `3` -- Legendre points
    /// * `4` -- Legendre points
    /// * `5` -- Legendre points
    ///
    /// ## nip for Tri class
    ///
    /// * `1` -- Internal points
    /// * `3`:
    ///     - `Edge` -- Points on edge
    ///     - Otherwise, internal points
    /// * `4` -- Internal points
    /// * `12` -- Internal points
    /// * `16` -- Internal points
    ///
    /// ## nip for Qua class
    ///
    /// * `1` -- Legendre points
    /// * `4` -- Legendre points
    /// * `5`:
    ///     - `WilsonStable` -- Wilson's "Stable" version with w0=0.004 and wa=0.999 to mimic 4-point rule
    ///     - Otherwise, Wilson's formula
    /// * `9` -- Legendre points
    /// * `16` -- Legendre points
    ///
    /// ## nip for Tet class
    ///
    /// * `1` -- Internal points
    /// * `4` -- Internal points
    /// * `5` -- Internal points
    /// * `6` -- Internal points
    ///
    /// ## nip for Hex class
    ///
    /// * `6` -- Iron's formula
    /// * `8` -- Legendre points
    /// * `9`:
    ///     - `WilsonStable` -- Wilson's "Stable" version
    ///     - Otherwise, Wilson's formula
    /// * `14` -- Iron's formula
    /// * `27` -- Legendre points
    pub fn select_int_points(&mut self, nip: usize, option: OptionIntPoint) -> Result<(), StrError> {
        match self.class {
            GeoClass::Lin => match nip {
                1 => self.ip_data = &IP_LIN_LEGENDRE_1,
                2 => self.ip_data = &IP_LIN_LEGENDRE_2,
                3 => self.ip_data = &IP_LIN_LEGENDRE_3,
                4 => self.ip_data = &IP_LIN_LEGENDRE_4,
                5 => self.ip_data = &IP_LIN_LEGENDRE_5,
                _ => return Err("number of integration points is not available for Lin class"),
            },
            GeoClass::Tri => match nip {
                1 => self.ip_data = &IP_TRI_INTERNAL_1,
                3 => {
                    if option == OptionIntPoint::Edge {
                        self.ip_data = &IP_TRI_EDGE_3
                    } else {
                        self.ip_data = &IP_TRI_INTERNAL_3
                    }
                }
                4 => self.ip_data = &IP_TRI_INTERNAL_4,
                12 => self.ip_data = &IP_TRI_INTERNAL_12,
                16 => self.ip_data = &IP_TRI_INTERNAL_16,
                _ => return Err("number of integration points is not available for Tri class"),
            },
            GeoClass::Qua => match nip {
                1 => self.ip_data = &IP_QUA_LEGENDRE_1,
                4 => self.ip_data = &IP_QUA_LEGENDRE_4,
                5 => {
                    if option == OptionIntPoint::WilsonStable {
                        self.ip_data = &IP_QUA_WILSON_STABLE_5
                    } else {
                        self.ip_data = &IP_QUA_WILSON_CORNER_5
                    }
                }
                8 => self.ip_data = &IP_QUA_WILSON_8,
                9 => self.ip_data = &IP_QUA_LEGENDRE_9,
                16 => self.ip_data = &IP_QUA_LEGENDRE_16,
                _ => return Err("number of integration points is not available for Qua class"),
            },
            GeoClass::Tet => match nip {
                1 => self.ip_data = &IP_TET_INTERNAL_1,
                4 => self.ip_data = &IP_TET_INTERNAL_4,
                5 => self.ip_data = &IP_TET_INTERNAL_5,
                6 => self.ip_data = &IP_TET_INTERNAL_6,
                _ => return Err("number of integration points is not available for Tet class"),
            },
            GeoClass::Hex => match nip {
                6 => self.ip_data = &IP_HEX_IRONS_6,
                8 => self.ip_data = &IP_HEX_LEGENDRE_8,
                9 => {
                    if option == OptionIntPoint::WilsonStable {
                        self.ip_data = &IP_HEX_WILSON_STABLE_9
                    } else {
                        self.ip_data = &IP_HEX_WILSON_CORNER_9
                    }
                }
                14 => self.ip_data = &IP_HEX_IRONS_14,
                27 => self.ip_data = &IP_HEX_LEGENDRE_27,
                _ => return Err("number of integration points is not available for Hex class"),
            },
        }
        Ok(())
    }

    pub fn integrate_fx(&mut self) -> Result<f64, StrError> {
        Ok(0.0)
    }
}
<|endoftext|>