<commit_before>#[macro_use]
extern crate failure;
#[macro_use]
extern crate serde_derive;
extern crate log;
use azure_sdk_core::errors::AzureError;
use log::debug;
use oauth2::basic::BasicClient;
use oauth2::reqwest::async_http_client;
use oauth2::AsyncCodeTokenRequest;
use oauth2::{
    AuthType, AuthUrl, AuthorizationCode, ClientId, ClientSecret, CsrfToken, PkceCodeChallenge,
    PkceCodeVerifier, RedirectUrl, TokenUrl,
};
use url::form_urlencoded;
use url::Url;
mod login_response;
pub use login_response::*;
use std::sync::Arc;
pub mod errors;
mod naive_server;
use futures::TryFutureExt;
pub use naive_server::naive_server;
use reqwest;

#[derive(Debug)]
pub struct AuthObj {
    pub client: BasicClient,
    pub authorize_url: Url,
    pub csrf_state: CsrfToken,
    pub pkce_code_verifier: PkceCodeVerifier,
}

pub fn authorize_delegate(
    client_id: ClientId,
    client_secret: ClientSecret,
    tenant_id: &str,
    redirect_url: Url,
    resource: &str,
) -> AuthObj {
    let auth_url = AuthUrl::from_url(
        Url::parse(&format!(
            "https://login.microsoftonline.com/{}/oauth2/authorize",
            tenant_id
        ))
        .expect("Invalid authorization endpoint URL"),
    );
    let token_url = TokenUrl::from_url(
        Url::parse(&format!(
            "https://login.microsoftonline.com/{}/oauth2/v2.0/token",
            tenant_id
        ))
        .expect("Invalid token endpoint URL"),
    );

    // Set up the config for the Microsoft Graph OAuth2 process.
    let client = BasicClient::new(client_id, Some(client_secret), auth_url, Some(token_url))
        // Microsoft Graph requires client_id and client_secret in URL rather than
        // using Basic authentication.
        .set_auth_type(AuthType::RequestBody)
        .set_redirect_url(RedirectUrl::from_url(redirect_url));

    // Microsoft Graph supports Proof Key for Code Exchange (PKCE - https://oauth.net/2/pkce/).
    // Create a PKCE code verifier and SHA-256 encode it as a code challenge.
    let (pkce_code_challenge, pkce_code_verifier) = PkceCodeChallenge::new_random_sha256();

    // Generate the authorization URL to which we'll redirect the user.
    let (authorize_url, csrf_state) = client
        .authorize_url(CsrfToken::new_random)
        .add_extra_param("resource", resource) //"https://management.azure.com/".to_owned())
        .set_pkce_challenge(pkce_code_challenge)
        .url();

    AuthObj {
        client,
        authorize_url,
        csrf_state,
        pkce_code_verifier,
    }
}

pub async fn exchange(
    auth_obj: AuthObj,
    code: AuthorizationCode,
) -> Result<
    oauth2::StandardTokenResponse<oauth2::EmptyExtraTokenFields, oauth2::basic::BasicTokenType>,
    oauth2::RequestTokenError<
        oauth2::reqwest::Error<reqwest::Error>,
        oauth2::StandardErrorResponse<oauth2::basic::BasicErrorResponseType>,
    >,
> {
    // Exchange the code with a token.
    let token = auth_obj
        .client
        .exchange_code(code)
        // Send the PKCE code verifier in the token request
        .set_pkce_verifier(auth_obj.pkce_code_verifier)
        .request_async(async_http_client)
        .await?;

    debug!("MS Graph returned the following token:\n{:?}\n", token);
    Ok(token)
}

pub async fn authorize_non_interactive(
    client: Arc<reqwest::Client>,
    //  grant_type: &str, fixed on "client_credentials",
    client_id: &oauth2::ClientId,
    client_secret: &oauth2::ClientSecret,
    resource: &str,
    tenant_id: &str,
) -> Result<LoginResponse, AzureError> {
    let encoded: String = form_urlencoded::Serializer::new(String::new())
        .append_pair("grant_type", "client_credentials")
        .append_pair("client_id", client_id.as_str())
        .append_pair("client_secret", client_secret.secret())
        .append_pair("resource", resource)
        .finish();

    let url = url::Url::parse(&format!(
        "https://login.microsoftonline.com/{}/oauth2/token",
        tenant_id
    ))
    .map_err(|error| AzureError::GenericErrorWithText(error.to_string()))?;

    client
        .post(url)
        .header("ContentType", "Application / WwwFormUrlEncoded")
        .body(encoded)
        .send()
        .await
        .map_err(|e| AzureError::GenericErrorWithText(e.to_string()))?
        .json::<LoginResponse>()
        .map_err(|e| AzureError::GenericErrorWithText(e.to_string()))
        .await
}
<commit_msg>Re-export oauth2 types for easier authentication<commit_after>#[macro_use]
extern crate failure;
#[macro_use]
extern crate serde_derive;
extern crate log;
use azure_sdk_core::errors::AzureError;
use log::debug;
use oauth2::basic::BasicClient;
use oauth2::reqwest::async_http_client;
use oauth2::AsyncCodeTokenRequest;
use oauth2::{
    AuthType, AuthUrl, AuthorizationCode, CsrfToken, PkceCodeChallenge,
    PkceCodeVerifier, RedirectUrl, TokenUrl,
};
pub use oauth2::{ClientId, ClientSecret};
use url::form_urlencoded;
use url::Url;
mod login_response;
pub use login_response::*;
use std::sync::Arc;
pub mod errors;
mod naive_server;
use futures::TryFutureExt;
pub use naive_server::naive_server;
use reqwest;

#[derive(Debug)]
pub struct AuthObj {
    pub client: BasicClient,
    pub authorize_url: Url,
    pub csrf_state: CsrfToken,
    pub pkce_code_verifier: PkceCodeVerifier,
}

pub fn authorize_delegate(
    client_id: ClientId,
    client_secret: ClientSecret,
    tenant_id: &str,
    redirect_url: Url,
    resource: &str,
) -> AuthObj {
    let auth_url = AuthUrl::from_url(
        Url::parse(&format!(
            "https://login.microsoftonline.com/{}/oauth2/authorize",
            tenant_id
        ))
        .expect("Invalid authorization endpoint URL"),
    );
    let token_url = TokenUrl::from_url(
        Url::parse(&format!(
            "https://login.microsoftonline.com/{}/oauth2/v2.0/token",
            tenant_id
        ))
        .expect("Invalid token endpoint URL"),
    );

    // Set up the config for the Microsoft Graph OAuth2 process.
    let client = BasicClient::new(client_id, Some(client_secret), auth_url, Some(token_url))
        // Microsoft Graph requires client_id and client_secret in URL rather than
        // using Basic authentication.
        .set_auth_type(AuthType::RequestBody)
        .set_redirect_url(RedirectUrl::from_url(redirect_url));

    // Microsoft Graph supports Proof Key for Code Exchange (PKCE - https://oauth.net/2/pkce/).
    // Create a PKCE code verifier and SHA-256 encode it as a code challenge.
    let (pkce_code_challenge, pkce_code_verifier) = PkceCodeChallenge::new_random_sha256();

    // Generate the authorization URL to which we'll redirect the user.
    let (authorize_url, csrf_state) = client
        .authorize_url(CsrfToken::new_random)
        .add_extra_param("resource", resource) //"https://management.azure.com/".to_owned())
        .set_pkce_challenge(pkce_code_challenge)
        .url();

    AuthObj {
        client,
        authorize_url,
        csrf_state,
        pkce_code_verifier,
    }
}

pub async fn exchange(
    auth_obj: AuthObj,
    code: AuthorizationCode,
) -> Result<
    oauth2::StandardTokenResponse<oauth2::EmptyExtraTokenFields, oauth2::basic::BasicTokenType>,
    oauth2::RequestTokenError<
        oauth2::reqwest::Error<reqwest::Error>,
        oauth2::StandardErrorResponse<oauth2::basic::BasicErrorResponseType>,
    >,
> {
    // Exchange the code with a token.
    let token = auth_obj
        .client
        .exchange_code(code)
        // Send the PKCE code verifier in the token request
        .set_pkce_verifier(auth_obj.pkce_code_verifier)
        .request_async(async_http_client)
        .await?;

    debug!("MS Graph returned the following token:\n{:?}\n", token);
    Ok(token)
}

pub async fn authorize_non_interactive(
    client: Arc<reqwest::Client>,
    //  grant_type: &str, fixed on "client_credentials",
    client_id: &oauth2::ClientId,
    client_secret: &oauth2::ClientSecret,
    resource: &str,
    tenant_id: &str,
) -> Result<LoginResponse, AzureError> {
    let encoded: String = form_urlencoded::Serializer::new(String::new())
        .append_pair("grant_type", "client_credentials")
        .append_pair("client_id", client_id.as_str())
        .append_pair("client_secret", client_secret.secret())
        .append_pair("resource", resource)
        .finish();

    let url = url::Url::parse(&format!(
        "https://login.microsoftonline.com/{}/oauth2/token",
        tenant_id
    ))
    .map_err(|error| AzureError::GenericErrorWithText(error.to_string()))?;

    client
        .post(url)
        .header("ContentType", "Application / WwwFormUrlEncoded")
        .body(encoded)
        .send()
        .await
        .map_err(|e| AzureError::GenericErrorWithText(e.to_string()))?
        .json::<LoginResponse>()
        .map_err(|e| AzureError::GenericErrorWithText(e.to_string()))
        .await
}
<|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/.

// Get ability to instantiate a devicemapper context.

use std::sync::Once;

use devicemapper::{DmResult, DM};

use crate::stratis::{StratisError, StratisResult};

static INIT: Once = Once::new();
static mut DM_CONTEXT: Option<DmResult<DM>> = None;

pub fn get_dm_init() -> StratisResult<&'static DM> {
    unsafe {
        INIT.call_once(|| DM_CONTEXT = Some(DM::new()));
        match &DM_CONTEXT {
            Some(Ok(ref context)) => Ok(context),
            Some(Err(e)) => Err(StratisError::Chained(
                "Failed to initialize DM context".to_string(),
                // FIXME: Cannot clone DMError
                Box::new(StratisError::Msg(e.to_string())),
            )),
            _ => panic!("DM_CONTEXT.is_some()"),
        }
    }
}

pub fn get_dm() -> &'static DM {
    get_dm_init().expect(
        "the engine has already called get_dm_init() and exited if get_dm_init() returned an error",
    )
}
<commit_msg>Use DmError::clone<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/.

// Get ability to instantiate a devicemapper context.

use std::sync::Once;

use devicemapper::{DmResult, DM};

use crate::stratis::{StratisError, StratisResult};

static INIT: Once = Once::new();
static mut DM_CONTEXT: Option<DmResult<DM>> = None;

pub fn get_dm_init() -> StratisResult<&'static DM> {
    unsafe {
        INIT.call_once(|| DM_CONTEXT = Some(DM::new()));
        match &DM_CONTEXT {
            Some(Ok(ref context)) => Ok(context),
            Some(Err(e)) => Err(StratisError::Chained(
                "Failed to initialize DM context".to_string(),
                Box::new(e.clone().into()),
            )),
            _ => panic!("DM_CONTEXT.is_some()"),
        }
    }
}

pub fn get_dm() -> &'static DM {
    get_dm_init().expect(
        "the engine has already called get_dm_init() and exited if get_dm_init() returned an error",
    )
}
<|endoftext|>


<commit_before>use ffmpeg::format;
use gl;
use gl::types::*;
use ocl::{self, OclPrm};

use super::*;
use capture;
use hooks::hw::FrameCapture;
use manual_free::ManualFree;

pub struct SamplingConverter {
    /// Difference, in video frames, between how much time passed in-game and how much video we
    /// output.
    remainder: f64,

    /// The target time_base.
    time_base: f64,

    /// Data with a destructor.
    private: ManualFree<SamplingConverterPrivate>,
}

struct SamplingConverterPrivate {
    /// Data used for OpenCL operations.
    ///
    /// This is Some(None) if OpenCL is unavailable and None during an engine restart.
    ocl_runtime_data: Option<Option<OclRuntimeData>>,

    /// Pixels from the buffer are stored here when the engine restarts.
    ocl_backup_buffer: Option<Vec<ocl::prm::Float>>,

    /// The video resolution.
    video_resolution: (u32, u32),
}

struct OclRuntimeData {
    /// Buffer images.
    ocl_buffers: [ocl::Image<ocl::prm::Float>; 2],

    /// Output image.
    ocl_output_image: ocl::Image<ocl::prm::Float>,

    /// Index of the last written to OpenCL buffer.
    ocl_current_buffer_index: usize,
}

impl SamplingConverter {
    #[inline]
    pub fn new(engine: &Engine, time_base: f64, video_resolution: (u32, u32)) -> Self {
        assert!(time_base > 0f64);

        Self {
            remainder: 0f64,
            time_base,
            private: ManualFree::new(SamplingConverterPrivate::new(engine, video_resolution)),
        }
    }

    /// This should be called before an engine restart.
    #[inline]
    pub fn backup_and_free_ocl_data(&mut self, engine: &Engine) {
        self.private.backup_and_free_ocl_data(engine);
    }

    #[inline]
    pub fn free(&mut self) {
        self.private.free();
    }
}

impl FPSConverter for SamplingConverter {
    fn time_passed<F>(&mut self, engine: &Engine, frametime: f64, capture: F)
    where
        F: FnOnce(&Engine) -> FrameCapture,
    {
        assert!(frametime >= 0.0f64);

        let frame_capture = capture(engine);

        let old_remainder = self.remainder;
        self.remainder += frametime / self.time_base;

        let exposure = capture::get_capture_parameters(engine).sampling_exposure;

        if self.remainder <= (1f64 - exposure) {
            // Do nothing.
        } else if self.remainder < 1f64 {
            let weight = (self.remainder - old_remainder.max(1f64 - exposure)) * (1f64 / exposure);

            match frame_capture {
                FrameCapture::OpenGL => {
                    unimplemented!();
                }

                FrameCapture::OpenCL(ocl_gl_texture) => {
                    let ocl_data = self.private.get_ocl_data(engine).unwrap();

                    weighted_image_add(engine,
                                       ocl_gl_texture.as_ref(),
                                       ocl_data.src_buffer(),
                                       ocl_data.dst_buffer(),
                                       weight as f32);

                    ocl_data.switch_buffer_index();
                }
            }
        } else {
            let weight = (1f64 - old_remainder.max(1f64 - exposure)) * (1f64 / exposure);

            match frame_capture {
                FrameCapture::OpenGL => {
                    unimplemented!();
                }

                FrameCapture::OpenCL(ocl_gl_texture) => {
                    let ocl_data = self.private.get_ocl_data(engine).unwrap();

                    weighted_image_add(engine,
                                       ocl_gl_texture.as_ref(),
                                       ocl_data.src_buffer(),
                                       ocl_data.output_image(),
                                       weight as f32);

                    fill_with_black(engine, ocl_data.dst_buffer());

                    ocl_data.switch_buffer_index();

                    // Output the frame.
                    let (w, h) = hw::get_resolution(engine);
                    let mut buf = capture::get_buffer(engine, (w, h));
                    hw::read_ocl_image_into_buf(engine, ocl_data.output_image(), &mut buf);
                    capture::capture(engine, buf, 1);

                    self.remainder -= 1f64;

                    // Output it more times if needed.
                    let additional_frames = self.remainder as usize;
                    if additional_frames > 0 {
                        let mut buf = capture::get_buffer(engine, (w, h));
                        hw::read_ocl_image_into_buf(engine, ocl_gl_texture.as_ref(), &mut buf);
                        capture::capture(engine, buf, additional_frames);

                        self.remainder -= additional_frames as f64;
                    }

                    // Add the remaining image into the buffer.
                    if self.remainder > (1f64 - exposure) {
                        weighted_image_add(engine,
                                           ocl_gl_texture.as_ref(),
                                           ocl_data.src_buffer(),
                                           ocl_data.dst_buffer(),
                                           (((1f64 - exposure) - self.remainder) *
                                                (1f64 / exposure)) as
                                               f32);
                        ocl_data.switch_buffer_index();
                    }
                }
            }
        }

        // let (w, h) = hw::get_resolution(engine);
        // let mut buf = capture::get_buffer(engine, (w, h));
        //
        // match frame_capture {
        //     FrameCapture::OpenGL => {
        //         buf.set_format(format::Pixel::RGB24);
        //
        //         unsafe {
        //             // Our buffer expects 1-byte alignment.
        //             gl::PixelStorei(gl::PACK_ALIGNMENT, 1);
        //
        //             // Get the pixels!
        //             gl::ReadPixels(0,
        //                            0,
        //                            w as GLsizei,
        //                            h as GLsizei,
        //                            gl::RGB,
        //                            gl::UNSIGNED_BYTE,
        //                            buf.as_mut_slice().as_mut_ptr() as _);
        //         }
        //     }
        //
        //     FrameCapture::OpenCL(ocl_gl_texture) => {
        //         hw::read_ocl_image_into_buf(engine, &ocl_gl_texture, &mut buf);
        //     }
        // }
        //
        // capture::capture(engine, buf, frames);
    }
}

impl SamplingConverterPrivate {
    #[inline]
    fn new(engine: &Engine, video_resolution: (u32, u32)) -> Self {
        Self {
            ocl_runtime_data: Some(OclRuntimeData::new(engine, video_resolution)),
            ocl_backup_buffer: None,
            video_resolution,
        }
    }

    #[inline]
    fn get_ocl_data(&mut self, engine: &Engine) -> Option<&mut OclRuntimeData> {
        if self.ocl_runtime_data.is_none() {
            self.restore_ocl_data(engine);
        }

        self.ocl_runtime_data.as_mut().unwrap().as_mut()
    }

    /// This should be called before an engine restart.
    fn backup_and_free_ocl_data(&mut self, engine: &Engine) {
        let set_to_none = if let Some(Some(ref ocl_data)) = self.ocl_runtime_data {
            // Copy the src buffer into the output image.
            weighted_image_add(engine,
                               ocl_data.dst_buffer(),
                               ocl_data.src_buffer(),
                               ocl_data.output_image(),
                               0f32);

            let image = ocl_data.output_image();

            let mut backup_buffer = Vec::with_capacity(image.element_count());
            backup_buffer.resize(image.element_count(), 0f32.into());

            image.read(&mut backup_buffer).enq().expect("image.read()");

            self.ocl_backup_buffer = Some(backup_buffer);

            true
        } else {
            false
        };

        if set_to_none {
            self.ocl_runtime_data = None;
        }
    }

    /// This should be called after an engine restart.
    fn restore_ocl_data(&mut self, engine: &Engine) {
        if self.ocl_runtime_data.is_some() {
            return;
        }

        let ocl_data = OclRuntimeData::new(engine, self.video_resolution)
            .expect("changing from fullscreen to windowed is not supported");

        let pro_que = hw::get_pro_que(engine).unwrap();
        let temp_image = hw::build_ocl_image(engine,
                                             &pro_que,
                                             ocl::MemFlags::new().read_only().host_write_only(),
                                             ocl::enums::ImageChannelDataType::Float,
                                             self.video_resolution.into())
                         .expect("building an OpenCL image");

        let backup_buffer = self.ocl_backup_buffer.take().unwrap();
        temp_image.write(&backup_buffer)
                  .enq()
                  .expect("image.write()");

        // Copy the backup buffer into the src buffer.
        weighted_image_add(engine,
                           ocl_data.dst_buffer(),
                           &temp_image,
                           ocl_data.src_buffer(),
                           0f32);

        self.ocl_runtime_data = Some(Some(ocl_data));
    }
}

impl OclRuntimeData {
    fn new(engine: &Engine, (w, h): (u32, u32)) -> Option<Self> {
        hw::get_pro_que(engine).map(|pro_que| {
            let rv = Self {
                ocl_buffers: [
                    hw::build_ocl_image(engine,
                                        &pro_que,
                                        ocl::MemFlags::new()
                                            .read_write()
                                            .host_no_access(),
                                        ocl::enums::ImageChannelDataType::Float,
                                        (w, h).into())
                    .expect("building an OpenCL image"),
                    hw::build_ocl_image(engine,
                                        &pro_que,
                                        ocl::MemFlags::new()
                                            .read_write()
                                            .host_no_access(),
                                        ocl::enums::ImageChannelDataType::Float,
                                        (w, h).into())
                    .expect("building an OpenCL image"),
                ],
                ocl_output_image: hw::build_ocl_image(engine,
                                                      &pro_que,
                                                      ocl::MemFlags::new()
                                                          .read_write()
                                                          .host_read_only(),
                                                      ocl::enums::ImageChannelDataType::Float,
                                                      (w, h).into())
                                  .expect("building an OpenCL image"),
                ocl_current_buffer_index: 0,
            };

            fill_with_black(engine, rv.src_buffer());

            rv
        })
    }

    #[inline]
    fn src_buffer(&self) -> &ocl::Image<ocl::prm::Float> {
        &self.ocl_buffers[self.ocl_current_buffer_index]
    }

    #[inline]
    fn dst_buffer(&self) -> &ocl::Image<ocl::prm::Float> {
        &self.ocl_buffers[self.ocl_current_buffer_index ^ 1]
    }

    #[inline]
    fn output_image(&self) -> &ocl::Image<ocl::prm::Float> {
        &self.ocl_output_image
    }

    #[inline]
    fn switch_buffer_index(&mut self) {
        self.ocl_current_buffer_index ^= 1;
    }
}

#[inline]
fn weighted_image_add<T: OclPrm, U: OclPrm, V: OclPrm>(engine: &Engine,
                                                       src: &ocl::Image<T>,
                                                       buf: &ocl::Image<U>,
                                                       dst: &ocl::Image<V>,
                                                       weight: f32) {
    let pro_que = hw::get_pro_que(engine).unwrap();

    let kernel = pro_que.create_kernel("weighted_image_add")
                        .unwrap()
                        .gws(src.dims())
                        .arg_img(src)
                        .arg_img(buf)
                        .arg_img(dst)
                        .arg_scl(weight);

    kernel.enq().expect("sampling kernel enq()");
}

#[inline]
fn fill_with_black<T: OclPrm>(engine: &Engine, image: &ocl::Image<T>) {
    let pro_que = hw::get_pro_que(engine).unwrap();

    let kernel = pro_que.create_kernel("fill_with_black")
                        .unwrap()
                        .gws(image.dims())
                        .arg_img(image);

    kernel.enq().expect("sampling kernel enq()");
}
<commit_msg>Add stricter error handling in restore_ocl_data<commit_after>use ffmpeg::format;
use gl;
use gl::types::*;
use ocl::{self, OclPrm};

use super::*;
use capture;
use hooks::hw::FrameCapture;
use manual_free::ManualFree;

pub struct SamplingConverter {
    /// Difference, in video frames, between how much time passed in-game and how much video we
    /// output.
    remainder: f64,

    /// The target time_base.
    time_base: f64,

    /// Data with a destructor.
    private: ManualFree<SamplingConverterPrivate>,
}

struct SamplingConverterPrivate {
    /// Data used for OpenCL operations.
    ///
    /// This is Some(None) if OpenCL is unavailable and None during an engine restart.
    ocl_runtime_data: Option<Option<OclRuntimeData>>,

    /// Pixels from the buffer are stored here when the engine restarts.
    ocl_backup_buffer: Option<Vec<ocl::prm::Float>>,

    /// The video resolution.
    video_resolution: (u32, u32),
}

struct OclRuntimeData {
    /// Buffer images.
    ocl_buffers: [ocl::Image<ocl::prm::Float>; 2],

    /// Output image.
    ocl_output_image: ocl::Image<ocl::prm::Float>,

    /// Index of the last written to OpenCL buffer.
    ocl_current_buffer_index: usize,
}

impl SamplingConverter {
    #[inline]
    pub fn new(engine: &Engine, time_base: f64, video_resolution: (u32, u32)) -> Self {
        assert!(time_base > 0f64);

        Self {
            remainder: 0f64,
            time_base,
            private: ManualFree::new(SamplingConverterPrivate::new(engine, video_resolution)),
        }
    }

    /// This should be called before an engine restart.
    #[inline]
    pub fn backup_and_free_ocl_data(&mut self, engine: &Engine) {
        self.private.backup_and_free_ocl_data(engine);
    }

    #[inline]
    pub fn free(&mut self) {
        self.private.free();
    }
}

impl FPSConverter for SamplingConverter {
    fn time_passed<F>(&mut self, engine: &Engine, frametime: f64, capture: F)
    where
        F: FnOnce(&Engine) -> FrameCapture,
    {
        assert!(frametime >= 0.0f64);

        let frame_capture = capture(engine);

        let old_remainder = self.remainder;
        self.remainder += frametime / self.time_base;

        let exposure = capture::get_capture_parameters(engine).sampling_exposure;

        if self.remainder <= (1f64 - exposure) {
            // Do nothing.
        } else if self.remainder < 1f64 {
            let weight = (self.remainder - old_remainder.max(1f64 - exposure)) * (1f64 / exposure);

            match frame_capture {
                FrameCapture::OpenGL => {
                    unimplemented!();
                }

                FrameCapture::OpenCL(ocl_gl_texture) => {
                    let ocl_data = self.private.get_ocl_data(engine).unwrap();

                    weighted_image_add(engine,
                                       ocl_gl_texture.as_ref(),
                                       ocl_data.src_buffer(),
                                       ocl_data.dst_buffer(),
                                       weight as f32);

                    ocl_data.switch_buffer_index();
                }
            }
        } else {
            let weight = (1f64 - old_remainder.max(1f64 - exposure)) * (1f64 / exposure);

            match frame_capture {
                FrameCapture::OpenGL => {
                    unimplemented!();
                }

                FrameCapture::OpenCL(ocl_gl_texture) => {
                    let ocl_data = self.private.get_ocl_data(engine).unwrap();

                    weighted_image_add(engine,
                                       ocl_gl_texture.as_ref(),
                                       ocl_data.src_buffer(),
                                       ocl_data.output_image(),
                                       weight as f32);

                    fill_with_black(engine, ocl_data.dst_buffer());

                    ocl_data.switch_buffer_index();

                    // Output the frame.
                    let (w, h) = hw::get_resolution(engine);
                    let mut buf = capture::get_buffer(engine, (w, h));
                    hw::read_ocl_image_into_buf(engine, ocl_data.output_image(), &mut buf);
                    capture::capture(engine, buf, 1);

                    self.remainder -= 1f64;

                    // Output it more times if needed.
                    let additional_frames = self.remainder as usize;
                    if additional_frames > 0 {
                        let mut buf = capture::get_buffer(engine, (w, h));
                        hw::read_ocl_image_into_buf(engine, ocl_gl_texture.as_ref(), &mut buf);
                        capture::capture(engine, buf, additional_frames);

                        self.remainder -= additional_frames as f64;
                    }

                    // Add the remaining image into the buffer.
                    if self.remainder > (1f64 - exposure) {
                        weighted_image_add(engine,
                                           ocl_gl_texture.as_ref(),
                                           ocl_data.src_buffer(),
                                           ocl_data.dst_buffer(),
                                           (((1f64 - exposure) - self.remainder) *
                                                (1f64 / exposure)) as
                                               f32);
                        ocl_data.switch_buffer_index();
                    }
                }
            }
        }

        // let (w, h) = hw::get_resolution(engine);
        // let mut buf = capture::get_buffer(engine, (w, h));
        //
        // match frame_capture {
        //     FrameCapture::OpenGL => {
        //         buf.set_format(format::Pixel::RGB24);
        //
        //         unsafe {
        //             // Our buffer expects 1-byte alignment.
        //             gl::PixelStorei(gl::PACK_ALIGNMENT, 1);
        //
        //             // Get the pixels!
        //             gl::ReadPixels(0,
        //                            0,
        //                            w as GLsizei,
        //                            h as GLsizei,
        //                            gl::RGB,
        //                            gl::UNSIGNED_BYTE,
        //                            buf.as_mut_slice().as_mut_ptr() as _);
        //         }
        //     }
        //
        //     FrameCapture::OpenCL(ocl_gl_texture) => {
        //         hw::read_ocl_image_into_buf(engine, &ocl_gl_texture, &mut buf);
        //     }
        // }
        //
        // capture::capture(engine, buf, frames);
    }
}

impl SamplingConverterPrivate {
    #[inline]
    fn new(engine: &Engine, video_resolution: (u32, u32)) -> Self {
        Self {
            ocl_runtime_data: Some(OclRuntimeData::new(engine, video_resolution)),
            ocl_backup_buffer: None,
            video_resolution,
        }
    }

    #[inline]
    fn get_ocl_data(&mut self, engine: &Engine) -> Option<&mut OclRuntimeData> {
        if self.ocl_runtime_data.is_none() {
            self.restore_ocl_data(engine);
        }

        self.ocl_runtime_data.as_mut().unwrap().as_mut()
    }

    /// This should be called before an engine restart.
    fn backup_and_free_ocl_data(&mut self, engine: &Engine) {
        let set_to_none = if let Some(Some(ref ocl_data)) = self.ocl_runtime_data {
            // Copy the src buffer into the output image.
            weighted_image_add(engine,
                               ocl_data.dst_buffer(),
                               ocl_data.src_buffer(),
                               ocl_data.output_image(),
                               0f32);

            let image = ocl_data.output_image();

            let mut backup_buffer = Vec::with_capacity(image.element_count());
            backup_buffer.resize(image.element_count(), 0f32.into());

            image.read(&mut backup_buffer).enq().expect("image.read()");

            self.ocl_backup_buffer = Some(backup_buffer);

            true
        } else {
            false
        };

        if set_to_none {
            self.ocl_runtime_data = None;
        }
    }

    /// This should be called after an engine restart.
    fn restore_ocl_data(&mut self, engine: &Engine) {
        if self.ocl_runtime_data.is_some() {
            panic!("tried to restore already existing OpenCL data");
        }

        let ocl_data = OclRuntimeData::new(engine, self.video_resolution)
            .expect("changing from fullscreen to windowed is not supported");

        let pro_que = hw::get_pro_que(engine).unwrap();
        let temp_image = hw::build_ocl_image(engine,
                                             &pro_que,
                                             ocl::MemFlags::new().read_only().host_write_only(),
                                             ocl::enums::ImageChannelDataType::Float,
                                             self.video_resolution.into())
                         .expect("building an OpenCL image");

        let backup_buffer = self.ocl_backup_buffer.take().unwrap();
        temp_image.write(&backup_buffer)
                  .enq()
                  .expect("image.write()");

        // Copy the backup buffer into the src buffer.
        weighted_image_add(engine,
                           ocl_data.dst_buffer(),
                           &temp_image,
                           ocl_data.src_buffer(),
                           0f32);

        self.ocl_runtime_data = Some(Some(ocl_data));
    }
}

impl OclRuntimeData {
    fn new(engine: &Engine, (w, h): (u32, u32)) -> Option<Self> {
        hw::get_pro_que(engine).map(|pro_que| {
            let rv = Self {
                ocl_buffers: [
                    hw::build_ocl_image(engine,
                                        &pro_que,
                                        ocl::MemFlags::new()
                                            .read_write()
                                            .host_no_access(),
                                        ocl::enums::ImageChannelDataType::Float,
                                        (w, h).into())
                    .expect("building an OpenCL image"),
                    hw::build_ocl_image(engine,
                                        &pro_que,
                                        ocl::MemFlags::new()
                                            .read_write()
                                            .host_no_access(),
                                        ocl::enums::ImageChannelDataType::Float,
                                        (w, h).into())
                    .expect("building an OpenCL image"),
                ],
                ocl_output_image: hw::build_ocl_image(engine,
                                                      &pro_que,
                                                      ocl::MemFlags::new()
                                                          .read_write()
                                                          .host_read_only(),
                                                      ocl::enums::ImageChannelDataType::Float,
                                                      (w, h).into())
                                  .expect("building an OpenCL image"),
                ocl_current_buffer_index: 0,
            };

            fill_with_black(engine, rv.src_buffer());

            rv
        })
    }

    #[inline]
    fn src_buffer(&self) -> &ocl::Image<ocl::prm::Float> {
        &self.ocl_buffers[self.ocl_current_buffer_index]
    }

    #[inline]
    fn dst_buffer(&self) -> &ocl::Image<ocl::prm::Float> {
        &self.ocl_buffers[self.ocl_current_buffer_index ^ 1]
    }

    #[inline]
    fn output_image(&self) -> &ocl::Image<ocl::prm::Float> {
        &self.ocl_output_image
    }

    #[inline]
    fn switch_buffer_index(&mut self) {
        self.ocl_current_buffer_index ^= 1;
    }
}

#[inline]
fn weighted_image_add<T: OclPrm, U: OclPrm, V: OclPrm>(engine: &Engine,
                                                       src: &ocl::Image<T>,
                                                       buf: &ocl::Image<U>,
                                                       dst: &ocl::Image<V>,
                                                       weight: f32) {
    let pro_que = hw::get_pro_que(engine).unwrap();

    let kernel = pro_que.create_kernel("weighted_image_add")
                        .unwrap()
                        .gws(src.dims())
                        .arg_img(src)
                        .arg_img(buf)
                        .arg_img(dst)
                        .arg_scl(weight);

    kernel.enq().expect("sampling kernel enq()");
}

#[inline]
fn fill_with_black<T: OclPrm>(engine: &Engine, image: &ocl::Image<T>) {
    let pro_que = hw::get_pro_que(engine).unwrap();

    let kernel = pro_que.create_kernel("fill_with_black")
                        .unwrap()
                        .gws(image.dims())
                        .arg_img(image);

    kernel.enq().expect("sampling kernel enq()");
}
<|endoftext|>


<commit_before>//! Track which values are live in an EBB with instruction granularity.
//!
//! The `LiveValueTracker` keeps track of the set of live SSA values at each instruction in an EBB.
//! The sets of live values are computed on the fly as the tracker is moved from instruction to
//! instruction, starting at the EBB header.

use dominator_tree::DominatorTree;
use entity::{EntityList, ListPool};
use ir::{Inst, Ebb, Value, DataFlowGraph, Layout, ExpandedProgramPoint};
use partition_slice::partition_slice;
use regalloc::affinity::Affinity;
use regalloc::liveness::Liveness;
use regalloc::liverange::LiveRange;
use std::collections::HashMap;
use std::vec::Vec;

type ValueList = EntityList<Value>;

/// Compute and track live values throughout an EBB.
pub struct LiveValueTracker {
    /// The set of values that are live at the current program point.
    live: LiveValueVec,

    /// Saved set of live values for every jump and branch that can potentially be an immediate
    /// dominator of an EBB.
    ///
    /// This is the set of values that are live *before* the branch.
    idom_sets: HashMap<Inst, ValueList>,

    /// Memory pool for the live sets.
    idom_pool: ListPool<Value>,
}

/// Information about a value that is live at the current program point.
pub struct LiveValue {
    /// The live value.
    pub value: Value,

    /// The local ending point of the live range in the current EBB, as returned by
    /// `LiveRange::def_local_end()` or `LiveRange::livein_local_end()`.
    pub endpoint: Inst,

    /// The affinity of the value as represented in its `LiveRange`.
    ///
    /// This value is simply a copy of the affinity stored in the live range. We copy it because
    /// almost all users of `LiveValue` need to look at it.
    pub affinity: Affinity,

    /// The live range for this value never leaves its EBB.
    pub is_local: bool,

    /// This value is dead - the live range ends immediately.
    pub is_dead: bool,
}

struct LiveValueVec {
    /// The set of values that are live at the current program point.
    values: Vec<LiveValue>,

    /// How many values at the front of `values` are known to be live after `inst`?
    ///
    /// This is used to pass a much smaller slice to `partition_slice` when its called a second
    /// time for the same instruction.
    live_prefix: Option<(Inst, usize)>,
}

impl LiveValueVec {
    fn new() -> Self {
        Self {
            values: Vec::new(),
            live_prefix: None,
        }
    }

    /// Add a new live value to `values`. Copy some properties from `lr`.
    fn push(&mut self, value: Value, endpoint: Inst, lr: &LiveRange) {
        self.values.push(LiveValue {
            value,
            endpoint,
            affinity: lr.affinity,
            is_local: lr.is_local(),
            is_dead: lr.is_dead(),
        });
    }

    /// Remove all elements.
    fn clear(&mut self) {
        self.values.clear();
        self.live_prefix = None;
    }

    /// Make sure that the values killed by `next_inst` are moved to the end of the `values`
    /// vector.
    ///
    /// Returns the number of values that will be live after `next_inst`.
    fn live_after(&mut self, next_inst: Inst) -> usize {
        // How many values at the front of the vector are already known to survive `next_inst`?
        // We don't need to pass this prefix to `partition_slice()`
        let keep = match self.live_prefix {
            Some((i, prefix)) if i == next_inst => prefix,
            _ => 0,
        };

        // Move the remaining surviving values to the front partition of the vector.
        let prefix = keep + partition_slice(&mut self.values[keep..], |v| v.endpoint != next_inst);

        // Remember the new prefix length in case we get called again for the same `next_inst`.
        self.live_prefix = Some((next_inst, prefix));
        prefix
    }

    /// Remove the values killed by `next_inst`.
    fn remove_kill_values(&mut self, next_inst: Inst) {
        let keep = self.live_after(next_inst);
        self.values.truncate(keep);
    }

    /// Remove any dead values.
    fn remove_dead_values(&mut self) {
        self.values.retain(|v| !v.is_dead);
        self.live_prefix = None;
    }
}

impl LiveValueTracker {
    /// Create a new blank tracker.
    pub fn new() -> Self {
        Self {
            live: LiveValueVec::new(),
            idom_sets: HashMap::new(),
            idom_pool: ListPool::new(),
        }
    }

    /// Clear all cached information.
    pub fn clear(&mut self) {
        self.live.clear();
        self.idom_sets.clear();
        self.idom_pool.clear();
    }

    /// Get the set of currently live values.
    ///
    /// Between calls to `process_inst()` and `drop_dead()`, this includes both values killed and
    /// defined by the current instruction.
    pub fn live(&self) -> &[LiveValue] {
        &self.live.values
    }

    /// Get a mutable set of currently live values.
    ///
    /// Use with care and don't move entries around.
    pub fn live_mut(&mut self) -> &mut [LiveValue] {
        &mut self.live.values
    }

    /// Move the current position to the top of `ebb`.
    ///
    /// This depends on the stored live value set at `ebb`'s immediate dominator, so that must have
    /// been visited first.
    ///
    /// Returns `(liveins, args)` as a pair of slices. The first slice is the set of live-in values
    /// from the immediate dominator. The second slice is the set of `ebb` parameters.
    ///
    /// Dead parameters with no uses are included in `args`. Call `drop_dead_args()` to remove them.
    pub fn ebb_top(
        &mut self,
        ebb: Ebb,
        dfg: &DataFlowGraph,
        liveness: &Liveness,
        layout: &Layout,
        domtree: &DominatorTree,
    ) -> (&[LiveValue], &[LiveValue]) {
        // Start over, compute the set of live values at the top of the EBB from two sources:
        //
        // 1. Values that were live before `ebb`'s immediate dominator, filtered for those that are
        //    actually live-in.
        // 2. Arguments to `ebb` that are not dead.
        //
        self.live.clear();

        // Compute the live-in values. Start by filtering the set of values that were live before
        // the immediate dominator. Just use the empty set if there's no immediate dominator (i.e.,
        // the entry block or an unreachable block).
        if let Some(idom) = domtree.idom(ebb) {
            // If the immediate dominator exits, we must have a stored list for it. This is a
            // requirement to the order EBBs are visited: All dominators must have been processed
            // before the current EBB.
            let idom_live_list = self.idom_sets.get(&idom).expect(
                "No stored live set for dominator",
            );
            let ctx = liveness.context(layout);
            // Get just the values that are live-in to `ebb`.
            for &value in idom_live_list.as_slice(&self.idom_pool) {
                let lr = liveness.get(value).expect(
                    "Immediate dominator value has no live range",
                );

                // Check if this value is live-in here.
                if let Some(endpoint) = lr.livein_local_end(ebb, ctx) {
                    self.live.push(value, endpoint, lr);
                }
            }
        }

        // Now add all the live parameters to `ebb`.
        let first_arg = self.live.values.len();
        for &value in dfg.ebb_params(ebb) {
            let lr = &liveness[value];
            debug_assert_eq!(lr.def(), ebb.into());
            match lr.def_local_end().into() {
                ExpandedProgramPoint::Inst(endpoint) => {
                    self.live.push(value, endpoint, lr);
                }
                ExpandedProgramPoint::Ebb(local_ebb) => {
                    // This is a dead EBB parameter which is not even live into the first
                    // instruction in the EBB.
                    debug_assert_eq!(
                        local_ebb,
                        ebb,
                        "EBB parameter live range ends at wrong EBB header"
                    );
                    // Give this value a fake endpoint that is the first instruction in the EBB.
                    // We expect it to be removed by calling `drop_dead_args()`.
                    self.live.push(
                        value,
                        layout.first_inst(ebb).expect("Empty EBB"),
                        lr,
                    );
                }
            }
        }

        self.live.values.split_at(first_arg)
    }

    /// Prepare to move past `inst`.
    ///
    /// Determine the set of already live values that are killed by `inst`, and add the new defined
    /// values to the tracked set.
    ///
    /// Returns `(throughs, kills, defs)` as a tuple of slices:
    ///
    /// 1. The `throughs` slice is the set of live-through values that are neither defined nor
    ///    killed by the instruction.
    /// 2. The `kills` slice is the set of values that were live before the instruction and are
    ///    killed at the instruction. This does not include dead defs.
    /// 3. The `defs` slice is guaranteed to be in the same order as `inst`'s results, and includes
    ///    dead defines.
    ///
    /// The order of `throughs` and `kills` is arbitrary.
    ///
    /// The `drop_dead()` method must be called next to actually remove the dead values from the
    /// tracked set after the two returned slices are no longer needed.
    pub fn process_inst(
        &mut self,
        inst: Inst,
        dfg: &DataFlowGraph,
        liveness: &Liveness,
    ) -> (&[LiveValue], &[LiveValue], &[LiveValue]) {
        // Save a copy of the live values before any branches or jumps that could be somebody's
        // immediate dominator.
        if dfg[inst].opcode().is_branch() {
            self.save_idom_live_set(inst);
        }

        // Move killed values to the end of the vector.
        // Don't remove them yet, `drop_dead()` will do that.
        let first_kill = self.live.live_after(inst);

        // Add the values defined by `inst`.
        let first_def = self.live.values.len();
        for &value in dfg.inst_results(inst) {
            let lr = &liveness[value];
            debug_assert_eq!(lr.def(), inst.into());
            match lr.def_local_end().into() {
                ExpandedProgramPoint::Inst(endpoint) => {
                    self.live.push(value, endpoint, lr);
                }
                ExpandedProgramPoint::Ebb(ebb) => {
                    panic!("Instruction result live range can't end at {}", ebb);
                }
            }
        }

        (
            &self.live.values[0..first_kill],
            &self.live.values[first_kill..first_def],
            &self.live.values[first_def..],
        )
    }

    /// Prepare to move past a ghost instruction.
    ///
    /// This is like `process_inst`, except any defs are ignored.
    ///
    /// Returns `(throughs, kills)`.
    pub fn process_ghost(&mut self, inst: Inst) -> (&[LiveValue], &[LiveValue]) {
        let first_kill = self.live.live_after(inst);
        self.live.values.as_slice().split_at(first_kill)
    }

    /// Drop the values that are now dead after moving past `inst`.
    ///
    /// This removes both live values that were killed by `inst` and dead defines on `inst` itself.
    ///
    /// This must be called after `process_inst(inst)` and before proceeding to the next
    /// instruction.
    pub fn drop_dead(&mut self, inst: Inst) {
        // Remove both live values that were killed by `inst` and dead defines from `inst`.
        self.live.remove_kill_values(inst);
    }

    /// Drop any values that are marked as `is_dead`.
    ///
    /// Use this after calling `ebb_top` to clean out dead EBB parameters.
    pub fn drop_dead_params(&mut self) {
        self.live.remove_dead_values();
    }

    /// Process new spills.
    ///
    /// Any values where `f` returns true are spilled and will be treated as if their affinity was
    /// `Stack`.
    pub fn process_spills<F>(&mut self, mut f: F)
    where
        F: FnMut(Value) -> bool,
    {
        for lv in &mut self.live.values {
            if f(lv.value) {
                lv.affinity = Affinity::Stack;
            }
        }
    }

    /// Save the current set of live values so it is associated with `idom`.
    fn save_idom_live_set(&mut self, idom: Inst) {
        let values = self.live.values.iter().map(|lv| lv.value);
        let pool = &mut self.idom_pool;
        // If there already is a set saved for `idom`, just keep it.
        self.idom_sets.entry(idom).or_insert_with(|| {
            let mut list = ValueList::default();
            list.extend(values, pool);
            list
        });
    }
}
<commit_msg>Derive Debug for LiveValue.<commit_after>//! Track which values are live in an EBB with instruction granularity.
//!
//! The `LiveValueTracker` keeps track of the set of live SSA values at each instruction in an EBB.
//! The sets of live values are computed on the fly as the tracker is moved from instruction to
//! instruction, starting at the EBB header.

use dominator_tree::DominatorTree;
use entity::{EntityList, ListPool};
use ir::{Inst, Ebb, Value, DataFlowGraph, Layout, ExpandedProgramPoint};
use partition_slice::partition_slice;
use regalloc::affinity::Affinity;
use regalloc::liveness::Liveness;
use regalloc::liverange::LiveRange;
use std::collections::HashMap;
use std::vec::Vec;

type ValueList = EntityList<Value>;

/// Compute and track live values throughout an EBB.
pub struct LiveValueTracker {
    /// The set of values that are live at the current program point.
    live: LiveValueVec,

    /// Saved set of live values for every jump and branch that can potentially be an immediate
    /// dominator of an EBB.
    ///
    /// This is the set of values that are live *before* the branch.
    idom_sets: HashMap<Inst, ValueList>,

    /// Memory pool for the live sets.
    idom_pool: ListPool<Value>,
}

/// Information about a value that is live at the current program point.
#[derive(Debug)]
pub struct LiveValue {
    /// The live value.
    pub value: Value,

    /// The local ending point of the live range in the current EBB, as returned by
    /// `LiveRange::def_local_end()` or `LiveRange::livein_local_end()`.
    pub endpoint: Inst,

    /// The affinity of the value as represented in its `LiveRange`.
    ///
    /// This value is simply a copy of the affinity stored in the live range. We copy it because
    /// almost all users of `LiveValue` need to look at it.
    pub affinity: Affinity,

    /// The live range for this value never leaves its EBB.
    pub is_local: bool,

    /// This value is dead - the live range ends immediately.
    pub is_dead: bool,
}

struct LiveValueVec {
    /// The set of values that are live at the current program point.
    values: Vec<LiveValue>,

    /// How many values at the front of `values` are known to be live after `inst`?
    ///
    /// This is used to pass a much smaller slice to `partition_slice` when its called a second
    /// time for the same instruction.
    live_prefix: Option<(Inst, usize)>,
}

impl LiveValueVec {
    fn new() -> Self {
        Self {
            values: Vec::new(),
            live_prefix: None,
        }
    }

    /// Add a new live value to `values`. Copy some properties from `lr`.
    fn push(&mut self, value: Value, endpoint: Inst, lr: &LiveRange) {
        self.values.push(LiveValue {
            value,
            endpoint,
            affinity: lr.affinity,
            is_local: lr.is_local(),
            is_dead: lr.is_dead(),
        });
    }

    /// Remove all elements.
    fn clear(&mut self) {
        self.values.clear();
        self.live_prefix = None;
    }

    /// Make sure that the values killed by `next_inst` are moved to the end of the `values`
    /// vector.
    ///
    /// Returns the number of values that will be live after `next_inst`.
    fn live_after(&mut self, next_inst: Inst) -> usize {
        // How many values at the front of the vector are already known to survive `next_inst`?
        // We don't need to pass this prefix to `partition_slice()`
        let keep = match self.live_prefix {
            Some((i, prefix)) if i == next_inst => prefix,
            _ => 0,
        };

        // Move the remaining surviving values to the front partition of the vector.
        let prefix = keep + partition_slice(&mut self.values[keep..], |v| v.endpoint != next_inst);

        // Remember the new prefix length in case we get called again for the same `next_inst`.
        self.live_prefix = Some((next_inst, prefix));
        prefix
    }

    /// Remove the values killed by `next_inst`.
    fn remove_kill_values(&mut self, next_inst: Inst) {
        let keep = self.live_after(next_inst);
        self.values.truncate(keep);
    }

    /// Remove any dead values.
    fn remove_dead_values(&mut self) {
        self.values.retain(|v| !v.is_dead);
        self.live_prefix = None;
    }
}

impl LiveValueTracker {
    /// Create a new blank tracker.
    pub fn new() -> Self {
        Self {
            live: LiveValueVec::new(),
            idom_sets: HashMap::new(),
            idom_pool: ListPool::new(),
        }
    }

    /// Clear all cached information.
    pub fn clear(&mut self) {
        self.live.clear();
        self.idom_sets.clear();
        self.idom_pool.clear();
    }

    /// Get the set of currently live values.
    ///
    /// Between calls to `process_inst()` and `drop_dead()`, this includes both values killed and
    /// defined by the current instruction.
    pub fn live(&self) -> &[LiveValue] {
        &self.live.values
    }

    /// Get a mutable set of currently live values.
    ///
    /// Use with care and don't move entries around.
    pub fn live_mut(&mut self) -> &mut [LiveValue] {
        &mut self.live.values
    }

    /// Move the current position to the top of `ebb`.
    ///
    /// This depends on the stored live value set at `ebb`'s immediate dominator, so that must have
    /// been visited first.
    ///
    /// Returns `(liveins, args)` as a pair of slices. The first slice is the set of live-in values
    /// from the immediate dominator. The second slice is the set of `ebb` parameters.
    ///
    /// Dead parameters with no uses are included in `args`. Call `drop_dead_args()` to remove them.
    pub fn ebb_top(
        &mut self,
        ebb: Ebb,
        dfg: &DataFlowGraph,
        liveness: &Liveness,
        layout: &Layout,
        domtree: &DominatorTree,
    ) -> (&[LiveValue], &[LiveValue]) {
        // Start over, compute the set of live values at the top of the EBB from two sources:
        //
        // 1. Values that were live before `ebb`'s immediate dominator, filtered for those that are
        //    actually live-in.
        // 2. Arguments to `ebb` that are not dead.
        //
        self.live.clear();

        // Compute the live-in values. Start by filtering the set of values that were live before
        // the immediate dominator. Just use the empty set if there's no immediate dominator (i.e.,
        // the entry block or an unreachable block).
        if let Some(idom) = domtree.idom(ebb) {
            // If the immediate dominator exits, we must have a stored list for it. This is a
            // requirement to the order EBBs are visited: All dominators must have been processed
            // before the current EBB.
            let idom_live_list = self.idom_sets.get(&idom).expect(
                "No stored live set for dominator",
            );
            let ctx = liveness.context(layout);
            // Get just the values that are live-in to `ebb`.
            for &value in idom_live_list.as_slice(&self.idom_pool) {
                let lr = liveness.get(value).expect(
                    "Immediate dominator value has no live range",
                );

                // Check if this value is live-in here.
                if let Some(endpoint) = lr.livein_local_end(ebb, ctx) {
                    self.live.push(value, endpoint, lr);
                }
            }
        }

        // Now add all the live parameters to `ebb`.
        let first_arg = self.live.values.len();
        for &value in dfg.ebb_params(ebb) {
            let lr = &liveness[value];
            debug_assert_eq!(lr.def(), ebb.into());
            match lr.def_local_end().into() {
                ExpandedProgramPoint::Inst(endpoint) => {
                    self.live.push(value, endpoint, lr);
                }
                ExpandedProgramPoint::Ebb(local_ebb) => {
                    // This is a dead EBB parameter which is not even live into the first
                    // instruction in the EBB.
                    debug_assert_eq!(
                        local_ebb,
                        ebb,
                        "EBB parameter live range ends at wrong EBB header"
                    );
                    // Give this value a fake endpoint that is the first instruction in the EBB.
                    // We expect it to be removed by calling `drop_dead_args()`.
                    self.live.push(
                        value,
                        layout.first_inst(ebb).expect("Empty EBB"),
                        lr,
                    );
                }
            }
        }

        self.live.values.split_at(first_arg)
    }

    /// Prepare to move past `inst`.
    ///
    /// Determine the set of already live values that are killed by `inst`, and add the new defined
    /// values to the tracked set.
    ///
    /// Returns `(throughs, kills, defs)` as a tuple of slices:
    ///
    /// 1. The `throughs` slice is the set of live-through values that are neither defined nor
    ///    killed by the instruction.
    /// 2. The `kills` slice is the set of values that were live before the instruction and are
    ///    killed at the instruction. This does not include dead defs.
    /// 3. The `defs` slice is guaranteed to be in the same order as `inst`'s results, and includes
    ///    dead defines.
    ///
    /// The order of `throughs` and `kills` is arbitrary.
    ///
    /// The `drop_dead()` method must be called next to actually remove the dead values from the
    /// tracked set after the two returned slices are no longer needed.
    pub fn process_inst(
        &mut self,
        inst: Inst,
        dfg: &DataFlowGraph,
        liveness: &Liveness,
    ) -> (&[LiveValue], &[LiveValue], &[LiveValue]) {
        // Save a copy of the live values before any branches or jumps that could be somebody's
        // immediate dominator.
        if dfg[inst].opcode().is_branch() {
            self.save_idom_live_set(inst);
        }

        // Move killed values to the end of the vector.
        // Don't remove them yet, `drop_dead()` will do that.
        let first_kill = self.live.live_after(inst);

        // Add the values defined by `inst`.
        let first_def = self.live.values.len();
        for &value in dfg.inst_results(inst) {
            let lr = &liveness[value];
            debug_assert_eq!(lr.def(), inst.into());
            match lr.def_local_end().into() {
                ExpandedProgramPoint::Inst(endpoint) => {
                    self.live.push(value, endpoint, lr);
                }
                ExpandedProgramPoint::Ebb(ebb) => {
                    panic!("Instruction result live range can't end at {}", ebb);
                }
            }
        }

        (
            &self.live.values[0..first_kill],
            &self.live.values[first_kill..first_def],
            &self.live.values[first_def..],
        )
    }

    /// Prepare to move past a ghost instruction.
    ///
    /// This is like `process_inst`, except any defs are ignored.
    ///
    /// Returns `(throughs, kills)`.
    pub fn process_ghost(&mut self, inst: Inst) -> (&[LiveValue], &[LiveValue]) {
        let first_kill = self.live.live_after(inst);
        self.live.values.as_slice().split_at(first_kill)
    }

    /// Drop the values that are now dead after moving past `inst`.
    ///
    /// This removes both live values that were killed by `inst` and dead defines on `inst` itself.
    ///
    /// This must be called after `process_inst(inst)` and before proceeding to the next
    /// instruction.
    pub fn drop_dead(&mut self, inst: Inst) {
        // Remove both live values that were killed by `inst` and dead defines from `inst`.
        self.live.remove_kill_values(inst);
    }

    /// Drop any values that are marked as `is_dead`.
    ///
    /// Use this after calling `ebb_top` to clean out dead EBB parameters.
    pub fn drop_dead_params(&mut self) {
        self.live.remove_dead_values();
    }

    /// Process new spills.
    ///
    /// Any values where `f` returns true are spilled and will be treated as if their affinity was
    /// `Stack`.
    pub fn process_spills<F>(&mut self, mut f: F)
    where
        F: FnMut(Value) -> bool,
    {
        for lv in &mut self.live.values {
            if f(lv.value) {
                lv.affinity = Affinity::Stack;
            }
        }
    }

    /// Save the current set of live values so it is associated with `idom`.
    fn save_idom_live_set(&mut self, idom: Inst) {
        let values = self.live.values.iter().map(|lv| lv.value);
        let pool = &mut self.idom_pool;
        // If there already is a set saved for `idom`, just keep it.
        self.idom_sets.entry(idom).or_insert_with(|| {
            let mut list = ValueList::default();
            list.extend(values, pool);
            list
        });
    }
}
<|endoftext|>


<commit_before>//! Known Ethereum 2.0 clients and their fingerprints.
//!
//! Currently using identify to fingerprint.

use libp2p::identify::IdentifyInfo;
use serde::Serialize;
use strum::{AsRefStr, EnumIter, IntoStaticStr};

/// Various client and protocol information related to a node.
#[derive(Clone, Debug, Serialize)]
pub struct Client {
    /// The client's name (Ex: lighthouse, prism, nimbus, etc)
    pub kind: ClientKind,
    /// The client's version.
    pub version: String,
    /// The OS version of the client.
    pub os_version: String,
    /// The libp2p protocol version.
    pub protocol_version: String,
    /// Identify agent string
    pub agent_string: Option<String>,
}

#[derive(Clone, Copy, Debug, Serialize, PartialEq, AsRefStr, IntoStaticStr, EnumIter)]
pub enum ClientKind {
    /// A lighthouse node (the best kind).
    Lighthouse,
    /// A Nimbus node.
    Nimbus,
    /// A Teku node.
    Teku,
    /// A Prysm node.
    Prysm,
    /// A lodestar node.
    Lodestar,
    /// An unknown client.
    Unknown,
}

impl Default for Client {
    fn default() -> Self {
        Client {
            kind: ClientKind::Unknown,
            version: "unknown".into(),
            os_version: "unknown".into(),
            protocol_version: "unknown".into(),
            agent_string: None,
        }
    }
}

impl Client {
    /// Builds a `Client` from `IdentifyInfo`.
    pub fn from_identify_info(info: &IdentifyInfo) -> Self {
        let (kind, version, os_version) = client_from_agent_version(&info.agent_version);

        Client {
            kind,
            version,
            os_version,
            protocol_version: info.protocol_version.clone(),
            agent_string: Some(info.agent_version.clone()),
        }
    }
}

impl std::fmt::Display for Client {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        match self.kind {
            ClientKind::Lighthouse => write!(
                f,
                "Lighthouse: version: {}, os_version: {}",
                self.version, self.os_version
            ),
            ClientKind::Teku => write!(
                f,
                "Teku: version: {}, os_version: {}",
                self.version, self.os_version
            ),
            ClientKind::Nimbus => write!(
                f,
                "Nimbus: version: {}, os_version: {}",
                self.version, self.os_version
            ),
            ClientKind::Prysm => write!(
                f,
                "Prysm: version: {}, os_version: {}",
                self.version, self.os_version
            ),
            ClientKind::Lodestar => write!(f, "Lodestar: version: {}", self.version),
            ClientKind::Unknown => {
                if let Some(agent_string) = &self.agent_string {
                    write!(f, "Unknown: {}", agent_string)
                } else {
                    write!(f, "Unknown")
                }
            }
        }
    }
}

impl std::fmt::Display for ClientKind {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        f.write_str(self.as_ref())
    }
}

// helper function to identify clients from their agent_version. Returns the client
// kind and it's associated version and the OS kind.
fn client_from_agent_version(agent_version: &str) -> (ClientKind, String, String) {
    let mut agent_split = agent_version.split('/');
    match agent_split.next() {
        Some("Lighthouse") => {
            let kind = ClientKind::Lighthouse;
            let mut version = String::from("unknown");
            let mut os_version = version.clone();
            if let Some(agent_version) = agent_split.next() {
                version = agent_version.into();
                if let Some(agent_os_version) = agent_split.next() {
                    os_version = agent_os_version.into();
                }
            }
            (kind, version, os_version)
        }
        Some("teku") => {
            let kind = ClientKind::Teku;
            let mut version = String::from("unknown");
            let mut os_version = version.clone();
            if agent_split.next().is_some() {
                if let Some(agent_version) = agent_split.next() {
                    version = agent_version.into();
                    if let Some(agent_os_version) = agent_split.next() {
                        os_version = agent_os_version.into();
                    }
                }
            }
            (kind, version, os_version)
        }
        Some("github.com") => {
            let kind = ClientKind::Prysm;
            let unknown = String::from("unknown");
            (kind, unknown.clone(), unknown)
        }
        Some("Prysm") => {
            let kind = ClientKind::Prysm;
            let mut version = String::from("unknown");
            let mut os_version = version.clone();
            if agent_split.next().is_some() {
                if let Some(agent_version) = agent_split.next() {
                    version = agent_version.into();
                    if let Some(agent_os_version) = agent_split.next() {
                        os_version = agent_os_version.into();
                    }
                }
            }
            (kind, version, os_version)
        }
        Some("nimbus") => {
            let kind = ClientKind::Nimbus;
            let mut version = String::from("unknown");
            let mut os_version = version.clone();
            if agent_split.next().is_some() {
                if let Some(agent_version) = agent_split.next() {
                    version = agent_version.into();
                    if let Some(agent_os_version) = agent_split.next() {
                        os_version = agent_os_version.into();
                    }
                }
            }
            (kind, version, os_version)
        }
        Some("nim-libp2p") => {
            let kind = ClientKind::Nimbus;
            let mut version = String::from("unknown");
            let mut os_version = version.clone();
            if let Some(agent_version) = agent_split.next() {
                version = agent_version.into();
                if let Some(agent_os_version) = agent_split.next() {
                    os_version = agent_os_version.into();
                }
            }
            (kind, version, os_version)
        }
        Some("js-libp2p") => {
            let kind = ClientKind::Lodestar;
            let mut version = String::from("unknown");
            let mut os_version = version.clone();
            if let Some(agent_version) = agent_split.next() {
                version = agent_version.into();
                if let Some(agent_os_version) = agent_split.next() {
                    os_version = agent_os_version.into();
                }
            }
            (kind, version, os_version)
        }
        _ => {
            let unknown = String::from("unknown");
            (ClientKind::Unknown, unknown.clone(), unknown)
        }
    }
}
<commit_msg>Handle Lodestar's new agent string (#3620)<commit_after>//! Known Ethereum 2.0 clients and their fingerprints.
//!
//! Currently using identify to fingerprint.

use libp2p::identify::IdentifyInfo;
use serde::Serialize;
use strum::{AsRefStr, EnumIter, IntoStaticStr};

/// Various client and protocol information related to a node.
#[derive(Clone, Debug, Serialize)]
pub struct Client {
    /// The client's name (Ex: lighthouse, prism, nimbus, etc)
    pub kind: ClientKind,
    /// The client's version.
    pub version: String,
    /// The OS version of the client.
    pub os_version: String,
    /// The libp2p protocol version.
    pub protocol_version: String,
    /// Identify agent string
    pub agent_string: Option<String>,
}

#[derive(Clone, Copy, Debug, Serialize, PartialEq, AsRefStr, IntoStaticStr, EnumIter)]
pub enum ClientKind {
    /// A lighthouse node (the best kind).
    Lighthouse,
    /// A Nimbus node.
    Nimbus,
    /// A Teku node.
    Teku,
    /// A Prysm node.
    Prysm,
    /// A lodestar node.
    Lodestar,
    /// An unknown client.
    Unknown,
}

impl Default for Client {
    fn default() -> Self {
        Client {
            kind: ClientKind::Unknown,
            version: "unknown".into(),
            os_version: "unknown".into(),
            protocol_version: "unknown".into(),
            agent_string: None,
        }
    }
}

impl Client {
    /// Builds a `Client` from `IdentifyInfo`.
    pub fn from_identify_info(info: &IdentifyInfo) -> Self {
        let (kind, version, os_version) = client_from_agent_version(&info.agent_version);

        Client {
            kind,
            version,
            os_version,
            protocol_version: info.protocol_version.clone(),
            agent_string: Some(info.agent_version.clone()),
        }
    }
}

impl std::fmt::Display for Client {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        match self.kind {
            ClientKind::Lighthouse => write!(
                f,
                "Lighthouse: version: {}, os_version: {}",
                self.version, self.os_version
            ),
            ClientKind::Teku => write!(
                f,
                "Teku: version: {}, os_version: {}",
                self.version, self.os_version
            ),
            ClientKind::Nimbus => write!(
                f,
                "Nimbus: version: {}, os_version: {}",
                self.version, self.os_version
            ),
            ClientKind::Prysm => write!(
                f,
                "Prysm: version: {}, os_version: {}",
                self.version, self.os_version
            ),
            ClientKind::Lodestar => write!(f, "Lodestar: version: {}", self.version),
            ClientKind::Unknown => {
                if let Some(agent_string) = &self.agent_string {
                    write!(f, "Unknown: {}", agent_string)
                } else {
                    write!(f, "Unknown")
                }
            }
        }
    }
}

impl std::fmt::Display for ClientKind {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        f.write_str(self.as_ref())
    }
}

// helper function to identify clients from their agent_version. Returns the client
// kind and it's associated version and the OS kind.
fn client_from_agent_version(agent_version: &str) -> (ClientKind, String, String) {
    let mut agent_split = agent_version.split('/');
    match agent_split.next() {
        Some("Lighthouse") => {
            let kind = ClientKind::Lighthouse;
            let mut version = String::from("unknown");
            let mut os_version = version.clone();
            if let Some(agent_version) = agent_split.next() {
                version = agent_version.into();
                if let Some(agent_os_version) = agent_split.next() {
                    os_version = agent_os_version.into();
                }
            }
            (kind, version, os_version)
        }
        Some("teku") => {
            let kind = ClientKind::Teku;
            let mut version = String::from("unknown");
            let mut os_version = version.clone();
            if agent_split.next().is_some() {
                if let Some(agent_version) = agent_split.next() {
                    version = agent_version.into();
                    if let Some(agent_os_version) = agent_split.next() {
                        os_version = agent_os_version.into();
                    }
                }
            }
            (kind, version, os_version)
        }
        Some("github.com") => {
            let kind = ClientKind::Prysm;
            let unknown = String::from("unknown");
            (kind, unknown.clone(), unknown)
        }
        Some("Prysm") => {
            let kind = ClientKind::Prysm;
            let mut version = String::from("unknown");
            let mut os_version = version.clone();
            if agent_split.next().is_some() {
                if let Some(agent_version) = agent_split.next() {
                    version = agent_version.into();
                    if let Some(agent_os_version) = agent_split.next() {
                        os_version = agent_os_version.into();
                    }
                }
            }
            (kind, version, os_version)
        }
        Some("nimbus") => {
            let kind = ClientKind::Nimbus;
            let mut version = String::from("unknown");
            let mut os_version = version.clone();
            if agent_split.next().is_some() {
                if let Some(agent_version) = agent_split.next() {
                    version = agent_version.into();
                    if let Some(agent_os_version) = agent_split.next() {
                        os_version = agent_os_version.into();
                    }
                }
            }
            (kind, version, os_version)
        }
        Some("nim-libp2p") => {
            let kind = ClientKind::Nimbus;
            let mut version = String::from("unknown");
            let mut os_version = version.clone();
            if let Some(agent_version) = agent_split.next() {
                version = agent_version.into();
                if let Some(agent_os_version) = agent_split.next() {
                    os_version = agent_os_version.into();
                }
            }
            (kind, version, os_version)
        }
        Some("js-libp2p") | Some("lodestar") => {
            let kind = ClientKind::Lodestar;
            let mut version = String::from("unknown");
            let mut os_version = version.clone();
            if let Some(agent_version) = agent_split.next() {
                version = agent_version.into();
                if let Some(agent_os_version) = agent_split.next() {
                    os_version = agent_os_version.into();
                }
            }
            (kind, version, os_version)
        }
        _ => {
            let unknown = String::from("unknown");
            (ClientKind::Unknown, unknown.clone(), unknown)
        }
    }
}
<|endoftext|>


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

use std::ops::Range;

use buffer::BufferSlice;
use buffer::sys::UnsafeBuffer;
use device::DeviceOwned;
use device::Queue;
use image::Image;
use memory::Content;

use SafeDeref;
use VulkanObject;

/// Trait for objects that represent either a buffer or a slice of a buffer.
pub unsafe trait Buffer: DeviceOwned {
    /// Returns the inner information about this buffer.
    fn inner(&self) -> BufferInner;

    /// Returns the size of the buffer in bytes.
    #[inline]
    fn size(&self) -> usize {
        self.inner().buffer.size()
    }

    /// Returns the length of the buffer in number of elements.
    ///
    /// This method can only be called for buffers whose type is known to be an array.
    #[inline]
    fn len(&self) -> usize where Self: TypedBuffer, Self::Content: Content {
        self.size() / <Self::Content as Content>::indiv_size()
    }

    /// Builds a `BufferSlice` object holding the buffer by reference.
    #[inline]
    fn as_buffer_slice(&self) -> BufferSlice<Self::Content, &Self>
        where Self: Sized + TypedBuffer
    {
        BufferSlice::from(self)
    }

    /// Builds a `BufferSlice` object holding part of the buffer by reference.
    ///
    /// This method can only be called for buffers whose type is known to be an array.
    ///
    /// This method can be used when you want to perform an operation on some part of the buffer
    /// and not on the whole buffer.
    ///
    /// Returns `None` if out of range.
    #[inline]
    fn slice<T>(&self, range: Range<usize>) -> Option<BufferSlice<[T], &Self>>
        where Self: Sized + TypedBuffer<Content = [T]>,
              T: 'static
    {
        BufferSlice::slice(self.as_buffer_slice(), range)
    }

    /// Builds a `BufferSlice` object holding the buffer by value.
    #[inline]
    fn into_buffer_slice(self) -> BufferSlice<Self::Content, Self>
        where Self: Sized + TypedBuffer
    {
        BufferSlice::from(self)
    }

    /// Returns true if an access to `self` (as defined by `self_offset` and `self_size`)
    /// potentially overlaps the same memory as an access to `other` (as defined by `other_offset`
    /// and `other_size`).
    ///
    /// If this function returns `false`, this means that we are allowed to access the offset/size
    /// of `self` at the same time as the offset/size of `other` without causing a data race.
    fn conflicts_buffer(&self, self_offset: usize, self_size: usize,
                        other: &Buffer, other_offset: usize, other_size: usize)
                        -> bool
    {
        // TODO: should we really provide a default implementation?

        debug_assert!(self_size <= self.size());

        if self.inner().buffer.internal_object() != other.inner().buffer.internal_object() {
            return false;
        }

        let self_offset = self_offset + self.inner().offset;
        let other_offset = other_offset + other.inner().offset;

        if self_offset < other_offset && self_offset + self_size <= other_offset {
            return false;
        }

        if other_offset < self_offset && other_offset + other_size <= self_offset {
            return false;
        }

        true
    }

    /// Returns true if an access to `self` (as defined by `self_offset` and `self_size`)
    /// potentially overlaps the same memory as an access to `other` (as defined by
    /// `other_first_layer`, `other_num_layers`, `other_first_mipmap` and `other_num_mipmaps`).
    ///
    /// If this function returns `false`, this means that we are allowed to access the offset/size
    /// of `self` at the same time as the offset/size of `other` without causing a data race.
    fn conflicts_image(&self, self_offset: usize, self_size: usize, other: &Image,
                       other_first_layer: u32, other_num_layers: u32, other_first_mipmap: u32,
                       other_num_mipmaps: u32) -> bool
    {
        let other_key = other.conflict_key(other_first_layer, other_num_layers, other_first_mipmap,
                                           other_num_mipmaps);
        self.conflict_key(self_offset, self_size) == other_key
    }

    /// Returns a key that uniquely identifies the range given by offset/size.
    ///
    /// Two ranges that potentially overlap in memory should return the same key.
    ///
    /// The key is shared amongst all buffers and images, which means that you can make several
    /// different buffer objects share the same memory, or make some buffer objects share memory
    /// with images, as long as they return the same key.
    ///
    /// Since it is possible to accidentally return the same key for memory ranges that don't
    /// overlap, the `conflicts_buffer` or `conflicts_image` function should always be called to
    /// verify whether they actually overlap.
    fn conflict_key(&self, self_offset: usize, self_size: usize) -> u64 {
        // FIXME: remove implementation
        unimplemented!()
    }

    /// Locks the resource for usage on the GPU. Returns `false` if the lock was already acquired.
    ///
    /// This function implementation should remember that it has been called and return `false` if
    /// it gets called a second time.
    ///
    /// The only way to know that the GPU has stopped accessing a queue is when the buffer object
    /// gets destroyed. Therefore you are encouraged to use temporary objects or handles (similar
    /// to a lock) in order to represent a GPU access.
    // TODO: return Result?
    fn try_gpu_lock(&self, exclusive_access: bool, queue: &Queue) -> bool;

    /// Locks the resource for usage on the GPU. Supposes that the resource is already locked, and
    /// simply increases the lock by one.
    ///
    /// Must only be called after `try_gpu_lock()` succeeded.
    unsafe fn increase_gpu_lock(&self);
}

/// Inner information about a buffer.
#[derive(Copy, Clone, Debug)]
pub struct BufferInner<'a> {
    /// The underlying buffer object.
    pub buffer: &'a UnsafeBuffer,
    /// The offset in bytes from the start of the underlying buffer object to the start of the
    /// buffer we're describing.
    pub offset: usize,
}

unsafe impl<T> Buffer for T where T: SafeDeref, T::Target: Buffer {
    #[inline]
    fn inner(&self) -> BufferInner {
        (**self).inner()
    }

    #[inline]
    fn size(&self) -> usize {
        (**self).size()
    }

    #[inline]
    fn conflicts_buffer(&self, self_offset: usize, self_size: usize,
                        other: &Buffer, other_offset: usize, other_size: usize) -> bool
    {
        (**self).conflicts_buffer(self_offset, self_size, other, other_offset, other_size)
    }

    #[inline]
    fn conflict_key(&self, self_offset: usize, self_size: usize) -> u64 {
        (**self).conflict_key(self_offset, self_size)
    }

    #[inline]
    fn try_gpu_lock(&self, exclusive_access: bool, queue: &Queue) -> bool {
        (**self).try_gpu_lock(exclusive_access, queue)
    }

    #[inline]
    unsafe fn increase_gpu_lock(&self) {
        (**self).increase_gpu_lock()
    }
}

pub unsafe trait TypedBuffer: Buffer {
    type Content: ?Sized + 'static;
}

unsafe impl<T> TypedBuffer for T where T: SafeDeref, T::Target: TypedBuffer {
    type Content = <T::Target as TypedBuffer>::Content;
}
<commit_msg>Add Buffer::index method<commit_after>// Copyright (c) 2016 The vulkano developers
// Licensed under the Apache License, Version 2.0
// <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT
// license <LICENSE-MIT or http://opensource.org/licenses/MIT>,
// at your option. All files in the project carrying such
// notice may not be copied, modified, or distributed except
// according to those terms.

use std::ops::Range;

use buffer::BufferSlice;
use buffer::sys::UnsafeBuffer;
use device::DeviceOwned;
use device::Queue;
use image::Image;
use memory::Content;

use SafeDeref;
use VulkanObject;

/// Trait for objects that represent either a buffer or a slice of a buffer.
pub unsafe trait Buffer: DeviceOwned {
    /// Returns the inner information about this buffer.
    fn inner(&self) -> BufferInner;

    /// Returns the size of the buffer in bytes.
    #[inline]
    fn size(&self) -> usize {
        self.inner().buffer.size()
    }

    /// Returns the length of the buffer in number of elements.
    ///
    /// This method can only be called for buffers whose type is known to be an array.
    #[inline]
    fn len(&self) -> usize where Self: TypedBuffer, Self::Content: Content {
        self.size() / <Self::Content as Content>::indiv_size()
    }

    /// Builds a `BufferSlice` object holding the buffer by reference.
    #[inline]
    fn as_buffer_slice(&self) -> BufferSlice<Self::Content, &Self>
        where Self: Sized + TypedBuffer
    {
        BufferSlice::from(self)
    }

    /// Builds a `BufferSlice` object holding part of the buffer by reference.
    ///
    /// This method can only be called for buffers whose type is known to be an array.
    ///
    /// This method can be used when you want to perform an operation on some part of the buffer
    /// and not on the whole buffer.
    ///
    /// Returns `None` if out of range.
    #[inline]
    fn slice<T>(&self, range: Range<usize>) -> Option<BufferSlice<[T], &Self>>
        where Self: Sized + TypedBuffer<Content = [T]>,
              T: 'static
    {
        BufferSlice::slice(self.as_buffer_slice(), range)
    }

    /// Builds a `BufferSlice` object holding the buffer by value.
    #[inline]
    fn into_buffer_slice(self) -> BufferSlice<Self::Content, Self>
        where Self: Sized + TypedBuffer
    {
        BufferSlice::from(self)
    }

    /// Builds a `BufferSlice` object holding part of the buffer by reference.
    ///
    /// This method can only be called for buffers whose type is known to be an array.
    ///
    /// This method can be used when you want to perform an operation on a specific element of the
    /// buffer and not on the whole buffer.
    ///
    /// Returns `None` if out of range.
    #[inline]
    fn index<T>(&self, index: usize) -> Option<BufferSlice<[T], &Self>>
        where Self: Sized + TypedBuffer<Content = [T]>,
              T: 'static
    {
        self.slice(index .. (index + 1))
    }

    /// Returns true if an access to `self` (as defined by `self_offset` and `self_size`)
    /// potentially overlaps the same memory as an access to `other` (as defined by `other_offset`
    /// and `other_size`).
    ///
    /// If this function returns `false`, this means that we are allowed to access the offset/size
    /// of `self` at the same time as the offset/size of `other` without causing a data race.
    fn conflicts_buffer(&self, self_offset: usize, self_size: usize,
                        other: &Buffer, other_offset: usize, other_size: usize)
                        -> bool
    {
        // TODO: should we really provide a default implementation?

        debug_assert!(self_size <= self.size());

        if self.inner().buffer.internal_object() != other.inner().buffer.internal_object() {
            return false;
        }

        let self_offset = self_offset + self.inner().offset;
        let other_offset = other_offset + other.inner().offset;

        if self_offset < other_offset && self_offset + self_size <= other_offset {
            return false;
        }

        if other_offset < self_offset && other_offset + other_size <= self_offset {
            return false;
        }

        true
    }

    /// Returns true if an access to `self` (as defined by `self_offset` and `self_size`)
    /// potentially overlaps the same memory as an access to `other` (as defined by
    /// `other_first_layer`, `other_num_layers`, `other_first_mipmap` and `other_num_mipmaps`).
    ///
    /// If this function returns `false`, this means that we are allowed to access the offset/size
    /// of `self` at the same time as the offset/size of `other` without causing a data race.
    fn conflicts_image(&self, self_offset: usize, self_size: usize, other: &Image,
                       other_first_layer: u32, other_num_layers: u32, other_first_mipmap: u32,
                       other_num_mipmaps: u32) -> bool
    {
        let other_key = other.conflict_key(other_first_layer, other_num_layers, other_first_mipmap,
                                           other_num_mipmaps);
        self.conflict_key(self_offset, self_size) == other_key
    }

    /// Returns a key that uniquely identifies the range given by offset/size.
    ///
    /// Two ranges that potentially overlap in memory should return the same key.
    ///
    /// The key is shared amongst all buffers and images, which means that you can make several
    /// different buffer objects share the same memory, or make some buffer objects share memory
    /// with images, as long as they return the same key.
    ///
    /// Since it is possible to accidentally return the same key for memory ranges that don't
    /// overlap, the `conflicts_buffer` or `conflicts_image` function should always be called to
    /// verify whether they actually overlap.
    fn conflict_key(&self, self_offset: usize, self_size: usize) -> u64 {
        // FIXME: remove implementation
        unimplemented!()
    }

    /// Locks the resource for usage on the GPU. Returns `false` if the lock was already acquired.
    ///
    /// This function implementation should remember that it has been called and return `false` if
    /// it gets called a second time.
    ///
    /// The only way to know that the GPU has stopped accessing a queue is when the buffer object
    /// gets destroyed. Therefore you are encouraged to use temporary objects or handles (similar
    /// to a lock) in order to represent a GPU access.
    // TODO: return Result?
    fn try_gpu_lock(&self, exclusive_access: bool, queue: &Queue) -> bool;

    /// Locks the resource for usage on the GPU. Supposes that the resource is already locked, and
    /// simply increases the lock by one.
    ///
    /// Must only be called after `try_gpu_lock()` succeeded.
    unsafe fn increase_gpu_lock(&self);
}

/// Inner information about a buffer.
#[derive(Copy, Clone, Debug)]
pub struct BufferInner<'a> {
    /// The underlying buffer object.
    pub buffer: &'a UnsafeBuffer,
    /// The offset in bytes from the start of the underlying buffer object to the start of the
    /// buffer we're describing.
    pub offset: usize,
}

unsafe impl<T> Buffer for T where T: SafeDeref, T::Target: Buffer {
    #[inline]
    fn inner(&self) -> BufferInner {
        (**self).inner()
    }

    #[inline]
    fn size(&self) -> usize {
        (**self).size()
    }

    #[inline]
    fn conflicts_buffer(&self, self_offset: usize, self_size: usize,
                        other: &Buffer, other_offset: usize, other_size: usize) -> bool
    {
        (**self).conflicts_buffer(self_offset, self_size, other, other_offset, other_size)
    }

    #[inline]
    fn conflict_key(&self, self_offset: usize, self_size: usize) -> u64 {
        (**self).conflict_key(self_offset, self_size)
    }

    #[inline]
    fn try_gpu_lock(&self, exclusive_access: bool, queue: &Queue) -> bool {
        (**self).try_gpu_lock(exclusive_access, queue)
    }

    #[inline]
    unsafe fn increase_gpu_lock(&self) {
        (**self).increase_gpu_lock()
    }
}

pub unsafe trait TypedBuffer: Buffer {
    type Content: ?Sized + 'static;
}

unsafe impl<T> TypedBuffer for T where T: SafeDeref, T::Target: TypedBuffer {
    type Content = <T::Target as TypedBuffer>::Content;
}
<|endoftext|>