<commit_before>use std::collections::VecDeque;

extern crate sliding_window;
use sliding_window::SliceRing;

#[test]
fn test_deque_push_many_back() {
    let mut deque: VecDeque<i32> = VecDeque::new();
    let vec = (0..10000).collect::<Vec<i32>>();
    deque.push_many_back(&vec[..]);
    assert_eq!(deque.len(), 10000);
    assert_eq!(deque[0], 0);
    assert_eq!(deque[9999], 9999);
    let vec = (500..1000).collect::<Vec<i32>>();
    deque.push_many_back(&vec[..]);
    assert_eq!(deque.len(), 10500);
    assert_eq!(deque[10000], 500);
    assert_eq!(deque[10499], 999);
}

// impl<T: Copy> SlidingWindow<T> {
//     pub fn new(window_size: usize, step_size: usize) -> Self {
//         assert!(0 < window_size);
//         assert!(0 < step_size);
//
//         SlidingWindow {
//             window_size: window_size,
//             step_size: step_size,
//             // TODO with_capacity
//             ringbuffer: VecDeque::new(),
//         }
//     }
//
//     // TODO how fast is this ?
//     // time complexity
//     // append `samples`
//     pub fn len
//
//     pub fn is_full(&self) -> bool {
//         self.window_size <= self.ringbuffer.len()
//     }
//
//     pub fn read_front(&mut self, fill_me: &mut [T]) -> bool {
//         if !self.can_fill() { return false; }
//         assert_eq!(fill_me.len(), self.window_size);
//         for i in 0..self.window_size {
//             fill_me[i] = self.ringbuffer[i];
//         }
//         true
//     }
//
//     pub fn drop_front(&mut self, count: usize) {
//         for _ in 0..count {
//             self.buf.pop_front();
//         }
//     }
//
//     // if `self.can_fill()` fills `window` fully with the next
//     // `window_size` samples.
//     // then makes a step discards `self.step_size` samples.
//     // else does nothing.
//     // `window.len()` must be equal to `self.window_size`.
//     // returns whether `self.can_fill()`.
//     pub fn fill_and_step(&mut self, fill_me: &mut [T]) -> bool {
//         if !self.fill(fill_me) { return false; }
//         self.step();
//         true
//     }
// }

// #[test]
// fn test_window_1_step_1() {
//     let mut sliding_window: SlidingWindow<i32> = SlidingWindow::new(1, 1);
//     assert!(!sliding_window.can_fill());
//     let samples: Vec<i32> = vec![];
//     sliding_window.write(&samples[..]);
//     assert!(!sliding_window.can_fill());
//     assert_eq!(sliding_window.ringbuffer.len(), 0);
//
//     let mut window: Vec<i32> = vec![0];
//     assert!(!sliding_window.read(&mut window[..]));
//     assert_eq!(window, vec![0]);
//
//     let samples: Vec<i32> = vec![1];
//     sliding_window.write(&samples[..]);
//     assert_eq!(sliding_window.ringbuffer.len(), 1);
//     assert!(sliding_window.can_fill());
//     assert!(sliding_window.read(&mut window[..]));
//     assert_eq!(window, vec![1]);
//     assert_eq!(sliding_window.ringbuffer.len(), 0);
//
//     let samples: Vec<i32> = vec![1, 2, 3];
//     sliding_window.write(&samples[..]);
//     assert_eq!(sliding_window.ringbuffer.len(), 3);
//
//     assert!(sliding_window.can_fill());
//     assert!(sliding_window.read(&mut window[..]));
//     assert_eq!(window, vec![1]);
//     assert_eq!(sliding_window.ringbuffer.len(), 2);
//
//     assert!(sliding_window.can_fill());
//     assert!(sliding_window.read(&mut window[..]));
//     assert_eq!(window, vec![2]);
//     assert_eq!(sliding_window.ringbuffer.len(), 1);
//
//     assert!(sliding_window.can_fill());
//     assert!(sliding_window.read(&mut window[..]));
//     assert_eq!(window, vec![3]);
//     assert_eq!(sliding_window.ringbuffer.len(), 0);
//     assert!(!sliding_window.can_fill());
// }
//
// #[test]
// fn test_window_4_step_2() {
//     // 50% overlap
//
//     let mut sliding_window: SlidingWindow<i32> = SlidingWindow::new(4, 2);
//     assert!(!sliding_window.can_fill());
//     let samples: Vec<i32> = vec![];
//     sliding_window.write(&samples[..]);
//     assert!(!sliding_window.can_fill());
//     assert_eq!(sliding_window.ringbuffer.len(), 0);
//
//     let mut window: Vec<i32> = vec![0];
//     assert!(!sliding_window.read(&mut window[..]));
//     assert_eq!(window, vec![0]);
//
//     {
//         let mut ring: VecDeque<i32> = VecDeque::new();
//         let mut window: Vec<i32> = vec![0, 0, 0, 0];
//         let samples: Vec<i32> = vec![1, 2, 3];
//         // println!("samples {:?}", samples);
//         let mut calls = 0;
//         window!(2, ring, &samples[..], &mut window[..], {
//             calls += 1;
//         });
//         assert_eq!(calls, 0);
//         assert_eq!(window, vec![0, 0, 0, 0]);
//         assert_eq!(ring.len(), 3);
//     }
//
//     {
//         let mut ring: VecDeque<i32> = VecDeque::new();
//         let mut window: Vec<i32> = vec![0, 0, 0, 0];
//         let samples: Vec<i32> = vec![1, 2, 3, 4];
//         // println!("samples {:?}", samples);
//         let mut calls = 0;
//         window!(2, ring, &samples[..], &mut window[..], {
//             assert_eq!(ring.len(), 2);
//             assert_eq!(window, vec![1, 2, 3, 4]);
//             calls += 1;
//         });
//         assert_eq!(calls, 1);
//         assert_eq!(window, vec![1, 2, 3, 4]);
//         assert_eq!(ring.len(), 2);
//     }
//
//     {
//         let mut ring: VecDeque<i32> = VecDeque::new();
//         let mut window: Vec<i32> = vec![0, 0, 0, 0];
//         let samples: Vec<i32> = vec![1, 2, 3 ,4, 5, 6, 7, 8, 9, 10, 11];
//         let mut calls = 0;
//         window!(2, ring, &samples[..], &mut window[..], {
//             match calls {
//                 0 => { assert_eq!(window, vec![1, 2, 3, 4]) },
//                 1 => { assert_eq!(window, vec![3, 4, 5, 6]) },
//                 2 => { assert_eq!(window, vec![5, 6, 7, 8]) },
//                 3 => { assert_eq!(window, vec![7, 8, 9, 10]) },
//                 _ => { assert!(false) },
//             }
//             calls += 1;
//         });
//         assert_eq!(calls, 4);
//         assert_eq!(window, vec![7, 8, 9, 10]);
//         assert_eq!(ring.len(), 3);
//
//         let samples: Vec<i32> = vec![12, 13, 14, 15, 16];
//         let mut calls = 0;
//         window!(2, ring, &samples[..], &mut window[..], {
//             match calls {
//                 0 => { assert_eq!(window, vec![9, 10, 11, 12]) },
//                 1 => { assert_eq!(window, vec![11, 12, 13, 14]) },
//                 2 => { assert_eq!(window, vec![13, 14, 15, 16]) },
//                 _ => { assert!(false) },
//             }
//             calls += 1;
//         });
//         assert_eq!(calls, 3);
//         assert_eq!(window, vec![13, 14, 15, 16]);
//         assert_eq!(ring.len(), 2);
//     }
// }
//
// #[test]
// fn test_window_1024_step_512() {
//     // 50% overlap
//     use std::collections::VecDeque;
//     use std::iter;
//
//     {
//         let mut ring: VecDeque<i32> = VecDeque::new();
//         let mut window: Vec<i32> = vec![0; 1024];
//         let samples: Vec<i32> =
//             iter::repeat(1).take(1024)
//             .chain(iter::repeat(2).take(1024))
//             .chain(iter::repeat(3).take(1024))
//             .chain(iter::repeat(4).take(1024))
//             .collect();
//         assert_eq!(samples.len(), 1024 * 4);
//         let mut calls = 0;
//         window!(512, ring, &samples[..], &mut window[..], {
//             match calls {
//                 0 => {
//                     assert_eq!(
//                         window,
//                         iter::repeat(1).take(1024).collect::<Vec<i32>>()
//                     );
//                 },
//                 1 => {
//                     assert_eq!(
//                         window,
//                         iter::repeat(1).take(512)
//                         .chain(iter::repeat(2).take(512))
//                         .collect::<Vec<i32>>()
//                     );
//                 },
//                 2 => {
//                     assert_eq!(
//                         window,
//                         iter::repeat(2).take(1024).collect::<Vec<i32>>()
//                     );
//                 },
//                 3 => {
//                     assert_eq!(
//                         window,
//                         iter::repeat(2).take(512)
//                         .chain(iter::repeat(3).take(512))
//                         .collect::<Vec<i32>>()
//                     );
//                 },
//                 4 => {
//                     assert_eq!(
//                         window,
//                         iter::repeat(3).take(1024).collect::<Vec<i32>>()
//                     );
//                 },
//                 5 => {
//                     assert_eq!(
//                         window,
//                         iter::repeat(3).take(512)
//                         .chain(iter::repeat(4).take(512))
//                         .collect::<Vec<i32>>()
//                     );
//                 },
//                 6 => {
//                     assert_eq!(
//                         window,
//                         iter::repeat(4).take(1024).collect::<Vec<i32>>()
//                     );
//                 },
//                 _ => {}
//             }
//             calls += 1;
//         });
//         assert_eq!(calls, 7);
//         assert_eq!(ring.len(), 512);
//     }
// }

// 4048 and 512
<commit_msg>start writing tests once against both deque and optimized<commit_after>use std::collections::VecDeque;

extern crate sliding_window;
use sliding_window::SliceRing;
use sliding_window::OptimizedSliceRing;

macro_rules! test_slice_ring {
    ($new:expr) => {{
        let mut testable = $new;

        let input = (0..10000).collect::<Vec<i32>>();
        testable.push_many_back(&input[..]);
        assert_eq!(testable.len(), 10000);
        assert_eq!(testable.capacity(), 16383);

        let mut output: Vec<i32> = std::iter::repeat(0).take(1000).collect();
        testable.read_many_front(&mut output[..]);
        assert_eq!(output, (0..1000).collect::<Vec<i32>>());
    }};
}

#[test]
fn test_deque_slice_ring() {
    test_slice_ring!(VecDeque::<i32>::new());
}

#[test]
fn test_optimized_slice_ring() {
    test_slice_ring!(OptimizedSliceRing::<i32>::new());
}

#[test]
fn test_deque_push_many_back() {
    let mut deque: VecDeque<i32> = VecDeque::new();
    let vec = (0..10000).collect::<Vec<i32>>();
    deque.push_many_back(&vec[..]);
    assert_eq!(deque.len(), 10000);
    assert_eq!(deque[0], 0);
    assert_eq!(deque[9999], 9999);
    let vec = (500..1000).collect::<Vec<i32>>();
    deque.push_many_back(&vec[..]);
    assert_eq!(deque.len(), 10500);
    assert_eq!(deque[10000], 500);
    assert_eq!(deque[10499], 999);
}

// impl<T: Copy> SlidingWindow<T> {
//     pub fn new(window_size: usize, step_size: usize) -> Self {
//         assert!(0 < window_size);
//         assert!(0 < step_size);
//
//         SlidingWindow {
//             window_size: window_size,
//             step_size: step_size,
//             // TODO with_capacity
//             ringbuffer: VecDeque::new(),
//         }
//     }
//
//     // TODO how fast is this ?
//     // time complexity
//     // append `samples`
//     pub fn len
//
//     pub fn is_full(&self) -> bool {
//         self.window_size <= self.ringbuffer.len()
//     }
//
//     pub fn read_front(&mut self, fill_me: &mut [T]) -> bool {
//         if !self.can_fill() { return false; }
//         assert_eq!(fill_me.len(), self.window_size);
//         for i in 0..self.window_size {
//             fill_me[i] = self.ringbuffer[i];
//         }
//         true
//     }
//
//     pub fn drop_front(&mut self, count: usize) {
//         for _ in 0..count {
//             self.buf.pop_front();
//         }
//     }
//
//     // if `self.can_fill()` fills `window` fully with the next
//     // `window_size` samples.
//     // then makes a step discards `self.step_size` samples.
//     // else does nothing.
//     // `window.len()` must be equal to `self.window_size`.
//     // returns whether `self.can_fill()`.
//     pub fn fill_and_step(&mut self, fill_me: &mut [T]) -> bool {
//         if !self.fill(fill_me) { return false; }
//         self.step();
//         true
//     }
// }

// #[test]
// fn test_window_1_step_1() {
//     let mut sliding_window: SlidingWindow<i32> = SlidingWindow::new(1, 1);
//     assert!(!sliding_window.can_fill());
//     let samples: Vec<i32> = vec![];
//     sliding_window.write(&samples[..]);
//     assert!(!sliding_window.can_fill());
//     assert_eq!(sliding_window.ringbuffer.len(), 0);
//
//     let mut window: Vec<i32> = vec![0];
//     assert!(!sliding_window.read(&mut window[..]));
//     assert_eq!(window, vec![0]);
//
//     let samples: Vec<i32> = vec![1];
//     sliding_window.write(&samples[..]);
//     assert_eq!(sliding_window.ringbuffer.len(), 1);
//     assert!(sliding_window.can_fill());
//     assert!(sliding_window.read(&mut window[..]));
//     assert_eq!(window, vec![1]);
//     assert_eq!(sliding_window.ringbuffer.len(), 0);
//
//     let samples: Vec<i32> = vec![1, 2, 3];
//     sliding_window.write(&samples[..]);
//     assert_eq!(sliding_window.ringbuffer.len(), 3);
//
//     assert!(sliding_window.can_fill());
//     assert!(sliding_window.read(&mut window[..]));
//     assert_eq!(window, vec![1]);
//     assert_eq!(sliding_window.ringbuffer.len(), 2);
//
//     assert!(sliding_window.can_fill());
//     assert!(sliding_window.read(&mut window[..]));
//     assert_eq!(window, vec![2]);
//     assert_eq!(sliding_window.ringbuffer.len(), 1);
//
//     assert!(sliding_window.can_fill());
//     assert!(sliding_window.read(&mut window[..]));
//     assert_eq!(window, vec![3]);
//     assert_eq!(sliding_window.ringbuffer.len(), 0);
//     assert!(!sliding_window.can_fill());
// }
//
// #[test]
// fn test_window_4_step_2() {
//     // 50% overlap
//
//     let mut sliding_window: SlidingWindow<i32> = SlidingWindow::new(4, 2);
//     assert!(!sliding_window.can_fill());
//     let samples: Vec<i32> = vec![];
//     sliding_window.write(&samples[..]);
//     assert!(!sliding_window.can_fill());
//     assert_eq!(sliding_window.ringbuffer.len(), 0);
//
//     let mut window: Vec<i32> = vec![0];
//     assert!(!sliding_window.read(&mut window[..]));
//     assert_eq!(window, vec![0]);
//
//     {
//         let mut ring: VecDeque<i32> = VecDeque::new();
//         let mut window: Vec<i32> = vec![0, 0, 0, 0];
//         let samples: Vec<i32> = vec![1, 2, 3];
//         // println!("samples {:?}", samples);
//         let mut calls = 0;
//         window!(2, ring, &samples[..], &mut window[..], {
//             calls += 1;
//         });
//         assert_eq!(calls, 0);
//         assert_eq!(window, vec![0, 0, 0, 0]);
//         assert_eq!(ring.len(), 3);
//     }
//
//     {
//         let mut ring: VecDeque<i32> = VecDeque::new();
//         let mut window: Vec<i32> = vec![0, 0, 0, 0];
//         let samples: Vec<i32> = vec![1, 2, 3, 4];
//         // println!("samples {:?}", samples);
//         let mut calls = 0;
//         window!(2, ring, &samples[..], &mut window[..], {
//             assert_eq!(ring.len(), 2);
//             assert_eq!(window, vec![1, 2, 3, 4]);
//             calls += 1;
//         });
//         assert_eq!(calls, 1);
//         assert_eq!(window, vec![1, 2, 3, 4]);
//         assert_eq!(ring.len(), 2);
//     }
//
//     {
//         let mut ring: VecDeque<i32> = VecDeque::new();
//         let mut window: Vec<i32> = vec![0, 0, 0, 0];
//         let samples: Vec<i32> = vec![1, 2, 3 ,4, 5, 6, 7, 8, 9, 10, 11];
//         let mut calls = 0;
//         window!(2, ring, &samples[..], &mut window[..], {
//             match calls {
//                 0 => { assert_eq!(window, vec![1, 2, 3, 4]) },
//                 1 => { assert_eq!(window, vec![3, 4, 5, 6]) },
//                 2 => { assert_eq!(window, vec![5, 6, 7, 8]) },
//                 3 => { assert_eq!(window, vec![7, 8, 9, 10]) },
//                 _ => { assert!(false) },
//             }
//             calls += 1;
//         });
//         assert_eq!(calls, 4);
//         assert_eq!(window, vec![7, 8, 9, 10]);
//         assert_eq!(ring.len(), 3);
//
//         let samples: Vec<i32> = vec![12, 13, 14, 15, 16];
//         let mut calls = 0;
//         window!(2, ring, &samples[..], &mut window[..], {
//             match calls {
//                 0 => { assert_eq!(window, vec![9, 10, 11, 12]) },
//                 1 => { assert_eq!(window, vec![11, 12, 13, 14]) },
//                 2 => { assert_eq!(window, vec![13, 14, 15, 16]) },
//                 _ => { assert!(false) },
//             }
//             calls += 1;
//         });
//         assert_eq!(calls, 3);
//         assert_eq!(window, vec![13, 14, 15, 16]);
//         assert_eq!(ring.len(), 2);
//     }
// }
//
// #[test]
// fn test_window_1024_step_512() {
//     // 50% overlap
//     use std::collections::VecDeque;
//     use std::iter;
//
//     {
//         let mut ring: VecDeque<i32> = VecDeque::new();
//         let mut window: Vec<i32> = vec![0; 1024];
//         let samples: Vec<i32> =
//             iter::repeat(1).take(1024)
//             .chain(iter::repeat(2).take(1024))
//             .chain(iter::repeat(3).take(1024))
//             .chain(iter::repeat(4).take(1024))
//             .collect();
//         assert_eq!(samples.len(), 1024 * 4);
//         let mut calls = 0;
//         window!(512, ring, &samples[..], &mut window[..], {
//             match calls {
//                 0 => {
//                     assert_eq!(
//                         window,
//                         iter::repeat(1).take(1024).collect::<Vec<i32>>()
//                     );
//                 },
//                 1 => {
//                     assert_eq!(
//                         window,
//                         iter::repeat(1).take(512)
//                         .chain(iter::repeat(2).take(512))
//                         .collect::<Vec<i32>>()
//                     );
//                 },
//                 2 => {
//                     assert_eq!(
//                         window,
//                         iter::repeat(2).take(1024).collect::<Vec<i32>>()
//                     );
//                 },
//                 3 => {
//                     assert_eq!(
//                         window,
//                         iter::repeat(2).take(512)
//                         .chain(iter::repeat(3).take(512))
//                         .collect::<Vec<i32>>()
//                     );
//                 },
//                 4 => {
//                     assert_eq!(
//                         window,
//                         iter::repeat(3).take(1024).collect::<Vec<i32>>()
//                     );
//                 },
//                 5 => {
//                     assert_eq!(
//                         window,
//                         iter::repeat(3).take(512)
//                         .chain(iter::repeat(4).take(512))
//                         .collect::<Vec<i32>>()
//                     );
//                 },
//                 6 => {
//                     assert_eq!(
//                         window,
//                         iter::repeat(4).take(1024).collect::<Vec<i32>>()
//                     );
//                 },
//                 _ => {}
//             }
//             calls += 1;
//         });
//         assert_eq!(calls, 7);
//         assert_eq!(ring.len(), 512);
//     }
// }

// 4048 and 512
<|endoftext|>


<commit_before>mod test_append_to_stream;
mod test_read_stream_events_forward;
<commit_msg>Don't try to consolidate all tests under the single module<commit_after><|endoftext|>


<commit_before>pub mod common;
<commit_msg>Remove unused file.<commit_after><|endoftext|>


<commit_before>extern crate z80emulib;

#[cfg(test)]
mod test_zex {
    use z80emulib::memory::*;
    use z80emulib::cpu::*;

    static ZEXDOC: &'static [u8] = include_bytes!("zexdoc.com");

    #[test]
    fn test_zexdoc() {
        let mut dummyrom0: Vec<u8> = vec![0; 16 * 1024];
        let dummyrom1: Vec<u8> = vec![0; 16 * 1024];

        for (i, byte) in ZEXDOC.iter().enumerate() {
            dummyrom0[i + 0x100] = *byte;
        }

        let memory = Memory::new(dummyrom0, dummyrom1);

        let mut cpu = Cpu::new(memory);
        cpu.set_pc(0x0100);
        cpu.write_reg16(Reg16::SP, 0xF000);

        cpu.run();
    }
}
<commit_msg>Fix SP in ZEXDOC test<commit_after>extern crate z80emulib;

#[cfg(test)]
mod test_zex {
    use z80emulib::memory::*;
    use z80emulib::cpu::*;

    static ZEXDOC: &'static [u8] = include_bytes!("zexdoc.com");

    #[test]
    fn test_zexdoc() {
        let mut dummyrom0: Vec<u8> = vec![0; 16 * 1024];
        let dummyrom1: Vec<u8> = vec![0; 16 * 1024];

        for (i, byte) in ZEXDOC.iter().enumerate() {
            dummyrom0[i + 0x100] = *byte;
        }
        // The ZEXDOC test seems to get its SP from address 0x0006
        dummyrom0[0x0006] = 0x00;
        dummyrom0[0x0007] = 0xF0;

        let memory = Memory::new(dummyrom0, dummyrom1);

        let mut cpu = Cpu::new(memory);
        cpu.set_pc(0x0100);

        cpu.run();
    }
}
<|endoftext|>


<commit_before>use std::error;
use std::fmt;
use std::mem;
use std::ptr;
use std::sync::Arc;
use std::sync::Mutex;

use device::Device;
use device::Queue;
use formats::FormatMarker;
use image::Image;
use image::ImagePrototype;
use image::Type2d;
use image::Usage as ImageUsage;
use memory::ChunkProperties;
use memory::ChunkRange;
use memory::MemorySourceChunk;
use swapchain::CompositeAlpha;
use swapchain::PresentMode;
use swapchain::Surface;
use swapchain::SurfaceTransform;
use sync::Fence;
use sync::Semaphore;
use sync::SharingMode;

use check_errors;
use Error;
use OomError;
use Success;
use VulkanObject;
use VulkanPointers;
use vk;

/// Contains the swapping system and the images that can be shown on a surface.
pub struct Swapchain {
    device: Arc<Device>,
    surface: Arc<Surface>,
    swapchain: vk::SwapchainKHR,

    images_semaphores: Mutex<Vec<Option<Arc<Semaphore>>>>,
}

impl Swapchain {
    /// Builds a new swapchain. Allocates images who content can be made visible on a surface.
    ///
    /// See also the `Surface::get_capabilities` function which returns the values that are
    /// supported by the implementation. All the parameters that you pass to `Swapchain::new`
    /// must be supported.
    ///
    /// The `clipped` parameter indicates whether the implementation is allowed to discard
    /// rendering operations that affect regions of the surface which aren't visible. This is
    /// important to take into account if your fragment shader has side-effects or if you want to
    /// read back the content of the image afterwards.
    ///
    /// This function returns the swapchain plus a list of the images that belong to the
    /// swapchain. The order in which the images are returned is important for the
    /// `acquire_next_image` and `present` functions.
    ///
    /// # Panic
    ///
    /// - Panicks if the device and the surface don't belong to the same instance.
    /// - Panicks if `color_attachment` is false in `usage`.
    ///
    pub fn new<F, S>(device: &Arc<Device>, surface: &Arc<Surface>, num_images: u32, format: F,
                     dimensions: [u32; 2], layers: u32, usage: &ImageUsage, sharing: S,
                     transform: SurfaceTransform, alpha: CompositeAlpha, mode: PresentMode,
                     clipped: bool) -> Result<(Arc<Swapchain>, Vec<ImagePrototype<Type2d, F, SwapchainAllocatedChunk>>), OomError>
        where F: FormatMarker, S: Into<SharingMode>
    {
        // FIXME: check that the parameters are supported

        // FIXME: check that the device and the surface belong to the same instance
        let vk = device.pointers();

        assert!(usage.color_attachment);
        let usage = usage.to_usage_bits();

        let sharing = sharing.into();

        let swapchain = unsafe {
            let (sh_mode, sh_count, sh_indices) = match sharing {
                SharingMode::Exclusive(id) => (vk::SHARING_MODE_EXCLUSIVE, 0, ptr::null()),
                SharingMode::Concurrent(ref ids) => (vk::SHARING_MODE_CONCURRENT, ids.len() as u32,
                                                     ids.as_ptr()),
            };

            let infos = vk::SwapchainCreateInfoKHR {
                sType: vk::STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR,
                pNext: ptr::null(),
                flags: 0,   // reserved
                surface: surface.internal_object(),
                minImageCount: num_images,
                imageFormat: F::format() as u32,
                imageColorSpace: vk::COLORSPACE_SRGB_NONLINEAR_KHR,     // only available value
                imageExtent: vk::Extent2D { width: dimensions[0], height: dimensions[1] },
                imageArrayLayers: layers,
                imageUsage: usage,
                imageSharingMode: sh_mode,
                queueFamilyIndexCount: sh_count,
                pQueueFamilyIndices: sh_indices,
                preTransform: transform as u32,
                compositeAlpha: alpha as u32,
                presentMode: mode as u32,
                clipped: if clipped { vk::TRUE } else { vk::FALSE },
                oldSwapchain: 0,      // TODO:
            };

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

        let swapchain = Arc::new(Swapchain {
            device: device.clone(),
            surface: surface.clone(),
            swapchain: swapchain,
            images_semaphores: Mutex::new(Vec::new()),
        });

        let images = unsafe {
            let mut num = mem::uninitialized();
            try!(check_errors(vk.GetSwapchainImagesKHR(device.internal_object(),
                                                       swapchain.swapchain, &mut num,
                                                       ptr::null_mut())));

            let mut images = Vec::with_capacity(num as usize);
            try!(check_errors(vk.GetSwapchainImagesKHR(device.internal_object(),
                                                       swapchain.swapchain, &mut num,
                                                       images.as_mut_ptr())));
            images.set_len(num as usize);
            images
        };

        let images = images.into_iter().enumerate().map(|(id, image)| unsafe {
            let mem = SwapchainAllocatedChunk { swapchain: swapchain.clone(), id: id };
            Image::from_raw_unowned(&device, image, mem, sharing.clone(), usage, dimensions, (), 1)
        }).collect::<Vec<_>>();

        {
            let mut semaphores = swapchain.images_semaphores.lock().unwrap();
            for _ in 0 .. images.len() {
                semaphores.push(None);
            }
        }

        Ok((swapchain, images))
    }

    /// Tries to take ownership of an image in order to draw on it.
    ///
    /// The function returns the index of the image in the array of images that was returned
    /// when creating the swapchain.
    ///
    /// If you try to draw on an image without acquiring it first, the execution will block. (TODO
    /// behavior may change).
    pub fn acquire_next_image(&self, timeout_ns: u64) -> Result<usize, AcquireError> {
        let vk = self.device.pointers();

        unsafe {
            let semaphore = Semaphore::new(&self.device).unwrap();      // TODO: error

            let mut out = mem::uninitialized();
            let r = try!(check_errors(vk.AcquireNextImageKHR(self.device.internal_object(),
                                                             self.swapchain, timeout_ns,
                                                             semaphore.internal_object(), 0,     // TODO: timeout
                                                             &mut out)));

            let id = match r {
                Success::Success => out as usize,
                Success::Suboptimal => out as usize,        // TODO: give that info to the user
                Success::NotReady => return Err(AcquireError::Timeout),
                Success::Timeout => return Err(AcquireError::Timeout),
                s => panic!("unexpected success value: {:?}", s)
            };

            let mut images_semaphores = self.images_semaphores.lock().unwrap();
            images_semaphores[id] = Some(semaphore);

            Ok(id)
        }
    }

    /// Presents an image on the screen.
    ///
    /// The parameter is the same index as what `acquire_next_image` returned. The image must
    /// have been acquired first.
    ///
    /// The actual behavior depends on the present mode that you passed when creating the
    /// swapchain.
    pub fn present(&self, queue: &mut Queue, index: usize) -> Result<(), OomError> {     // FIXME: wrong error
        let vk = self.device.pointers();

        let wait_semaphore = {
            let mut images_semaphores = self.images_semaphores.lock().unwrap();
            images_semaphores[index].take()
        };

        // FIXME: the semaphore will be destroyed ; need to return it

        unsafe {
            let mut result = mem::uninitialized();

            let index = index as u32;
            let infos = vk::PresentInfoKHR {
                sType: vk::STRUCTURE_TYPE_PRESENT_INFO_KHR,
                pNext: ptr::null(),
                waitSemaphoreCount: if let Some(_) = wait_semaphore { 1 } else { 0 },
                pWaitSemaphores: if let Some(ref sem) = wait_semaphore { &sem.internal_object() } else { ptr::null() },
                swapchainCount: 1,
                pSwapchains: &self.swapchain,
                pImageIndices: &index,
                pResults: &mut result,
            };

            try!(check_errors(vk.QueuePresentKHR(queue.internal_object(), &infos)));
            try!(check_errors(result));
            Ok(())
        }
    }
}

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

/// Error that can happen when calling `acquire_next_image`.
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
#[repr(u32)]
pub enum AcquireError {
    Timeout,
    SurfaceLost,
    OutOfDate,
}

impl error::Error for AcquireError {
    #[inline]
    fn description(&self) -> &str {
        match *self {
            AcquireError::Timeout => "no image is available for acquiring yet",
            AcquireError::SurfaceLost => "the surface of this swapchain is no longer valid",
            AcquireError::OutOfDate => "the swapchain needs to be recreated",
        }
    }
}

impl fmt::Display for AcquireError {
    #[inline]
    fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        write!(fmt, "{}", error::Error::description(self))
    }
}

impl From<Error> for AcquireError {
    #[inline]
    fn from(err: Error) -> AcquireError {
        match err {
            Error::SurfaceLost => AcquireError::SurfaceLost,
            Error::OutOfDate => AcquireError::OutOfDate,
            _ => panic!("unexpected error: {:?}", err)
        }
    }
}

/// "Dummy" object used for images that indicates that they were allocated as part of a swapchain.
pub struct SwapchainAllocatedChunk {
    swapchain: Arc<Swapchain>,
    id: usize,
}

// FIXME: needs correct synchronization as well
unsafe impl MemorySourceChunk for SwapchainAllocatedChunk {
    #[inline]
    fn properties(&self) -> ChunkProperties {
        unreachable!()
    }

    #[inline]
    fn requires_fence(&self) -> bool { false }
    #[inline]
    fn requires_semaphore(&self) -> bool { true }
    #[inline]
    fn may_alias(&self) -> bool { false }

    #[inline]
    fn gpu_access(&self, _: bool, _: ChunkRange, _: &mut Queue, _: Option<Arc<Fence>>,
                  post_semaphore: Option<Arc<Semaphore>>) -> Option<Arc<Semaphore>>
    {
        assert!(post_semaphore.is_some());
        // FIXME: must also check that image has been acquired
        let mut semaphores = self.swapchain.images_semaphores.lock().unwrap();
        let pre_semaphore = mem::replace(&mut semaphores[self.id], post_semaphore);
        pre_semaphore
    }
}
<commit_msg>Add draft in swapchain<commit_after>use std::error;
use std::fmt;
use std::mem;
use std::ptr;
use std::sync::Arc;
use std::sync::Mutex;

use device::Device;
use device::Queue;
use formats::FormatMarker;
use image::Image;
use image::ImagePrototype;
use image::Type2d;
use image::Usage as ImageUsage;
use memory::ChunkProperties;
use memory::ChunkRange;
use memory::MemorySourceChunk;
use swapchain::CompositeAlpha;
use swapchain::PresentMode;
use swapchain::Surface;
use swapchain::SurfaceTransform;
use sync::Fence;
use sync::Semaphore;
use sync::SharingMode;

use check_errors;
use Error;
use OomError;
use Success;
use VulkanObject;
use VulkanPointers;
use vk;

/// Contains the swapping system and the images that can be shown on a surface.
pub struct Swapchain {
    device: Arc<Device>,
    surface: Arc<Surface>,
    swapchain: vk::SwapchainKHR,

    images_semaphores: Mutex<Vec<Option<Arc<Semaphore>>>>,
}

impl Swapchain {
    /// Builds a new swapchain. Allocates images who content can be made visible on a surface.
    ///
    /// See also the `Surface::get_capabilities` function which returns the values that are
    /// supported by the implementation. All the parameters that you pass to `Swapchain::new`
    /// must be supported.
    ///
    /// The `clipped` parameter indicates whether the implementation is allowed to discard
    /// rendering operations that affect regions of the surface which aren't visible. This is
    /// important to take into account if your fragment shader has side-effects or if you want to
    /// read back the content of the image afterwards.
    ///
    /// This function returns the swapchain plus a list of the images that belong to the
    /// swapchain. The order in which the images are returned is important for the
    /// `acquire_next_image` and `present` functions.
    ///
    /// # Panic
    ///
    /// - Panicks if the device and the surface don't belong to the same instance.
    /// - Panicks if `color_attachment` is false in `usage`.
    ///
    pub fn new<F, S>(device: &Arc<Device>, surface: &Arc<Surface>, num_images: u32, format: F,
                     dimensions: [u32; 2], layers: u32, usage: &ImageUsage, sharing: S,
                     transform: SurfaceTransform, alpha: CompositeAlpha, mode: PresentMode,
                     clipped: bool) -> Result<(Arc<Swapchain>, Vec<ImagePrototype<Type2d, F, SwapchainAllocatedChunk>>), OomError>
        where F: FormatMarker, S: Into<SharingMode>
    {
        Swapchain::new_inner(device, surface, num_images, format, dimensions, layers, usage,
                             sharing, transform, alpha, mode, clipped)
    }

    // TODO:
    //pub fn recreate() { ... }

    fn new_inner<F, S>(device: &Arc<Device>, surface: &Arc<Surface>, num_images: u32, format: F,
                       dimensions: [u32; 2], layers: u32, usage: &ImageUsage, sharing: S,
                       transform: SurfaceTransform, alpha: CompositeAlpha, mode: PresentMode,
                       clipped: bool) -> Result<(Arc<Swapchain>, Vec<ImagePrototype<Type2d, F, SwapchainAllocatedChunk>>), OomError>
        where F: FormatMarker, S: Into<SharingMode>
    {
        // FIXME: check that the parameters are supported

        // FIXME: check that the device and the surface belong to the same instance
        let vk = device.pointers();

        assert!(usage.color_attachment);
        let usage = usage.to_usage_bits();

        let sharing = sharing.into();

        let swapchain = unsafe {
            let (sh_mode, sh_count, sh_indices) = match sharing {
                SharingMode::Exclusive(id) => (vk::SHARING_MODE_EXCLUSIVE, 0, ptr::null()),
                SharingMode::Concurrent(ref ids) => (vk::SHARING_MODE_CONCURRENT, ids.len() as u32,
                                                     ids.as_ptr()),
            };

            let infos = vk::SwapchainCreateInfoKHR {
                sType: vk::STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR,
                pNext: ptr::null(),
                flags: 0,   // reserved
                surface: surface.internal_object(),
                minImageCount: num_images,
                imageFormat: F::format() as u32,
                imageColorSpace: vk::COLORSPACE_SRGB_NONLINEAR_KHR,     // only available value
                imageExtent: vk::Extent2D { width: dimensions[0], height: dimensions[1] },
                imageArrayLayers: layers,
                imageUsage: usage,
                imageSharingMode: sh_mode,
                queueFamilyIndexCount: sh_count,
                pQueueFamilyIndices: sh_indices,
                preTransform: transform as u32,
                compositeAlpha: alpha as u32,
                presentMode: mode as u32,
                clipped: if clipped { vk::TRUE } else { vk::FALSE },
                oldSwapchain: 0,      // TODO:
            };

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

        let swapchain = Arc::new(Swapchain {
            device: device.clone(),
            surface: surface.clone(),
            swapchain: swapchain,
            images_semaphores: Mutex::new(Vec::new()),
        });

        let images = unsafe {
            let mut num = mem::uninitialized();
            try!(check_errors(vk.GetSwapchainImagesKHR(device.internal_object(),
                                                       swapchain.swapchain, &mut num,
                                                       ptr::null_mut())));

            let mut images = Vec::with_capacity(num as usize);
            try!(check_errors(vk.GetSwapchainImagesKHR(device.internal_object(),
                                                       swapchain.swapchain, &mut num,
                                                       images.as_mut_ptr())));
            images.set_len(num as usize);
            images
        };

        let images = images.into_iter().enumerate().map(|(id, image)| unsafe {
            let mem = SwapchainAllocatedChunk { swapchain: swapchain.clone(), id: id };
            Image::from_raw_unowned(&device, image, mem, sharing.clone(), usage, dimensions, (), 1)
        }).collect::<Vec<_>>();

        {
            let mut semaphores = swapchain.images_semaphores.lock().unwrap();
            for _ in 0 .. images.len() {
                semaphores.push(None);
            }
        }

        Ok((swapchain, images))
    }

    /// Tries to take ownership of an image in order to draw on it.
    ///
    /// The function returns the index of the image in the array of images that was returned
    /// when creating the swapchain.
    ///
    /// If you try to draw on an image without acquiring it first, the execution will block. (TODO
    /// behavior may change).
    pub fn acquire_next_image(&self, timeout_ns: u64) -> Result<usize, AcquireError> {
        let vk = self.device.pointers();

        unsafe {
            let semaphore = Semaphore::new(&self.device).unwrap();      // TODO: error

            let mut out = mem::uninitialized();
            let r = try!(check_errors(vk.AcquireNextImageKHR(self.device.internal_object(),
                                                             self.swapchain, timeout_ns,
                                                             semaphore.internal_object(), 0,     // TODO: timeout
                                                             &mut out)));

            let id = match r {
                Success::Success => out as usize,
                Success::Suboptimal => out as usize,        // TODO: give that info to the user
                Success::NotReady => return Err(AcquireError::Timeout),
                Success::Timeout => return Err(AcquireError::Timeout),
                s => panic!("unexpected success value: {:?}", s)
            };

            let mut images_semaphores = self.images_semaphores.lock().unwrap();
            images_semaphores[id] = Some(semaphore);

            Ok(id)
        }
    }

    /// Presents an image on the screen.
    ///
    /// The parameter is the same index as what `acquire_next_image` returned. The image must
    /// have been acquired first.
    ///
    /// The actual behavior depends on the present mode that you passed when creating the
    /// swapchain.
    pub fn present(&self, queue: &mut Queue, index: usize) -> Result<(), OomError> {     // FIXME: wrong error
        let vk = self.device.pointers();

        let wait_semaphore = {
            let mut images_semaphores = self.images_semaphores.lock().unwrap();
            images_semaphores[index].take()
        };

        // FIXME: the semaphore will be destroyed ; need to return it

        unsafe {
            let mut result = mem::uninitialized();

            let index = index as u32;
            let infos = vk::PresentInfoKHR {
                sType: vk::STRUCTURE_TYPE_PRESENT_INFO_KHR,
                pNext: ptr::null(),
                waitSemaphoreCount: if let Some(_) = wait_semaphore { 1 } else { 0 },
                pWaitSemaphores: if let Some(ref sem) = wait_semaphore { &sem.internal_object() } else { ptr::null() },
                swapchainCount: 1,
                pSwapchains: &self.swapchain,
                pImageIndices: &index,
                pResults: &mut result,
            };

            try!(check_errors(vk.QueuePresentKHR(queue.internal_object(), &infos)));
            try!(check_errors(result));
            Ok(())
        }
    }
}

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

/// Error that can happen when calling `acquire_next_image`.
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
#[repr(u32)]
pub enum AcquireError {
    Timeout,
    SurfaceLost,
    OutOfDate,
}

impl error::Error for AcquireError {
    #[inline]
    fn description(&self) -> &str {
        match *self {
            AcquireError::Timeout => "no image is available for acquiring yet",
            AcquireError::SurfaceLost => "the surface of this swapchain is no longer valid",
            AcquireError::OutOfDate => "the swapchain needs to be recreated",
        }
    }
}

impl fmt::Display for AcquireError {
    #[inline]
    fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        write!(fmt, "{}", error::Error::description(self))
    }
}

impl From<Error> for AcquireError {
    #[inline]
    fn from(err: Error) -> AcquireError {
        match err {
            Error::SurfaceLost => AcquireError::SurfaceLost,
            Error::OutOfDate => AcquireError::OutOfDate,
            _ => panic!("unexpected error: {:?}", err)
        }
    }
}

/// "Dummy" object used for images that indicates that they were allocated as part of a swapchain.
pub struct SwapchainAllocatedChunk {
    swapchain: Arc<Swapchain>,
    id: usize,
}

// FIXME: needs correct synchronization as well
unsafe impl MemorySourceChunk for SwapchainAllocatedChunk {
    #[inline]
    fn properties(&self) -> ChunkProperties {
        unreachable!()
    }

    #[inline]
    fn requires_fence(&self) -> bool { false }
    #[inline]
    fn requires_semaphore(&self) -> bool { true }
    #[inline]
    fn may_alias(&self) -> bool { false }

    #[inline]
    fn gpu_access(&self, _: bool, _: ChunkRange, _: &mut Queue, _: Option<Arc<Fence>>,
                  post_semaphore: Option<Arc<Semaphore>>) -> Option<Arc<Semaphore>>
    {
        assert!(post_semaphore.is_some());
        // FIXME: must also check that image has been acquired
        let mut semaphores = self.swapchain.images_semaphores.lock().unwrap();
        let pre_semaphore = mem::replace(&mut semaphores[self.id], post_semaphore);
        pre_semaphore
    }
}
<|endoftext|>


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

use dom::bindings::codegen::Bindings::CSSStyleDeclarationBinding::{self, CSSStyleDeclarationMethods};
use dom::bindings::codegen::InheritTypes::{NodeCast, ElementCast};
use dom::bindings::error::Error;
use dom::bindings::error::ErrorResult;
use dom::bindings::error::Fallible;
use dom::bindings::global::GlobalRef;
use dom::bindings::js::{JS, JSRef, OptionalRootedRootable, Temporary};
use dom::bindings::utils::{Reflector, reflect_dom_object};
use dom::document::DocumentHelpers;
use dom::element::{Element, ElementHelpers, StylePriority};
use dom::htmlelement::HTMLElement;
use dom::node::{window_from_node, document_from_node, NodeDamage, Node};
use dom::window::{Window, WindowHelpers};
use util::str::DOMString;
use string_cache::Atom;
use style::properties::{is_supported_property, longhands_from_shorthand, parse_style_attribute};
use style::properties::PropertyDeclaration;

use std::ascii::AsciiExt;
use std::borrow::ToOwned;

#[dom_struct]
pub struct CSSStyleDeclaration {
    reflector_: Reflector,
    owner: JS<HTMLElement>,
    readonly: bool,
}

#[derive(PartialEq)]
pub enum CSSModificationAccess {
    ReadWrite,
    Readonly
}

macro_rules! css_properties(
    ( $([$getter:ident, $setter:ident, $cssprop:expr]),* ) => (
        $(
            fn $getter(self) -> DOMString {
                self.GetPropertyValue($cssprop.to_owned())
            }
            fn $setter(self, value: DOMString) {
                self.SetPropertyValue($cssprop.to_owned(), value).unwrap();
            }
        )*
    );
);

fn serialize_list(list: &Vec<PropertyDeclaration>) -> DOMString {
    let mut result = String::new();
    for declaration in list.iter() {
        result.push_str(&serialize_value(declaration));
        result.push_str(" ");
    }
    result
}

fn serialize_value(declaration: &PropertyDeclaration) -> DOMString {
    declaration.value()
}

impl CSSStyleDeclaration {
    pub fn new_inherited(owner: JSRef<HTMLElement>, modification_access: CSSModificationAccess) -> CSSStyleDeclaration {
        CSSStyleDeclaration {
            reflector_: Reflector::new(),
            owner: JS::from_rooted(owner),
            readonly: modification_access == CSSModificationAccess::Readonly,
        }
    }

    pub fn new(global: JSRef<Window>, owner: JSRef<HTMLElement>, modification_access: CSSModificationAccess) -> Temporary<CSSStyleDeclaration> {
        reflect_dom_object(box CSSStyleDeclaration::new_inherited(owner, modification_access),
                           GlobalRef::Window(global),
                           CSSStyleDeclarationBinding::Wrap)
    }
}

trait PrivateCSSStyleDeclarationHelpers {
    fn get_declaration(self, property: &Atom) -> Option<PropertyDeclaration>;
    fn get_important_declaration(self, property: &Atom) -> Option<PropertyDeclaration>;
}

impl<'a> PrivateCSSStyleDeclarationHelpers for JSRef<'a, CSSStyleDeclaration> {
    fn get_declaration(self, property: &Atom) -> Option<PropertyDeclaration> {
        let owner = self.owner.root();
        let element: JSRef<Element> = ElementCast::from_ref(owner.r());
        element.get_inline_style_declaration(property).map(|decl| decl.clone())
    }

    fn get_important_declaration(self, property: &Atom) -> Option<PropertyDeclaration> {
        let owner = self.owner.root();
        let element: JSRef<Element> = ElementCast::from_ref(owner.r());
        element.get_important_inline_style_declaration(property).map(|decl| decl.clone())
    }
}

impl<'a> CSSStyleDeclarationMethods for JSRef<'a, CSSStyleDeclaration> {
    fn Length(self) -> u32 {
        let owner = self.owner.root();
        let elem: JSRef<Element> = ElementCast::from_ref(owner.r());
        let len = match *elem.style_attribute().borrow() {
            Some(ref declarations) => declarations.normal.len() + declarations.important.len(),
            None => 0
        };
        len as u32
    }

    fn Item(self, index: u32) -> DOMString {
        let index = index as usize;
        let owner = self.owner.root();
        let elem: JSRef<Element> = ElementCast::from_ref(owner.r());
        let style_attribute = elem.style_attribute().borrow();
        let result = style_attribute.as_ref().and_then(|declarations| {
            if index > declarations.normal.len() {
                declarations.important
                            .get(index - declarations.normal.len())
                            .map(|decl| format!("{:?} !important", decl))
            } else {
                declarations.normal
                            .get(index)
                            .map(|decl| format!("{:?}", decl))
            }
        });

        result.unwrap_or("".to_owned())
    }

    // http://dev.w3.org/csswg/cssom/#dom-cssstyledeclaration-getpropertyvalue
    fn GetPropertyValue(self, property: DOMString) -> DOMString {
        // Step 1
        let property = Atom::from_slice(&property.to_ascii_lowercase());

        // Step 2
        let longhand_properties = longhands_from_shorthand(&property);
        if let Some(longhand_properties) = longhand_properties {
            // Step 2.1
            let mut list = vec!();

            // Step 2.2
            for longhand in longhand_properties.iter() {
                // Step 2.2.1
                let declaration = self.get_declaration(&Atom::from_slice(&longhand));

                // Step 2.2.2 & 2.2.3
                match declaration {
                    Some(declaration) => list.push(declaration),
                    None => return "".to_owned(),
                }
            }

            // Step 2.3
            return serialize_list(&list);
        }

        // Step 3 & 4
        if let Some(ref declaration) = self.get_declaration(&property) {
            serialize_value(declaration)
        } else {
            "".to_owned()
        }
    }

    // http://dev.w3.org/csswg/cssom/#dom-cssstyledeclaration-getpropertypriority
    fn GetPropertyPriority(self, property: DOMString) -> DOMString {
        // Step 1
        let property = Atom::from_slice(&property.to_ascii_lowercase());

        // Step 2
        let longhand_properties = longhands_from_shorthand(&property);
        if let Some(longhand_properties) = longhand_properties {
            // Step 2.1 & 2.2 & 2.3
            if longhand_properties.iter()
                                  .map(|longhand| self.GetPropertyPriority(longhand.clone()))
                                  .all(|priority| priority == "important") {

                return "important".to_owned();
            }
        // Step 3
        } else if self.get_important_declaration(&property).is_some() {
            return "important".to_owned();
        }

        // Step 4
        "".to_owned()
    }

    // http://dev.w3.org/csswg/cssom/#dom-cssstyledeclaration-setproperty
    fn SetProperty(self, property: DOMString, value: DOMString,
                   priority: DOMString) -> ErrorResult {
        // Step 1
        if self.readonly {
            return Err(Error::NoModificationAllowedError);
        }

        // Step 2
        let property = property.to_ascii_lowercase();

        // Step 3
        if !is_supported_property(&property) {
            return Ok(());
        }

        // Step 4
        if value.is_empty() {
            return self.RemoveProperty(property).map(|_| ());
        }

        // Step 5
        let priority = priority.to_ascii_lowercase();
        if priority != "!important" && !priority.is_empty() {
            return Ok(());
        }

        // Step 6
        let mut synthesized_declaration = String::from_str(&property);
        synthesized_declaration.push_str(": ");
        synthesized_declaration.push_str(&value);

        let owner = self.owner.root();
        let window = window_from_node(owner.r()).root();
        let decl_block = parse_style_attribute(&synthesized_declaration, &window.r().get_url());

        // Step 7
        if decl_block.normal.len() == 0 {
            return Ok(());
        }

        let owner = self.owner.root();
        let element: JSRef<Element> = ElementCast::from_ref(owner.r());

        // Step 8
        for decl in decl_block.normal.iter() {
            // Step 9
            let style_priority = if priority.is_empty() { StylePriority::Normal } else { StylePriority::Important };
            element.update_inline_style(decl.clone(), style_priority);
        }

        let document = document_from_node(element).root();
        let node: JSRef<Node> = NodeCast::from_ref(element);
        document.r().content_changed(node, NodeDamage::NodeStyleDamaged);
        Ok(())
    }

    // http://dev.w3.org/csswg/cssom/#dom-cssstyledeclaration-setpropertypriority
    fn SetPropertyPriority(self, property: DOMString, priority: DOMString) -> ErrorResult {
        // Step 1
        if self.readonly {
            return Err(Error::NoModificationAllowedError);
        }

        // Step 2
        let property = property.to_ascii_lowercase();

        // Step 3
        if !is_supported_property(&property) {
            return Ok(());
        }

        // Step 4
        let priority = priority.to_ascii_lowercase();
        if priority != "important" && !priority.is_empty() {
            return Ok(());
        }

        let owner = self.owner.root();
        let window = window_from_node(owner.r()).root();
        let decl_block = parse_style_attribute(&property, &window.r().get_url());
        let element: JSRef<Element> = ElementCast::from_ref(owner.r());

        // Step 5
        for decl in decl_block.normal.iter() {
            // Step 6
            let style_priority = if priority.is_empty() { StylePriority::Normal } else { StylePriority::Important };
            element.update_inline_style(decl.clone(), style_priority);
        }

        let document = document_from_node(element).root();
        let node: JSRef<Node> = NodeCast::from_ref(element);
        document.r().content_changed(node, NodeDamage::NodeStyleDamaged);
        Ok(())
    }

    // http://dev.w3.org/csswg/cssom/#dom-cssstyledeclaration-setpropertyvalue
    fn SetPropertyValue(self, property: DOMString, value: DOMString) -> ErrorResult {
        self.SetProperty(property, value, "".to_owned())
    }

    // http://dev.w3.org/csswg/cssom/#dom-cssstyledeclaration-removeproperty
    fn RemoveProperty(self, property: DOMString) -> Fallible<DOMString> {
        // Step 1
        if self.readonly {
            return Err(Error::NoModificationAllowedError);
        }

        // Step 2
        let property = property.to_ascii_lowercase();

        // Step 3
        let value = self.GetPropertyValue(property.clone());

        let longhand_properties = longhands_from_shorthand(&property);
        match longhand_properties {
            Some(longhands) => {
                // Step 4
                for longhand in longhands.iter() {
                    try!(self.RemoveProperty(longhand.clone()));
                }
            }

            None => {
                // Step 5
                let owner = self.owner.root();
                let elem: JSRef<Element> = ElementCast::from_ref(owner.r());
                elem.remove_inline_style_property(property)
            }
        }

        // Step 6
        Ok(value)
    }

    // http://dev.w3.org/csswg/cssom/#dom-cssstyledeclaration-cssfloat
    fn CssFloat(self) -> DOMString {
        self.GetPropertyValue("float".to_owned())
    }

    // http://dev.w3.org/csswg/cssom/#dom-cssstyledeclaration-cssfloat
    fn SetCssFloat(self, value: DOMString) -> ErrorResult {
        self.SetPropertyValue("float".to_owned(), value)
    }

    fn IndexedGetter(self, index: u32, found: &mut bool) -> DOMString {
        let rval = self.Item(index);
        *found = index < self.Length();
        rval
    }

    css_properties_accessors!(css_properties);
}
<commit_msg>auto merge of #5451 : frewsxcv/servo/cleanup-css-style-declarations, r=Ms2ger<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use dom::bindings::codegen::Bindings::CSSStyleDeclarationBinding::{self, CSSStyleDeclarationMethods};
use dom::bindings::codegen::InheritTypes::{NodeCast, ElementCast};
use dom::bindings::error::{Error, ErrorResult, Fallible};
use dom::bindings::global::GlobalRef;
use dom::bindings::js::{JS, JSRef, OptionalRootedRootable, Temporary};
use dom::bindings::utils::{Reflector, reflect_dom_object};
use dom::document::DocumentHelpers;
use dom::element::{Element, ElementHelpers, StylePriority};
use dom::htmlelement::HTMLElement;
use dom::node::{window_from_node, document_from_node, NodeDamage, Node};
use dom::window::{Window, WindowHelpers};
use util::str::DOMString;
use string_cache::Atom;
use style::properties::{is_supported_property, longhands_from_shorthand, parse_style_attribute};
use style::properties::PropertyDeclaration;

use std::ascii::AsciiExt;
use std::borrow::ToOwned;

#[dom_struct]
pub struct CSSStyleDeclaration {
    reflector_: Reflector,
    owner: JS<HTMLElement>,
    readonly: bool,
}

#[derive(PartialEq)]
pub enum CSSModificationAccess {
    ReadWrite,
    Readonly
}

macro_rules! css_properties(
    ( $([$getter:ident, $setter:ident, $cssprop:expr]),* ) => (
        $(
            fn $getter(self) -> DOMString {
                self.GetPropertyValue($cssprop.to_owned())
            }
            fn $setter(self, value: DOMString) {
                self.SetPropertyValue($cssprop.to_owned(), value).unwrap();
            }
        )*
    );
);

fn serialize_list(list: &Vec<PropertyDeclaration>) -> DOMString {
    list.iter().fold(String::new(), |accum, ref declaration| {
        accum + &declaration.value() + " "
    })
}

impl CSSStyleDeclaration {
    pub fn new_inherited(owner: JSRef<HTMLElement>,
                         modification_access: CSSModificationAccess) -> CSSStyleDeclaration {
        CSSStyleDeclaration {
            reflector_: Reflector::new(),
            owner: JS::from_rooted(owner),
            readonly: modification_access == CSSModificationAccess::Readonly,
        }
    }

    pub fn new(global: JSRef<Window>, owner: JSRef<HTMLElement>,
               modification_access: CSSModificationAccess) -> Temporary<CSSStyleDeclaration> {
        reflect_dom_object(box CSSStyleDeclaration::new_inherited(owner, modification_access),
                           GlobalRef::Window(global),
                           CSSStyleDeclarationBinding::Wrap)
    }
}

trait PrivateCSSStyleDeclarationHelpers {
    fn get_declaration(self, property: &Atom) -> Option<PropertyDeclaration>;
    fn get_important_declaration(self, property: &Atom) -> Option<PropertyDeclaration>;
}

impl<'a> PrivateCSSStyleDeclarationHelpers for JSRef<'a, CSSStyleDeclaration> {
    fn get_declaration(self, property: &Atom) -> Option<PropertyDeclaration> {
        let owner = self.owner.root();
        let element: JSRef<Element> = ElementCast::from_ref(owner.r());
        element.get_inline_style_declaration(property).map(|decl| decl.clone())
    }

    fn get_important_declaration(self, property: &Atom) -> Option<PropertyDeclaration> {
        let owner = self.owner.root();
        let element: JSRef<Element> = ElementCast::from_ref(owner.r());
        element.get_important_inline_style_declaration(property).map(|decl| decl.clone())
    }
}

impl<'a> CSSStyleDeclarationMethods for JSRef<'a, CSSStyleDeclaration> {
    // http://dev.w3.org/csswg/cssom/#dom-cssstyledeclaration-length
    fn Length(self) -> u32 {
        let owner = self.owner.root();
        let elem: JSRef<Element> = ElementCast::from_ref(owner.r());
        let len = match *elem.style_attribute().borrow() {
            Some(ref declarations) => declarations.normal.len() + declarations.important.len(),
            None => 0
        };
        len as u32
    }

    // http://dev.w3.org/csswg/cssom/#dom-cssstyledeclaration-item
    fn Item(self, index: u32) -> DOMString {
        let index = index as usize;
        let owner = self.owner.root();
        let elem: JSRef<Element> = ElementCast::from_ref(owner.r());
        let style_attribute = elem.style_attribute().borrow();
        let result = style_attribute.as_ref().and_then(|declarations| {
            if index > declarations.normal.len() {
                declarations.important
                            .get(index - declarations.normal.len())
                            .map(|decl| format!("{:?} !important", decl))
            } else {
                declarations.normal
                            .get(index)
                            .map(|decl| format!("{:?}", decl))
            }
        });

        result.unwrap_or("".to_owned())
    }

    // http://dev.w3.org/csswg/cssom/#dom-cssstyledeclaration-getpropertyvalue
    fn GetPropertyValue(self, property: DOMString) -> DOMString {
        // Step 1
        let property = Atom::from_slice(&property.to_ascii_lowercase());

        // Step 2
        let longhand_properties = longhands_from_shorthand(&property);
        if let Some(longhand_properties) = longhand_properties {
            // Step 2.1
            let mut list = vec!();

            // Step 2.2
            for longhand in longhand_properties.iter() {
                // Step 2.2.1
                let declaration = self.get_declaration(&Atom::from_slice(&longhand));

                // Step 2.2.2 & 2.2.3
                match declaration {
                    Some(declaration) => list.push(declaration),
                    None => return "".to_owned(),
                }
            }

            // Step 2.3
            return serialize_list(&list);
        }

        // Step 3 & 4
        if let Some(ref declaration) = self.get_declaration(&property) {
            declaration.value()
        } else {
            "".to_owned()
        }
    }

    // http://dev.w3.org/csswg/cssom/#dom-cssstyledeclaration-getpropertypriority
    fn GetPropertyPriority(self, property: DOMString) -> DOMString {
        // Step 1
        let property = Atom::from_slice(&property.to_ascii_lowercase());

        // Step 2
        let longhand_properties = longhands_from_shorthand(&property);
        if let Some(longhand_properties) = longhand_properties {
            // Step 2.1 & 2.2 & 2.3
            if longhand_properties.iter()
                                  .map(|longhand| self.GetPropertyPriority(longhand.clone()))
                                  .all(|priority| priority == "important") {

                return "important".to_owned();
            }
        // Step 3
        } else if self.get_important_declaration(&property).is_some() {
            return "important".to_owned();
        }

        // Step 4
        "".to_owned()
    }

    // http://dev.w3.org/csswg/cssom/#dom-cssstyledeclaration-setproperty
    fn SetProperty(self, property: DOMString, value: DOMString,
                   priority: DOMString) -> ErrorResult {
        // Step 1
        if self.readonly {
            return Err(Error::NoModificationAllowedError);
        }

        // Step 2
        let property = property.to_ascii_lowercase();

        // Step 3
        if !is_supported_property(&property) {
            return Ok(());
        }

        // Step 4
        if value.is_empty() {
            return self.RemoveProperty(property).map(|_| ());
        }

        // Step 5
        let priority = priority.to_ascii_lowercase();
        if priority != "!important" && !priority.is_empty() {
            return Ok(());
        }

        // Step 6
        let mut synthesized_declaration = String::from_str(&property);
        synthesized_declaration.push_str(": ");
        synthesized_declaration.push_str(&value);

        let owner = self.owner.root();
        let window = window_from_node(owner.r()).root();
        let decl_block = parse_style_attribute(&synthesized_declaration, &window.r().get_url());

        // Step 7
        if decl_block.normal.len() == 0 {
            return Ok(());
        }

        let owner = self.owner.root();
        let element: JSRef<Element> = ElementCast::from_ref(owner.r());

        // Step 8
        for decl in decl_block.normal.iter() {
            // Step 9
            let style_priority = if priority.is_empty() {
                StylePriority::Normal
            } else {
                StylePriority::Important
            };
            element.update_inline_style(decl.clone(), style_priority);
        }

        let document = document_from_node(element).root();
        let node: JSRef<Node> = NodeCast::from_ref(element);
        document.r().content_changed(node, NodeDamage::NodeStyleDamaged);
        Ok(())
    }

    // http://dev.w3.org/csswg/cssom/#dom-cssstyledeclaration-setpropertypriority
    fn SetPropertyPriority(self, property: DOMString, priority: DOMString) -> ErrorResult {
        // Step 1
        if self.readonly {
            return Err(Error::NoModificationAllowedError);
        }

        // Step 2
        let property = property.to_ascii_lowercase();

        // Step 3
        if !is_supported_property(&property) {
            return Ok(());
        }

        // Step 4
        let priority = priority.to_ascii_lowercase();
        if priority != "important" && !priority.is_empty() {
            return Ok(());
        }

        let owner = self.owner.root();
        let window = window_from_node(owner.r()).root();
        let decl_block = parse_style_attribute(&property, &window.r().get_url());
        let element: JSRef<Element> = ElementCast::from_ref(owner.r());

        // Step 5
        for decl in decl_block.normal.iter() {
            // Step 6
            let style_priority = if priority.is_empty() {
                StylePriority::Normal
            } else {
                StylePriority::Important
            };
            element.update_inline_style(decl.clone(), style_priority);
        }

        let document = document_from_node(element).root();
        let node: JSRef<Node> = NodeCast::from_ref(element);
        document.r().content_changed(node, NodeDamage::NodeStyleDamaged);
        Ok(())
    }

    // http://dev.w3.org/csswg/cssom/#dom-cssstyledeclaration-setpropertyvalue
    fn SetPropertyValue(self, property: DOMString, value: DOMString) -> ErrorResult {
        self.SetProperty(property, value, "".to_owned())
    }

    // http://dev.w3.org/csswg/cssom/#dom-cssstyledeclaration-removeproperty
    fn RemoveProperty(self, property: DOMString) -> Fallible<DOMString> {
        // Step 1
        if self.readonly {
            return Err(Error::NoModificationAllowedError);
        }

        // Step 2
        let property = property.to_ascii_lowercase();

        // Step 3
        let value = self.GetPropertyValue(property.clone());

        let longhand_properties = longhands_from_shorthand(&property);
        match longhand_properties {
            Some(longhands) => {
                // Step 4
                for longhand in longhands.iter() {
                    try!(self.RemoveProperty(longhand.clone()));
                }
            }

            None => {
                // Step 5
                let owner = self.owner.root();
                let elem: JSRef<Element> = ElementCast::from_ref(owner.r());
                elem.remove_inline_style_property(property)
            }
        }

        // Step 6
        Ok(value)
    }

    // http://dev.w3.org/csswg/cssom/#dom-cssstyledeclaration-cssfloat
    fn CssFloat(self) -> DOMString {
        self.GetPropertyValue("float".to_owned())
    }

    // http://dev.w3.org/csswg/cssom/#dom-cssstyledeclaration-cssfloat
    fn SetCssFloat(self, value: DOMString) -> ErrorResult {
        self.SetPropertyValue("float".to_owned(), value)
    }

    fn IndexedGetter(self, index: u32, found: &mut bool) -> DOMString {
        let rval = self.Item(index);
        *found = index < self.Length();
        rval
    }

    css_properties_accessors!(css_properties);
}
<|endoftext|>


<commit_before>#![feature(optin_builtin_traits)]
#![feature(clone_from_slice)]

//#[macro_use] extern crate gfx;
#[macro_use] extern crate lazy_static;
#[macro_use] extern crate log;
extern crate env_logger;
extern crate libc;
extern crate winapi;
extern crate dx_safe;
//extern crate dxguid_sys;
extern crate dxgi_sys;
extern crate kernel32;
extern crate user32;
//extern crate d3d12_sys;
extern crate rand;
extern crate clock_ticks;
extern crate cgmath;
extern crate crossbeam;

#[macro_use] mod macros;
mod create_device;
mod window;
mod structwrappers;
mod utils;
//mod gfx_d3d12;
mod shape_gen;
mod dxsems;
mod core;
mod app;
mod cubes;
mod camera;

use dxsems::VertexFormat;
use winapi::*;
use dx_safe::*;
use create_device::*;
use kernel32::{CreateEventW, WaitForSingleObject};
use std::ptr;
use std::fmt;
use std::mem;
use std::env;
use std::cell::RefCell;
use std::rc::Rc;
use std::sync::{Arc, Mutex};
use std::collections::HashMap;
use window::*;
use utils::*;
use clock_ticks::*;
use cgmath::*;
use core::*;
use std::sync::atomic::{AtomicUsize, Ordering};
use rand::Rng;
use cubes::{Parameters, CubeParms};

#[link(name="d3dcompiler")]
extern {}

const FRAME_COUNT : u32 = 4;

fn main() {
  // Initialize logger
  env_logger::init().unwrap();

  // Set default values of cubes module parameters
  let mut parms = CubeParms {thread_count: 2, object_count: 2_000,};
  let mut adapters_to_test = vec![];
  for arg in env::args() {
    if let Ok(n) = arg.parse::<u32>() {
      // If command line parameter is a number, treat it as a number of graphics adapter.
      adapters_to_test.push(n);
    }
    if arg.starts_with("-o") {
      // Command line parameter -o<N> sets number of objects to draw
      // Note, that 2 in arg[2..] is a number of bytes, not characters.
      if let Ok(n) = (&arg[2..]).parse::<u32>() {
        parms.object_count = n;
      }
    }
    if arg.starts_with("-t") {
      // Command line parameter -t<N> sets number of threads and graphics command lists
      // to use for sending workload to GPU
      if let Ok(n) = (&arg[2..]).parse::<u32>() {
        parms.thread_count = n;
      }
    }
  }

  let factory: DXGIFactory4 = create_dxgi_factory2().expect("Cannot create DXGIFactory4. No can do.");
  let mut i=0;
  let mut adapters = vec![];
  // Iterate over available GPUs
  while let Ok(adapter)=factory.enum_adapters1(i) {
    let descr=adapter.get_desc1().unwrap();
    println!("Adapter {}: {}", i, wchar_array_to_string_lossy(&descr.Description));
    println!("   Dedicated video memory: {}MiB", descr.DedicatedVideoMemory/1024/1024);
    if adapters_to_test.len()==0 || adapters_to_test[..].contains(&i) {
      // If there's no numbers in command line add each and every available adapter,
      // otherwise use adapter numbers from command line
      adapters.push(adapter);
    }
    // It's easy to forget this.
    i+=1;
  }

  // I used this mutex to sync console output.
  let mutex=Arc::new(Mutex::new(()));
  crossbeam::scope(|scope| {
    for (a,id) in adapters.into_iter().zip(0 ..) {
      let mutex = mutex.clone();
      let parms = &parms;
      scope.spawn(move||{
        // Spawn a thread for each adapter
        main_prime(id, a, mutex, parms)
      });
    };
  });
}

fn main_prime<T: Parameters>(id: u32, adapter: DXGIAdapter1, mutex: Arc<Mutex<()>>, parms: &T) {
  // Setup window. Currently window module supports only one window per thread.
  let descr=wchar_array_to_string_lossy(&adapter.get_desc1().unwrap().Description);
  let title=format!("D3D12 Hello, rusty world! ({})", descr);
  let wnd=create_window(&title, 512, 256);

  {
    // This block of code is not required. I just checked some stuff
    if let Ok(dev)=d3d12_create_device(Some(&adapter), D3D_FEATURE_LEVEL_12_1) {
      let format = DXGI_FORMAT_R8G8B8A8_UNORM_SRGB;
      let mut fsup = D3D12_FEATURE_DATA_FORMAT_SUPPORT {
        Format: format,
        Support1: D3D12_FORMAT_SUPPORT1_NONE,
        Support2: D3D12_FORMAT_SUPPORT2_NONE,
      };
      if let Ok(_) = dev.check_feature_support_format_support(&mut fsup) {
        // We could have few threads running, so take a lock to prevent line interleaving
        let lock=mutex.lock();
        println!("{}", descr);
        println!("Format support for {:?} is {:x}, {:x}", format, fsup.Support1.0, fsup.Support2.0);
      }
    }
  }

  // Initialization of cubes module data required to render all stuff
  let data=
    match cubes::AppData::on_init(&wnd, Some(&adapter), FRAME_COUNT, parms) {
      Ok(appdata) => {
        Rc::new(RefCell::new(appdata))
      },
      Err(iq) => {
        dump_info_queue(iq.map(|iq|iq).as_ref());
        return ();
      },
    };

  // x and y store last mouse coords from WM_MOUSEMOVE
  let mut x:i32=0;
  let mut y:i32=0;
  // TODO: Make this horror go away
  // Simple and crude way to track state of keyboard keys
  let (mut wdown, mut sdown, mut adown, mut ddown, mut qdown, mut edown) = (false, false, false, false, false, false);
  // and state of left mouse button
  let mut mouse_down = false;
  // Profiling stuff
  let mut frame_count = 0;
  let mut avg_fps = 0;
  let mut start = precise_time_s();
  let mut mstart = start;
  // Window::poll_events() returns non-blocking iterator, that return Option<MSG>
  for mmsg in wnd.poll_events() {
    // "if let Some(msg)" extracts msg from mmsg
    // if mmsg is None, then 'else' branch is taken
    if let Some(msg) = mmsg {
      // Instead of passing messages into cubes module, I process them here
      // It is not well-thought-out design decision, it's just slightly simpler now, and cost of changing it is low.
      match msg.message {
        // Usual message processing stuff
        WM_SIZE => {
          // Normally this message goes to wndproc, in window.rs I repost it into message queue to prevent reentrancy problems
          debug!("WM_SIZE {}, {}  ", msg.wParam, msg.lParam);
          data.borrow_mut().on_resize(LOWORD(msg.lParam as u32) as u32, HIWORD(msg.lParam as u32) as u32, msg.wParam as u32);
        },
        WM_MOUSEMOVE => {
          let x1 = GET_X_LPARAM(msg.lParam) as i32;
          let y1 = GET_Y_LPARAM(msg.lParam) as i32;
          let (dx, dy) = (x1 - x, y - y1);
          x = x1;
          y = y1;
          if mouse_down {
            let mut data = data.borrow_mut();
            let camera = data.camera();
            camera.rotx(-dx as f32/6.);
            camera.roty(-dy as f32/6.);
          }
        },
        WM_KEYDOWN => {
          match msg.wParam as u8 {
            b'A' => adown = true,
            b'S' => sdown = true,
            b'D' => ddown = true,
            b'W' => wdown = true,
            b'Q' => qdown = true,
            b'E' => edown = true,
            _ => {},
          }
        },
        WM_KEYUP => {
          match msg.wParam as u8 {
            b'A' => adown = false,
            b'S' => sdown = false,
            b'D' => ddown = false,
            b'W' => wdown = false,
            b'Q' => qdown = false,
            b'E' => edown = false,
            _ => {},
          }
        },
        WM_LBUTTONDOWN => {
          mouse_down = true;
          set_capture(wnd.get_hwnd());
        },
        WM_LBUTTONUP => {
          mouse_down = false;
          release_capture();
        },
        _ => {},
      };
    } else {
      let do_not_render = data.borrow().is_minimized();
      if do_not_render {
        // MSDN suggest to use MsgWaitForMultipleObjects here, but 10ms sleep shouldn't create problems
        std::thread::sleep_ms(10);
      } else {
        {
          // data is Rc<RefCell<cubes::AppData>>
          // Rc is not really needed. I didn't pass it around.
          // Take a mutable reference to cubes::AppData
          let mut data = data.borrow_mut();
          // Process WASD keys
          let camera = data.camera();
          if wdown {
            camera.go(0.1, 0., 0.);
          };
          if sdown {
            camera.go(-0.1, 0., 0.);
          };
          if adown {
            camera.go(0., 0.1, 0.); // Something wrong with signs. Negative value should translate camera to the left
          };
          if ddown {
            camera.go(0., -0.1, 0.);
          };
          // Process Q and E keys. They control camera's roll
          if qdown {
            camera.rotz(-0.5);
          };
          if edown {
            camera.rotz(0.5);
          };
        }
        // For this simple program I don't separate update and render steps.
        // State change and rendering is done inside on_render.
        // Error handling isn't implemented yet. on_render panics, if it needs to.
        // TODO: remove x,y parameters
        // TODO: process error
        data.borrow_mut().on_render(x, y);
        // register rendered frame in performance collector
        ::perf_frame();
        // fps counting stuff
        frame_count += 1;
        let now = precise_time_s();
        let frametime = now - mstart;
        mstart = now;
        if now<start || now>=(start+1.0) {
          // Once per second show stats
          let (clear, fill, exec, present, wait) =
            PERFDATA.with(|p_data| {
              let p_data = p_data.borrow();
              let frames = p_data.frames as f64;
              (p_data.perf.get("clear").unwrap()*1000./frames,
                p_data.perf.get("fillbuf").unwrap()*1000./frames,
                p_data.perf.get("exec").unwrap()*1000./frames,
                p_data.perf.get("present").unwrap()*1000./frames,
                p_data.perf.get("wait").unwrap()*1000./frames, )
            });
          println!("Adapter {} FPS: {:3} clear:{:4.2} fill:{:4.2} exec:{:4.2} present:{:4.2} wait:{:4.2}   \r", id, avg_fps, clear, fill, exec, present, wait);
          start = now;
          let _ = ::std::io::Write::flush(&mut ::std::io::stdout());
          avg_fps = frame_count;
          frame_count = 0;
        }
      }
    }
  }
  // Application should exit fullscreen state before terminating.
  data.borrow().set_fullscreen(false).unwrap();
  // copy info queue
  let iq=data.borrow().info_queue().clone();
  // wait for all GPU processing to stop
  data.borrow().wait_frame();
  // release resources
  drop(data);
  // maybe debug layer has something to say
  dump_info_queue(iq.map(|iq|iq).as_ref());
}

// Simple render statistics collector
pub struct PerfData {
  frames: u64,
  perf: HashMap<&'static str, f64>,
}

thread_local!(static PERFDATA: RefCell<PerfData> =
  RefCell::new( {
    let mut pd = PerfData {
      frames: 0,
      perf: HashMap::new(),
    };
    pd.perf.insert("clear", 0.);
    pd.perf.insert("fillbuf", 0.);
    pd.perf.insert("exec", 0.);
    pd.perf.insert("present", 0.);
    pd.perf.insert("wait", 0.);
    pd
  } ));

pub fn perf_frame() {
  PERFDATA.with(|pd| {
    pd.borrow_mut().frames += 1;
  });
}

pub fn perf_start(name: &'static str) {
  PERFDATA.with(|pd| {
    *pd.borrow_mut().perf.get_mut(name).unwrap() -= precise_time_s();
  });
}

pub fn perf_end(name: &'static str) {
  PERFDATA.with(|pd| {
    *pd.borrow_mut().perf.get_mut(name).unwrap() += precise_time_s();
  });
}

pub fn perf_clear_start() {
  perf_start("clear");
}

pub fn perf_clear_end() {
  perf_end("clear");
}

pub fn perf_fillbuf_start() {
  perf_start("fillbuf");
}

pub fn perf_fillbuf_end() {
  perf_end("fillbuf");
}

pub fn perf_exec_start() {
  perf_start("exec");
}

pub fn perf_exec_end() {
  perf_end("exec");
}

pub fn perf_present_start() {
  perf_start("present");
}

pub fn perf_present_end() {
  perf_end("present");
}

pub fn perf_wait_start() {
  perf_start("wait");
}

pub fn perf_wait_end() {
  perf_end("wait");
}
<commit_msg>Reset render time statistics every second<commit_after>#![feature(optin_builtin_traits)]
#![feature(clone_from_slice)]

//#[macro_use] extern crate gfx;
#[macro_use] extern crate lazy_static;
#[macro_use] extern crate log;
extern crate env_logger;
extern crate libc;
extern crate winapi;
extern crate dx_safe;
//extern crate dxguid_sys;
extern crate dxgi_sys;
extern crate kernel32;
extern crate user32;
//extern crate d3d12_sys;
extern crate rand;
extern crate clock_ticks;
extern crate cgmath;
extern crate crossbeam;

#[macro_use] mod macros;
mod create_device;
mod window;
mod structwrappers;
mod utils;
//mod gfx_d3d12;
mod shape_gen;
mod dxsems;
mod core;
mod app;
mod cubes;
mod camera;

use dxsems::VertexFormat;
use winapi::*;
use dx_safe::*;
use create_device::*;
use kernel32::{CreateEventW, WaitForSingleObject};
use std::ptr;
use std::fmt;
use std::mem;
use std::env;
use std::cell::RefCell;
use std::rc::Rc;
use std::sync::{Arc, Mutex};
use std::collections::HashMap;
use window::*;
use utils::*;
use clock_ticks::*;
use cgmath::*;
use core::*;
use std::sync::atomic::{AtomicUsize, Ordering};
use rand::Rng;
use cubes::{Parameters, CubeParms};

#[link(name="d3dcompiler")]
extern {}

const FRAME_COUNT : u32 = 4;

fn main() {
  // Initialize logger
  env_logger::init().unwrap();

  // Set default values of cubes module parameters
  let mut parms = CubeParms {thread_count: 2, object_count: 2_000,};
  let mut adapters_to_test = vec![];
  for arg in env::args() {
    if let Ok(n) = arg.parse::<u32>() {
      // If command line parameter is a number, treat it as a number of graphics adapter.
      adapters_to_test.push(n);
    }
    if arg.starts_with("-o") {
      // Command line parameter -o<N> sets number of objects to draw
      // Note, that 2 in arg[2..] is a number of bytes, not characters.
      if let Ok(n) = (&arg[2..]).parse::<u32>() {
        parms.object_count = n;
      }
    }
    if arg.starts_with("-t") {
      // Command line parameter -t<N> sets number of threads and graphics command lists
      // to use for sending workload to GPU
      if let Ok(n) = (&arg[2..]).parse::<u32>() {
        parms.thread_count = n;
      }
    }
  }

  let factory: DXGIFactory4 = create_dxgi_factory2().expect("Cannot create DXGIFactory4. No can do.");
  let mut i=0;
  let mut adapters = vec![];
  // Iterate over available GPUs
  while let Ok(adapter)=factory.enum_adapters1(i) {
    let descr=adapter.get_desc1().unwrap();
    println!("Adapter {}: {}", i, wchar_array_to_string_lossy(&descr.Description));
    println!("   Dedicated video memory: {}MiB", descr.DedicatedVideoMemory/1024/1024);
    if adapters_to_test.len()==0 || adapters_to_test[..].contains(&i) {
      // If there's no numbers in command line add each and every available adapter,
      // otherwise use adapter numbers from command line
      adapters.push(adapter);
    }
    // It's easy to forget this.
    i+=1;
  }

  // I used this mutex to sync console output.
  let mutex=Arc::new(Mutex::new(()));
  crossbeam::scope(|scope| {
    for (id,a) in adapters.into_iter().enumerate() {
      let mutex = mutex.clone();
      let parms = &parms;
      scope.spawn(move||{
        // Spawn a thread for each adapter
        main_prime(id, a, mutex, parms)
      });
    };
  });
}

fn main_prime<T: Parameters>(id: usize, adapter: DXGIAdapter1, mutex: Arc<Mutex<()>>, parms: &T) {
  // Setup window. Currently window module supports only one window per thread.
  let descr=wchar_array_to_string_lossy(&adapter.get_desc1().unwrap().Description);
  let title=format!("D3D12 Hello, rusty world! ({})", descr);
  let wnd=create_window(&title, 512, 256);

  {
    // This block of code is not required. I just checked some stuff
    if let Ok(dev)=d3d12_create_device(Some(&adapter), D3D_FEATURE_LEVEL_12_1) {
      let format = DXGI_FORMAT_R8G8B8A8_UNORM_SRGB;
      let mut fsup = D3D12_FEATURE_DATA_FORMAT_SUPPORT {
        Format: format,
        Support1: D3D12_FORMAT_SUPPORT1_NONE,
        Support2: D3D12_FORMAT_SUPPORT2_NONE,
      };
      if let Ok(_) = dev.check_feature_support_format_support(&mut fsup) {
        // We could have few threads running, so take a lock to prevent line interleaving
        let lock=mutex.lock();
        println!("{}", descr);
        println!("Format support for {:?} is {:x}, {:x}", format, fsup.Support1.0, fsup.Support2.0);
      }
    }
  }

  // Initialization of cubes module data required to render all stuff
  let data=
    match cubes::AppData::on_init(&wnd, Some(&adapter), FRAME_COUNT, parms) {
      Ok(appdata) => {
        Rc::new(RefCell::new(appdata))
      },
      Err(iq) => {
        dump_info_queue(iq.map(|iq|iq).as_ref());
        return ();
      },
    };

  // x and y store last mouse coords from WM_MOUSEMOVE
  let mut x:i32=0;
  let mut y:i32=0;
  // TODO: Make this horror go away
  // Simple and crude way to track state of keyboard keys
  let (mut wdown, mut sdown, mut adown, mut ddown, mut qdown, mut edown) = (false, false, false, false, false, false);
  // and state of left mouse button
  let mut mouse_down = false;
  // Profiling stuff
  let mut frame_count = 0;
  let mut avg_fps = 0;
  let mut start = precise_time_s();
  let mut mstart = start;
  // Window::poll_events() returns non-blocking iterator, that return Option<MSG>
  for mmsg in wnd.poll_events() {
    // "if let Some(msg)" extracts msg from mmsg
    // if mmsg is None, then 'else' branch is taken
    if let Some(msg) = mmsg {
      // Instead of passing messages into cubes module, I process them here
      // It is not well-thought-out design decision, it's just slightly simpler now, and cost of changing it is low.
      match msg.message {
        // Usual message processing stuff
        WM_SIZE => {
          // Normally this message goes to wndproc, in window.rs I repost it into message queue to prevent reentrancy problems
          debug!("WM_SIZE {}, {}  ", msg.wParam, msg.lParam);
          data.borrow_mut().on_resize(LOWORD(msg.lParam as u32) as u32, HIWORD(msg.lParam as u32) as u32, msg.wParam as u32);
        },
        WM_MOUSEMOVE => {
          let x1 = GET_X_LPARAM(msg.lParam) as i32;
          let y1 = GET_Y_LPARAM(msg.lParam) as i32;
          let (dx, dy) = (x1 - x, y - y1);
          x = x1;
          y = y1;
          if mouse_down {
            let mut data = data.borrow_mut();
            let camera = data.camera();
            camera.rotx(-dx as f32/6.);
            camera.roty(-dy as f32/6.);
          }
        },
        WM_KEYDOWN => {
          match msg.wParam as u8 {
            b'A' => adown = true,
            b'S' => sdown = true,
            b'D' => ddown = true,
            b'W' => wdown = true,
            b'Q' => qdown = true,
            b'E' => edown = true,
            _ => {},
          }
        },
        WM_KEYUP => {
          match msg.wParam as u8 {
            b'A' => adown = false,
            b'S' => sdown = false,
            b'D' => ddown = false,
            b'W' => wdown = false,
            b'Q' => qdown = false,
            b'E' => edown = false,
            _ => {},
          }
        },
        WM_LBUTTONDOWN => {
          mouse_down = true;
          set_capture(wnd.get_hwnd());
        },
        WM_LBUTTONUP => {
          mouse_down = false;
          release_capture();
        },
        _ => {},
      };
    } else {
      let do_not_render = data.borrow().is_minimized();
      if do_not_render {
        // MSDN suggest to use MsgWaitForMultipleObjects here, but 10ms sleep shouldn't create problems
        std::thread::sleep_ms(10);
      } else {
        {
          // data is Rc<RefCell<cubes::AppData>>
          // Rc is not really needed. I didn't pass it around.
          // Take a mutable reference to cubes::AppData
          let mut data = data.borrow_mut();
          // Process WASD keys
          let camera = data.camera();
          if wdown {
            camera.go(0.1, 0., 0.);
          };
          if sdown {
            camera.go(-0.1, 0., 0.);
          };
          if adown {
            camera.go(0., 0.1, 0.); // Something wrong with signs. Negative value should translate camera to the left
          };
          if ddown {
            camera.go(0., -0.1, 0.);
          };
          // Process Q and E keys. They control camera's roll
          if qdown {
            camera.rotz(-0.5);
          };
          if edown {
            camera.rotz(0.5);
          };
        }
        // For this simple program I don't separate update and render steps.
        // State change and rendering is done inside on_render.
        // Error handling isn't implemented yet. on_render panics, if it needs to.
        // TODO: remove x,y parameters
        // TODO: process error
        data.borrow_mut().on_render(x, y);
        // register rendered frame in performance collector
        ::perf_frame();
        // fps counting stuff
        let now = precise_time_s();
        let frames = PERFDATA.with(|p_data| p_data.borrow().frames);
        if frames>0 && now<start || now>=(start+1.0) {
          // Once per second show stats
          let (clear, fill, exec, present, wait) =
            PERFDATA.with(|p_data| {
              let p_data = p_data.borrow();
              let frames = p_data.frames as f64;
              (p_data.perf.get("clear").unwrap()*1000./frames,
                p_data.perf.get("fillbuf").unwrap()*1000./frames,
                p_data.perf.get("exec").unwrap()*1000./frames,
                p_data.perf.get("present").unwrap()*1000./frames,
                p_data.perf.get("wait").unwrap()*1000./frames, )
            });
          println!("Adapter {} FPS: {:3} clear:{:4.2} fill:{:4.2} exec:{:4.2} present:{:4.2} wait:{:4.2}   \r", id, frames, clear, fill, exec, present, wait);
          let _ = ::std::io::Write::flush(&mut ::std::io::stdout());
          perf_reset();
          start = now;
        }
      }
    }
  }
  // Application should exit fullscreen state before terminating.
  data.borrow().set_fullscreen(false).unwrap();
  // copy info queue
  let iq=data.borrow().info_queue().clone();
  // wait for all GPU processing to stop
  data.borrow().wait_frame();
  // release resources
  drop(data);
  // maybe debug layer has something to say
  dump_info_queue(iq.map(|iq|iq).as_ref());
}

// Simple render statistics collector
pub struct PerfData {
  frames: u64,
  perf: HashMap<&'static str, f64>,
}

impl PerfData {
  fn new() -> PerfData {
    let mut pd = PerfData {
      frames: 0,
      perf: HashMap::new(),
    };
    pd.perf.insert("clear", 0.);
    pd.perf.insert("fillbuf", 0.);
    pd.perf.insert("exec", 0.);
    pd.perf.insert("present", 0.);
    pd.perf.insert("wait", 0.);
    pd
  }
}

thread_local!(static PERFDATA: RefCell<PerfData> =
  RefCell::new(PerfData::new()));

pub fn perf_frame() {
  PERFDATA.with(|pd| {
    pd.borrow_mut().frames += 1;
  });
}

pub fn perf_reset() {
  PERFDATA.with(|pd| {
    let mut pd=pd.borrow_mut();
    *pd = PerfData::new();
  });
}

pub fn perf_start(name: &'static str) {
  PERFDATA.with(|pd| {
    *pd.borrow_mut().perf.get_mut(name).unwrap() -= precise_time_s();
  });
}

pub fn perf_end(name: &'static str) {
  PERFDATA.with(|pd| {
    *pd.borrow_mut().perf.get_mut(name).unwrap() += precise_time_s();
  });
}

pub fn perf_clear_start() {
  perf_start("clear");
}

pub fn perf_clear_end() {
  perf_end("clear");
}

pub fn perf_fillbuf_start() {
  perf_start("fillbuf");
}

pub fn perf_fillbuf_end() {
  perf_end("fillbuf");
}

pub fn perf_exec_start() {
  perf_start("exec");
}

pub fn perf_exec_end() {
  perf_end("exec");
}

pub fn perf_present_start() {
  perf_start("present");
}

pub fn perf_present_end() {
  perf_end("present");
}

pub fn perf_wait_start() {
  perf_start("wait");
}

pub fn perf_wait_end() {
  perf_end("wait");
}
<|endoftext|>