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

use std::error;
use std::fmt;
use std::sync::Arc;

use buffer::BufferAccess;
use buffer::BufferViewRef;
use descriptor::descriptor::DescriptorDesc;
use descriptor::descriptor::DescriptorDescTy;
use descriptor::descriptor::DescriptorImageDesc;
use descriptor::descriptor::DescriptorImageDescArray;
use descriptor::descriptor::DescriptorImageDescDimensions;
use descriptor::descriptor::DescriptorType;
use descriptor::descriptor_set::DescriptorSet;
use descriptor::descriptor_set::DescriptorSetDesc;
use descriptor::descriptor_set::UnsafeDescriptorSetLayout;
use descriptor::descriptor_set::DescriptorPool;
use descriptor::descriptor_set::DescriptorPoolAlloc;
use descriptor::descriptor_set::UnsafeDescriptorSet;
use descriptor::descriptor_set::DescriptorWrite;
use descriptor::descriptor_set::StdDescriptorPoolAlloc;
use descriptor::pipeline_layout::PipelineLayoutAbstract;
use device::Device;
use device::DeviceOwned;
use format::Format;
use image::ImageAccess;
use image::ImageViewAccess;
use sampler::Sampler;
use OomError;
use VulkanObject;

/// An immutable descriptor set that is expected to be long-lived.
///
/// Creating a persistent descriptor set allocates from a pool, and can't be modified once created.
/// You are therefore encouraged to create them at initialization and not the during
/// performance-critical paths.
///
/// > **Note**: You can control of the pool that is used to create the descriptor set, if you wish
/// > so. By creating a implementation of the `DescriptorPool` trait that doesn't perform any
/// > actual allocation, you can skip this allocation and make it acceptable to use a persistent
/// > descriptor set in performance-critical paths..
///
/// The template parameter of the `PersistentDescriptorSet` is complex, and you shouldn't try to
/// express it explicitely. If you want to store your descriptor set in a struct or in a `Vec` for
/// example, you are encouraged to turn the `PersistentDescriptorSet` into a `Box<DescriptorSet>`
/// or a `Arc<DescriptorSet>`.
///
/// # Example
// TODO:
pub struct PersistentDescriptorSet<R, P = StdDescriptorPoolAlloc> {
    inner: P,
    resources: R,
    layout: Arc<UnsafeDescriptorSetLayout>
}

impl PersistentDescriptorSet<()> {
    /// Starts the process of building a `PersistentDescriptorSet`. Returns a builder.
    ///
    /// # Panic
    ///
    /// - Panics if the set id is out of range.
    ///
    pub fn start<Pl>(layout: Pl, set_id: usize) -> PersistentDescriptorSetBuilder<Pl, ()>
        where Pl: PipelineLayoutAbstract
    {
        assert!(layout.num_sets() > set_id);

        let cap = layout.num_bindings_in_set(set_id).unwrap_or(0);

        PersistentDescriptorSetBuilder {
            layout: layout,
            set_id: set_id,
            binding_id: 0,
            writes: Vec::with_capacity(cap),
            resources: (),
        }
    }
}

unsafe impl<R, P> DescriptorSet for PersistentDescriptorSet<R, P>
    where P: DescriptorPoolAlloc,
          R: PersistentDescriptorSetResources
{
    #[inline]
    fn inner(&self) -> &UnsafeDescriptorSet {
        self.inner.inner()
    }

    #[inline]
    fn num_buffers(&self) -> usize {
        self.resources.num_buffers()
    }

    #[inline]
    fn buffer(&self, index: usize) -> Option<(&BufferAccess, u32)> {
        self.resources.buffer(index)
    }

    #[inline]
    fn num_images(&self) -> usize {
        self.resources.num_images()
    }

    #[inline]
    fn image(&self, index: usize) -> Option<(&ImageAccess, u32)> {
        self.resources.image(index)
    }
}

// TODO: is DescriptorSetDesc really necessary?
unsafe impl<R, P> DescriptorSetDesc for PersistentDescriptorSet<R, P> {
    #[inline]
    fn num_bindings(&self) -> usize {
        unimplemented!()        // FIXME:
    }

    #[inline]
    fn descriptor(&self, binding: usize) -> Option<DescriptorDesc> {
        unimplemented!()        // FIXME:
    }
}

unsafe impl<R, P> DeviceOwned for PersistentDescriptorSet<R, P>
    where P: DeviceOwned
{
    #[inline]
    fn device(&self) -> &Arc<Device> {
        self.layout.device()
    }
}

/// Prototype of a `PersistentDescriptorSet`.
///
/// The template parameter `L` is the pipeline layout to use, and the template parameter `R` is
/// an unspecified type that represents the list of resources.
///
/// See the docs of `PersistentDescriptorSet` for an example.
pub struct PersistentDescriptorSetBuilder<L, R> {
    // The pipeline layout.
    layout: L,
    // Id of the set within the pipeline layout.
    set_id: usize,
    // Binding currently being filled.
    binding_id: usize,
    // The writes to perform on a descriptor set in order to put the resources in it.
    writes: Vec<DescriptorWrite>,
    // Holds the resources alive.
    resources: R,
}

// TODO: lots of checks are still missing, see the docs of
//       VkDescriptorImageInfo and VkWriteDescriptorSet

impl<L, R> PersistentDescriptorSetBuilder<L, R>
    where L: PipelineLayoutAbstract
{
    /// Builds a `PersistentDescriptorSet` from the builder.
    #[inline]
    pub fn build(self) -> Result<PersistentDescriptorSet<R, StdDescriptorPoolAlloc>, PersistentDescriptorSetBuildError> {
        let pool = Device::standard_descriptor_pool(self.layout.device());
        self.build_with_pool(pool)
    }

    /// Builds a `PersistentDescriptorSet` from the builder.
    ///
    /// # Panic
    ///
    /// Panics if the pool doesn't have the same device as the pipeline layout.
    ///
    pub fn build_with_pool<P>(self, pool: P)
                              -> Result<PersistentDescriptorSet<R, P::Alloc>, PersistentDescriptorSetBuildError>
        where P: DescriptorPool
    {
        assert_eq!(self.layout.device().internal_object(),
                   pool.device().internal_object());

        let expected_desc = self.layout.num_bindings_in_set(self.set_id).unwrap();

        if expected_desc > self.binding_id {
            return Err(PersistentDescriptorSetBuildError::MissingDescriptors {
                expected: expected_desc as u32,
                obtained: self.binding_id as u32,
            });
        }

        debug_assert_eq!(expected_desc, self.binding_id);

        let set_layout = self.layout.descriptor_set_layout(self.set_id)
            .expect("Unable to get the descriptor set layout")
            .clone();

        let set = unsafe {
            let mut set = pool.alloc(&set_layout)?;
            set.inner_mut().write(pool.device(), self.writes.into_iter());
            set
        };

        Ok(PersistentDescriptorSet {
            inner: set,
            resources: self.resources,
            layout: set_layout,
        })
    }

    /// Call this function if the next element of the set is an array in order to set the value of
    /// each element.
    ///
    /// Returns an error if the descriptor is empty.
    ///
    /// This function can be called even if the descriptor isn't an array, and it is valid to enter
    /// the "array", add one element, then leave.
    #[inline]
    pub fn enter_array(self) -> Result<PersistentDescriptorSetBuilderArray<L, R>, PersistentDescriptorSetError> {
        let desc = match self.layout.descriptor(self.set_id, self.binding_id) {
            Some(d) => d,
            None => return Err(PersistentDescriptorSetError::EmptyExpected),<commit_msg>Correctly implement DescriptorSetDesc in PersistentDescriptorSet<commit_after>// Copyright (c) 2017 The vulkano developers
// Licensed under the Apache License, Version 2.0
// <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT
// license <LICENSE-MIT or http://opensource.org/licenses/MIT>,
// at your option. All files in the project carrying such
// notice may not be copied, modified, or distributed except
// according to those terms.

use std::error;
use std::fmt;
use std::sync::Arc;

use buffer::BufferAccess;
use buffer::BufferViewRef;
use descriptor::descriptor::DescriptorDesc;
use descriptor::descriptor::DescriptorDescTy;
use descriptor::descriptor::DescriptorImageDesc;
use descriptor::descriptor::DescriptorImageDescArray;
use descriptor::descriptor::DescriptorImageDescDimensions;
use descriptor::descriptor::DescriptorType;
use descriptor::descriptor_set::DescriptorSet;
use descriptor::descriptor_set::DescriptorSetDesc;
use descriptor::descriptor_set::UnsafeDescriptorSetLayout;
use descriptor::descriptor_set::DescriptorPool;
use descriptor::descriptor_set::DescriptorPoolAlloc;
use descriptor::descriptor_set::UnsafeDescriptorSet;
use descriptor::descriptor_set::DescriptorWrite;
use descriptor::descriptor_set::StdDescriptorPoolAlloc;
use descriptor::pipeline_layout::PipelineLayoutAbstract;
use device::Device;
use device::DeviceOwned;
use format::Format;
use image::ImageAccess;
use image::ImageViewAccess;
use sampler::Sampler;
use OomError;
use VulkanObject;

/// An immutable descriptor set that is expected to be long-lived.
///
/// Creating a persistent descriptor set allocates from a pool, and can't be modified once created.
/// You are therefore encouraged to create them at initialization and not the during
/// performance-critical paths.
///
/// > **Note**: You can control of the pool that is used to create the descriptor set, if you wish
/// > so. By creating a implementation of the `DescriptorPool` trait that doesn't perform any
/// > actual allocation, you can skip this allocation and make it acceptable to use a persistent
/// > descriptor set in performance-critical paths..
///
/// The template parameter of the `PersistentDescriptorSet` is complex, and you shouldn't try to
/// express it explicitely. If you want to store your descriptor set in a struct or in a `Vec` for
/// example, you are encouraged to turn the `PersistentDescriptorSet` into a `Box<DescriptorSet>`
/// or a `Arc<DescriptorSet>`.
///
/// # Example
// TODO:
pub struct PersistentDescriptorSet<L, R, P = StdDescriptorPoolAlloc> {
    inner: P,
    resources: R,
    pipeline_layout: L,
    set_id: usize,
    layout: Arc<UnsafeDescriptorSetLayout>
}

impl<L> PersistentDescriptorSet<L, ()> {
    /// Starts the process of building a `PersistentDescriptorSet`. Returns a builder.
    ///
    /// # Panic
    ///
    /// - Panics if the set id is out of range.
    ///
    pub fn start(layout: L, set_id: usize) -> PersistentDescriptorSetBuilder<L, ()>
        where L: PipelineLayoutAbstract
    {
        assert!(layout.num_sets() > set_id);

        let cap = layout.num_bindings_in_set(set_id).unwrap_or(0);

        PersistentDescriptorSetBuilder {
            layout: layout,
            set_id: set_id,
            binding_id: 0,
            writes: Vec::with_capacity(cap),
            resources: (),
        }
    }
}

unsafe impl<L, R, P> DescriptorSet for PersistentDescriptorSet<L, R, P>
    where L: PipelineLayoutAbstract,
          P: DescriptorPoolAlloc,
          R: PersistentDescriptorSetResources
{
    #[inline]
    fn inner(&self) -> &UnsafeDescriptorSet {
        self.inner.inner()
    }

    #[inline]
    fn num_buffers(&self) -> usize {
        self.resources.num_buffers()
    }

    #[inline]
    fn buffer(&self, index: usize) -> Option<(&BufferAccess, u32)> {
        self.resources.buffer(index)
    }

    #[inline]
    fn num_images(&self) -> usize {
        self.resources.num_images()
    }

    #[inline]
    fn image(&self, index: usize) -> Option<(&ImageAccess, u32)> {
        self.resources.image(index)
    }
}

unsafe impl<L, R, P> DescriptorSetDesc for PersistentDescriptorSet<L, R, P>
    where L: PipelineLayoutAbstract
{
    #[inline]
    fn num_bindings(&self) -> usize {
        self.pipeline_layout.num_bindings_in_set(self.set_id).unwrap()
    }

    #[inline]
    fn descriptor(&self, binding: usize) -> Option<DescriptorDesc> {
        self.pipeline_layout.descriptor(self.set_id, binding)
    }
}

unsafe impl<R, P> DeviceOwned for PersistentDescriptorSet<R, P>
    where P: DeviceOwned
{
    #[inline]
    fn device(&self) -> &Arc<Device> {
        self.layout.device()
    }
}

/// Prototype of a `PersistentDescriptorSet`.
///
/// The template parameter `L` is the pipeline layout to use, and the template parameter `R` is
/// an unspecified type that represents the list of resources.
///
/// See the docs of `PersistentDescriptorSet` for an example.
pub struct PersistentDescriptorSetBuilder<L, R> {
    // The pipeline layout.
    layout: L,
    // Id of the set within the pipeline layout.
    set_id: usize,
    // Binding currently being filled.
    binding_id: usize,
    // The writes to perform on a descriptor set in order to put the resources in it.
    writes: Vec<DescriptorWrite>,
    // Holds the resources alive.
    resources: R,
}

// TODO: lots of checks are still missing, see the docs of
//       VkDescriptorImageInfo and VkWriteDescriptorSet

impl<L, R> PersistentDescriptorSetBuilder<L, R>
    where L: PipelineLayoutAbstract
{
    /// Builds a `PersistentDescriptorSet` from the builder.
    #[inline]
    pub fn build(self) -> Result<PersistentDescriptorSet<L, R, StdDescriptorPoolAlloc>, PersistentDescriptorSetBuildError> {
        let pool = Device::standard_descriptor_pool(self.layout.device());
        self.build_with_pool(pool)
    }

    /// Builds a `PersistentDescriptorSet` from the builder.
    ///
    /// # Panic
    ///
    /// Panics if the pool doesn't have the same device as the pipeline layout.
    ///
    pub fn build_with_pool<P>(self, pool: P)
                              -> Result<PersistentDescriptorSet<L, R, P::Alloc>, PersistentDescriptorSetBuildError>
        where P: DescriptorPool
    {
        assert_eq!(self.layout.device().internal_object(),
                   pool.device().internal_object());

        let expected_desc = self.layout.num_bindings_in_set(self.set_id).unwrap();

        if expected_desc > self.binding_id {
            return Err(PersistentDescriptorSetBuildError::MissingDescriptors {
                expected: expected_desc as u32,
                obtained: self.binding_id as u32,
            });
        }

        debug_assert_eq!(expected_desc, self.binding_id);

        let set_layout = self.layout.descriptor_set_layout(self.set_id)
            .expect("Unable to get the descriptor set layout")
            .clone();

        let set = unsafe {
            let mut set = pool.alloc(&set_layout)?;
            set.inner_mut().write(pool.device(), self.writes.into_iter());
            set
        };

        Ok(PersistentDescriptorSet {
            inner: set,
            resources: self.resources,
            pipeline_layout: self.layout,
            set_id: self.set_id,
            layout: set_layout,
        })
    }

    /// Call this function if the next element of the set is an array in order to set the value of
    /// each element.
    ///
    /// Returns an error if the descriptor is empty.
    ///
    /// This function can be called even if the descriptor isn't an array, and it is valid to enter
    /// the "array", add one element, then leave.
    #[inline]
    pub fn enter_array(self) -> Result<PersistentDescriptorSetBuilderArray<L, R>, PersistentDescriptorSetError> {
        let desc = match self.layout.descriptor(self.set_id, self.binding_id) {
            Some(d) => d,
            None => return Err(PersistentDescriptorSetError::EmptyExpected),
{'fraction_non_alphanumeric': 0.10931019079828984, 'fraction_numerical': 0.0022972369344649354, 'mean_word_length': 3.043343653250774, 'pattern_counts': {'":': 0, '<': 63, '<?xml version=': 0, '>': 103, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 2, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '7654601', 'n_tokens_mistral': 4382, 'n_tokens_neox': 4346, 'n_words': 1335}