buffer/image desc; queueflags
This commit is contained in:
parent
e3db023ec4
commit
da0befbeaf
|
@ -1,12 +1,67 @@
|
|||
use std::{
|
||||
borrow::Cow,
|
||||
ops::{Deref, DerefMut},
|
||||
sync::Arc,
|
||||
};
|
||||
|
||||
use ash::{prelude::VkResult, vk};
|
||||
use itertools::Itertools;
|
||||
use vk_mem::Alloc;
|
||||
|
||||
use crate::{define_device_owned_handle, device::DeviceOwned, Device};
|
||||
use crate::{
|
||||
define_device_owned_handle,
|
||||
device::{DeviceOwned, QueueFlags},
|
||||
Device,
|
||||
};
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct BufferDesc {
|
||||
pub flags: vk::BufferCreateFlags,
|
||||
pub name: Option<Cow<'static, str>>,
|
||||
pub size: u64,
|
||||
pub usage: vk::BufferUsageFlags,
|
||||
pub queue_families: QueueFlags,
|
||||
|
||||
pub mem_usage: vk_mem::MemoryUsage,
|
||||
pub alloc_flags: vk_mem::AllocationCreateFlags,
|
||||
}
|
||||
|
||||
impl std::fmt::Debug for BufferDesc {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
f.debug_struct("BufferDesc")
|
||||
.field("flags", &self.flags)
|
||||
.field("name", &self.name)
|
||||
.field("size", &self.size)
|
||||
.field("usage", &self.usage)
|
||||
.field("queue_families", &self.queue_families)
|
||||
.field("mem_usage", &self.mem_usage)
|
||||
.field_with("alloc_flags", |f| {
|
||||
write!(
|
||||
f,
|
||||
"{}",
|
||||
self.alloc_flags
|
||||
.iter_names()
|
||||
.map(|(name, _)| name)
|
||||
.format(" | ")
|
||||
)
|
||||
})
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for BufferDesc {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
flags: Default::default(),
|
||||
name: Default::default(),
|
||||
size: Default::default(),
|
||||
usage: Default::default(),
|
||||
queue_families: QueueFlags::empty(),
|
||||
alloc_flags: vk_mem::AllocationCreateFlags::empty(),
|
||||
mem_usage: vk_mem::MemoryUsage::Auto,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
define_device_owned_handle! {
|
||||
#[derive(Debug)]
|
||||
|
@ -19,15 +74,9 @@ define_device_owned_handle! {
|
|||
}
|
||||
|
||||
impl Buffer {
|
||||
pub fn new(
|
||||
device: Device,
|
||||
size: usize,
|
||||
usage: vk::BufferUsageFlags,
|
||||
queue_families: &[u32],
|
||||
memory_usage: vk_mem::MemoryUsage,
|
||||
alloc_flags: vk_mem::AllocationCreateFlags,
|
||||
name: Option<std::borrow::Cow<'static, str>>,
|
||||
) -> VkResult<Arc<Self>> {
|
||||
pub fn new(device: Device, desc: BufferDesc) -> VkResult<Arc<Self>> {
|
||||
let queue_families = device.queue_families().family_indices(desc.queue_families);
|
||||
|
||||
let sharing_mode = if queue_families.len() > 1 {
|
||||
vk::SharingMode::CONCURRENT
|
||||
} else {
|
||||
|
@ -37,24 +86,20 @@ impl Buffer {
|
|||
let (buffer, allocation) = unsafe {
|
||||
device.alloc().create_buffer(
|
||||
&vk::BufferCreateInfo::default()
|
||||
.size(size as u64)
|
||||
.usage(usage)
|
||||
.queue_family_indices(queue_families)
|
||||
.size(desc.size)
|
||||
.usage(desc.usage)
|
||||
.queue_family_indices(&queue_families)
|
||||
.sharing_mode(sharing_mode),
|
||||
&vk_mem::AllocationCreateInfo {
|
||||
flags: alloc_flags,
|
||||
usage: memory_usage,
|
||||
flags: desc.alloc_flags,
|
||||
usage: desc.mem_usage,
|
||||
..Default::default()
|
||||
},
|
||||
)?
|
||||
};
|
||||
|
||||
Ok(Arc::new(Self::construct(
|
||||
device,
|
||||
buffer,
|
||||
name,
|
||||
allocation,
|
||||
size as u64,
|
||||
device, buffer, desc.name, allocation, desc.size,
|
||||
)?))
|
||||
}
|
||||
|
||||
|
|
|
@ -40,6 +40,41 @@ impl DeviceQueueFamilies {
|
|||
pub fn transfer_familty(&self) -> u32 {
|
||||
self.transfer.0
|
||||
}
|
||||
|
||||
pub fn family_indices(&self, flags: QueueFlags) -> ArrayVec<[u32; 4]> {
|
||||
let mut indices = array_vec!([u32; 4]);
|
||||
if flags.contains(QueueFlags::GRAPHICS) {
|
||||
indices.push(self.graphics_familty());
|
||||
}
|
||||
if flags.contains(QueueFlags::PRESENT) {
|
||||
indices.push(self.present_familty());
|
||||
}
|
||||
if flags.contains(QueueFlags::ASYNC_COMPUTE) {
|
||||
indices.push(self.async_compute_familty());
|
||||
}
|
||||
if flags.contains(QueueFlags::TRANSFER) {
|
||||
indices.push(self.transfer_familty());
|
||||
}
|
||||
|
||||
let unique_len = indices.partition_dedup().0.len();
|
||||
indices.drain(unique_len..);
|
||||
|
||||
indices
|
||||
}
|
||||
}
|
||||
|
||||
bitflags::bitflags! {
|
||||
#[repr(transparent)]
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
||||
pub struct QueueFlags: u32 {
|
||||
const GRAPHICS = 1 << 0;
|
||||
const PRESENT = 1 << 1;
|
||||
const ASYNC_COMPUTE = 1 << 2;
|
||||
const TRANSFER = 1 << 3;
|
||||
|
||||
const NONE = 0;
|
||||
const PRESENT_GRAPHICS = 1 << 0 | 1 << 1;
|
||||
}
|
||||
}
|
||||
|
||||
#[repr(transparent)]
|
||||
|
@ -186,6 +221,9 @@ impl Device {
|
|||
pub fn dev(&self) -> &ash::Device {
|
||||
&self.0.device
|
||||
}
|
||||
pub fn instance(&self) -> &Arc<Instance> {
|
||||
&self.0.instance
|
||||
}
|
||||
pub fn swapchain(&self) -> &khr::swapchain::Device {
|
||||
&self.0.swapchain
|
||||
}
|
||||
|
|
|
@ -1,6 +1,9 @@
|
|||
use std::borrow::Cow;
|
||||
|
||||
use crate::{define_device_owned_handle, device::DeviceOwned};
|
||||
use crate::{
|
||||
define_device_owned_handle,
|
||||
device::{DeviceOwned, QueueFlags},
|
||||
};
|
||||
|
||||
use super::Device;
|
||||
use ash::{prelude::*, vk};
|
||||
|
@ -8,7 +11,7 @@ use itertools::Itertools;
|
|||
use vk_mem::Alloc;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct ImageDesc<'a> {
|
||||
pub struct ImageDesc {
|
||||
pub flags: vk::ImageCreateFlags,
|
||||
pub name: Option<Cow<'static, str>>,
|
||||
pub format: vk::Format,
|
||||
|
@ -19,14 +22,14 @@ pub struct ImageDesc<'a> {
|
|||
pub extent: vk::Extent3D,
|
||||
pub tiling: vk::ImageTiling,
|
||||
pub usage: vk::ImageUsageFlags,
|
||||
pub queue_families: &'a [u32],
|
||||
pub queue_families: QueueFlags,
|
||||
pub layout: vk::ImageLayout,
|
||||
|
||||
pub mem_usage: vk_mem::MemoryUsage,
|
||||
pub alloc_flags: vk_mem::AllocationCreateFlags,
|
||||
}
|
||||
|
||||
impl<'a> std::fmt::Debug for ImageDesc<'a> {
|
||||
impl<'a> std::fmt::Debug for ImageDesc {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
f.debug_struct("ImageDesc")
|
||||
.field("flags", &self.flags)
|
||||
|
@ -56,7 +59,7 @@ impl<'a> std::fmt::Debug for ImageDesc<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'a> Default for ImageDesc<'a> {
|
||||
impl Default for ImageDesc {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
flags: Default::default(),
|
||||
|
@ -69,7 +72,7 @@ impl<'a> Default for ImageDesc<'a> {
|
|||
extent: Default::default(),
|
||||
tiling: vk::ImageTiling::OPTIMAL,
|
||||
usage: Default::default(),
|
||||
queue_families: &[],
|
||||
queue_families: QueueFlags::empty(),
|
||||
layout: vk::ImageLayout::UNDEFINED,
|
||||
alloc_flags: vk_mem::AllocationCreateFlags::empty(),
|
||||
mem_usage: vk_mem::MemoryUsage::Auto,
|
||||
|
@ -106,6 +109,15 @@ impl Image {
|
|||
mem_usage,
|
||||
alloc_flags,
|
||||
} = desc;
|
||||
|
||||
let queue_families = device.queue_families().family_indices(queue_families);
|
||||
|
||||
let sharing_mode = if queue_families.len() > 1 {
|
||||
vk::SharingMode::CONCURRENT
|
||||
} else {
|
||||
vk::SharingMode::EXCLUSIVE
|
||||
};
|
||||
|
||||
let info = &vk::ImageCreateInfo::default()
|
||||
.flags(flags)
|
||||
.image_type(kind)
|
||||
|
@ -115,12 +127,8 @@ impl Image {
|
|||
.initial_layout(layout)
|
||||
.tiling(tiling)
|
||||
.usage(usage)
|
||||
.sharing_mode(if queue_families.len() > 1 {
|
||||
vk::SharingMode::CONCURRENT
|
||||
} else {
|
||||
vk::SharingMode::EXCLUSIVE
|
||||
})
|
||||
.queue_family_indices(queue_families)
|
||||
.sharing_mode(sharing_mode)
|
||||
.queue_family_indices(&queue_families)
|
||||
.array_layers(array_layers)
|
||||
.mip_levels(mip_levels);
|
||||
|
||||
|
|
|
@ -4,7 +4,8 @@
|
|||
let_chains,
|
||||
negative_impls,
|
||||
map_try_insert,
|
||||
debug_closure_helpers
|
||||
debug_closure_helpers,
|
||||
slice_partition_dedup
|
||||
)]
|
||||
|
||||
use std::{
|
||||
|
@ -18,7 +19,6 @@ use std::{
|
|||
atomic::{AtomicU32, AtomicU64},
|
||||
Arc,
|
||||
},
|
||||
time::Instant,
|
||||
};
|
||||
|
||||
use egui::Color32;
|
||||
|
@ -61,7 +61,7 @@ mod texture {
|
|||
Device,
|
||||
};
|
||||
|
||||
def_monotonic_id!(TextureId);
|
||||
def_monotonic_id!(pub TextureId);
|
||||
|
||||
pub struct Texture {
|
||||
id: TextureId,
|
||||
|
@ -125,7 +125,7 @@ mod texture {
|
|||
}
|
||||
}
|
||||
|
||||
use render_graph::Rgba;
|
||||
use util::Rgba;
|
||||
|
||||
#[derive(Debug, thiserror::Error)]
|
||||
pub enum Error {
|
||||
|
@ -526,9 +526,9 @@ impl SwapchainHandle {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Swapchain {
|
||||
device: Device,
|
||||
instance: Arc<Instance>,
|
||||
// has a strong ref to the surface because the surface may not outlive the swapchain
|
||||
surface: Arc<Surface>,
|
||||
swapchain: SwapchainHandle,
|
||||
|
@ -610,6 +610,7 @@ struct SwapchainParams {
|
|||
extent: vk::Extent2D,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
#[must_use = "This struct represents an acquired image from the swapchain and
|
||||
must be presented in order to free resources on the device."]
|
||||
pub struct SwapchainFrame {
|
||||
|
@ -696,17 +697,15 @@ impl Swapchain {
|
|||
}
|
||||
|
||||
pub fn new(
|
||||
instance: Arc<Instance>,
|
||||
device: Device,
|
||||
surface: Arc<Surface>,
|
||||
pdev: vk::PhysicalDevice,
|
||||
extent: vk::Extent2D,
|
||||
) -> Result<Self> {
|
||||
Self::create(instance, device, surface, pdev, Some(extent), None)
|
||||
Self::create(device, surface, pdev, Some(extent), None)
|
||||
}
|
||||
|
||||
fn create(
|
||||
instance: Arc<Instance>,
|
||||
device: Device,
|
||||
surface: Arc<Surface>,
|
||||
pdev: vk::PhysicalDevice,
|
||||
|
@ -720,7 +719,12 @@ impl Swapchain {
|
|||
image_count,
|
||||
min_image_count,
|
||||
extent,
|
||||
} = Self::get_swapchain_params_from_surface(&instance, surface.surface, pdev, extent)?;
|
||||
} = Self::get_swapchain_params_from_surface(
|
||||
device.instance(),
|
||||
surface.surface,
|
||||
pdev,
|
||||
extent,
|
||||
)?;
|
||||
|
||||
let (swapchain, images) = {
|
||||
let lock = old_swapchain.as_ref().map(|handle| handle.lock());
|
||||
|
@ -841,7 +845,6 @@ impl Swapchain {
|
|||
tracing::debug!("fences: {fences:?}");
|
||||
|
||||
Ok(Self {
|
||||
instance,
|
||||
device,
|
||||
surface,
|
||||
swapchain,
|
||||
|
@ -870,7 +873,6 @@ impl Swapchain {
|
|||
|
||||
fn recreate(&self, extent: Option<vk::Extent2D>) -> Result<Self> {
|
||||
Self::create(
|
||||
self.instance.clone(),
|
||||
self.device.clone(),
|
||||
self.surface.clone(),
|
||||
self.device.phy(),
|
||||
|
@ -1035,6 +1037,14 @@ pub struct Surface {
|
|||
surface: vk::SurfaceKHR,
|
||||
}
|
||||
|
||||
impl Debug for Surface {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
f.debug_struct("Surface")
|
||||
.field("surface", &self.surface)
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
||||
impl Surface {
|
||||
#[allow(dead_code)]
|
||||
fn headless(instance: Arc<Instance>) -> Result<Self> {
|
||||
|
@ -1734,7 +1744,6 @@ impl WindowContext {
|
|||
let surface = Arc::new(Surface::create(instance.clone(), display, window_handle)?);
|
||||
|
||||
let swapchain = Arc::new(Swapchain::new(
|
||||
instance,
|
||||
device.clone(),
|
||||
surface.clone(),
|
||||
device.phy(),
|
||||
|
@ -2081,16 +2090,19 @@ impl<W> Renderer<W> {
|
|||
.map(|(egui_id, delta)| {
|
||||
let size = delta.image.size();
|
||||
let byte_size = size[0] * size[1] * 4;
|
||||
|
||||
let mut staging = buffers::Buffer::new(
|
||||
self.vulkan.device.clone(),
|
||||
byte_size,
|
||||
vk::BufferUsageFlags::TRANSFER_SRC,
|
||||
&[],
|
||||
vk_mem::MemoryUsage::AutoPreferHost,
|
||||
vk_mem::AllocationCreateFlags::MAPPED
|
||||
| vk_mem::AllocationCreateFlags::HOST_ACCESS_SEQUENTIAL_WRITE
|
||||
| vk_mem::AllocationCreateFlags::STRATEGY_FIRST_FIT,
|
||||
Some(format!("egui-{egui_id:?}-staging-buf").into()),
|
||||
buffers::BufferDesc {
|
||||
name: Some(format!("egui-{egui_id:?}-staging-buf").into()),
|
||||
size: byte_size as u64,
|
||||
usage: vk::BufferUsageFlags::TRANSFER_SRC,
|
||||
mem_usage: vk_mem::MemoryUsage::AutoPreferHost,
|
||||
alloc_flags: vk_mem::AllocationCreateFlags::MAPPED
|
||||
| vk_mem::AllocationCreateFlags::HOST_ACCESS_SEQUENTIAL_WRITE
|
||||
| vk_mem::AllocationCreateFlags::STRATEGY_FIRST_FIT,
|
||||
..Default::default()
|
||||
},
|
||||
)
|
||||
.expect("staging buffer");
|
||||
{
|
||||
|
@ -2327,13 +2339,16 @@ impl<W> Renderer<W> {
|
|||
|
||||
let mut staging = buffers::Buffer::new(
|
||||
device.clone(),
|
||||
staging_size,
|
||||
vk::BufferUsageFlags::TRANSFER_SRC,
|
||||
&[device.queue_families().graphics_familty()],
|
||||
vk_mem::MemoryUsage::AutoPreferHost,
|
||||
vk_mem::AllocationCreateFlags::HOST_ACCESS_SEQUENTIAL_WRITE
|
||||
| vk_mem::AllocationCreateFlags::MAPPED,
|
||||
Some("egui-draw-staging".into()),
|
||||
buffers::BufferDesc {
|
||||
name: Some("egui-draw-staging".into()),
|
||||
size: staging_size as u64,
|
||||
usage: vk::BufferUsageFlags::TRANSFER_SRC,
|
||||
mem_usage: vk_mem::MemoryUsage::AutoPreferHost,
|
||||
alloc_flags: vk_mem::AllocationCreateFlags::MAPPED
|
||||
| vk_mem::AllocationCreateFlags::HOST_ACCESS_SEQUENTIAL_WRITE
|
||||
| vk_mem::AllocationCreateFlags::STRATEGY_FIRST_FIT,
|
||||
..Default::default()
|
||||
},
|
||||
)?;
|
||||
|
||||
{
|
||||
|
@ -2348,30 +2363,34 @@ impl<W> Renderer<W> {
|
|||
|
||||
let vertices = buffers::Buffer::new(
|
||||
device.clone(),
|
||||
vertices_size,
|
||||
vk::BufferUsageFlags::VERTEX_BUFFER | vk::BufferUsageFlags::TRANSFER_DST,
|
||||
&[device.queue_families().graphics_familty()],
|
||||
vk_mem::MemoryUsage::AutoPreferDevice,
|
||||
vk_mem::AllocationCreateFlags::empty(),
|
||||
Some("egui-draw-vertices".into()),
|
||||
buffers::BufferDesc {
|
||||
name: Some("egui-draw-vertices".into()),
|
||||
size: vertices_size as u64,
|
||||
usage: vk::BufferUsageFlags::TRANSFER_DST | vk::BufferUsageFlags::VERTEX_BUFFER,
|
||||
mem_usage: vk_mem::MemoryUsage::AutoPreferDevice,
|
||||
..Default::default()
|
||||
},
|
||||
)?;
|
||||
let indices = buffers::Buffer::new(
|
||||
device.clone(),
|
||||
indices_size,
|
||||
vk::BufferUsageFlags::INDEX_BUFFER | vk::BufferUsageFlags::TRANSFER_DST,
|
||||
&[device.queue_families().graphics_familty()],
|
||||
vk_mem::MemoryUsage::AutoPreferDevice,
|
||||
vk_mem::AllocationCreateFlags::empty(),
|
||||
Some("egui-draw-indices".into()),
|
||||
buffers::BufferDesc {
|
||||
name: Some("egui-draw-indices".into()),
|
||||
size: indices_size as u64,
|
||||
usage: vk::BufferUsageFlags::TRANSFER_DST | vk::BufferUsageFlags::INDEX_BUFFER,
|
||||
mem_usage: vk_mem::MemoryUsage::AutoPreferDevice,
|
||||
..Default::default()
|
||||
},
|
||||
)?;
|
||||
let draw_calls = buffers::Buffer::new(
|
||||
device.clone(),
|
||||
draw_calls_size,
|
||||
vk::BufferUsageFlags::INDIRECT_BUFFER | vk::BufferUsageFlags::TRANSFER_DST,
|
||||
&[device.queue_families().graphics_familty()],
|
||||
vk_mem::MemoryUsage::AutoPreferDevice,
|
||||
vk_mem::AllocationCreateFlags::empty(),
|
||||
Some("egui-draw-draw_calls".into()),
|
||||
buffers::BufferDesc {
|
||||
name: Some("egui-draw-draw_calls".into()),
|
||||
size: draw_calls_size as u64,
|
||||
usage: vk::BufferUsageFlags::TRANSFER_DST
|
||||
| vk::BufferUsageFlags::INDIRECT_BUFFER,
|
||||
mem_usage: vk_mem::MemoryUsage::AutoPreferDevice,
|
||||
..Default::default()
|
||||
},
|
||||
)?;
|
||||
|
||||
cmd.copy_buffers(
|
||||
|
@ -2404,12 +2423,14 @@ impl<W> Renderer<W> {
|
|||
|
||||
let mut texture_ids = buffers::Buffer::new(
|
||||
device.clone(),
|
||||
textures_indices.len() * size_of::<u32>(),
|
||||
vk::BufferUsageFlags::STORAGE_BUFFER,
|
||||
&[device.queue_families().graphics_familty()],
|
||||
vk_mem::MemoryUsage::AutoPreferDevice,
|
||||
vk_mem::AllocationCreateFlags::HOST_ACCESS_SEQUENTIAL_WRITE,
|
||||
Some("egui-draw-texture_ids".into()),
|
||||
buffers::BufferDesc {
|
||||
name: Some("egui-draw-texture_ids".into()),
|
||||
size: (textures_indices.len() * size_of::<u32>()) as u64,
|
||||
usage: vk::BufferUsageFlags::STORAGE_BUFFER,
|
||||
mem_usage: vk_mem::MemoryUsage::AutoPreferDevice,
|
||||
alloc_flags: vk_mem::AllocationCreateFlags::HOST_ACCESS_SEQUENTIAL_WRITE,
|
||||
..Default::default()
|
||||
},
|
||||
)?;
|
||||
{
|
||||
let mut map = texture_ids.map_arc()?;
|
||||
|
@ -3291,7 +3312,6 @@ mod test_swapchain {
|
|||
let surface = Arc::new(Surface::headless(vk.instance.clone())?);
|
||||
|
||||
let swapchain = Arc::new(Swapchain::new(
|
||||
vk.instance.clone(),
|
||||
vk.device.clone(),
|
||||
surface.clone(),
|
||||
vk.device.phy(),
|
||||
|
|
|
@ -4,9 +4,9 @@ use ash::vk;
|
|||
|
||||
#[macro_export]
|
||||
macro_rules! def_monotonic_id {
|
||||
($ty:ident) => {
|
||||
($vis:vis $ty:ident) => {
|
||||
#[derive(Copy, Clone, Hash, Eq, PartialEq, PartialOrd, Ord, Debug)]
|
||||
pub struct $ty(::core::num::NonZero<u32>);
|
||||
$vis struct $ty(::core::num::NonZero<u32>);
|
||||
|
||||
impl $ty {
|
||||
pub fn new() -> Self {
|
||||
|
@ -331,3 +331,31 @@ pub fn timed<T, F: FnOnce() -> T>(label: &str, f: F) -> T {
|
|||
|
||||
out
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub struct Rgba(pub [f32; 4]);
|
||||
|
||||
impl std::hash::Hash for Rgba {
|
||||
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
|
||||
self.0.map(|f| hash_f32(state, f));
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
impl Rgba {
|
||||
pub fn new(r: f32, g: f32, b: f32, a: f32) -> Self {
|
||||
Self([r, g, b, a])
|
||||
}
|
||||
pub fn into_u32(&self) -> [u32; 4] {
|
||||
self.0.map(|f| (f.clamp(0.0, 1.0) * 255.0) as u32)
|
||||
}
|
||||
pub fn into_f32(&self) -> [f32; 4] {
|
||||
self.0
|
||||
}
|
||||
pub fn into_snorm(&self) -> [f32; 4] {
|
||||
self.0.map(|f| (f - 0.5) * 2.0)
|
||||
}
|
||||
pub fn into_i32(&self) -> [i32; 4] {
|
||||
self.0.map(|f| (f.clamp(0.0, 1.0) * 255.0) as i32 - 128)
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue