fmt: cargo fmt
This commit is contained in:
parent
962a81c2e3
commit
2450217c29
|
@ -1,8 +1,8 @@
|
||||||
//! Cache helpers for `ShaderCompilation` objects to cache compiled SPIRV.
|
//! Cache helpers for `ShaderCompilation` objects to cache compiled SPIRV.
|
||||||
use librashader_preprocess::ShaderSource;
|
use librashader_preprocess::ShaderSource;
|
||||||
use librashader_reflect::back::targets::{GLSL, HLSL, SPIRV};
|
|
||||||
#[cfg(all(target_os = "windows", feature = "d3d"))]
|
#[cfg(all(target_os = "windows", feature = "d3d"))]
|
||||||
use librashader_reflect::back::targets::DXIL;
|
use librashader_reflect::back::targets::DXIL;
|
||||||
|
use librashader_reflect::back::targets::{GLSL, HLSL, SPIRV};
|
||||||
|
|
||||||
use librashader_reflect::back::{CompilerBackend, FromCompilation};
|
use librashader_reflect::back::{CompilerBackend, FromCompilation};
|
||||||
use librashader_reflect::error::{ShaderCompileError, ShaderReflectError};
|
use librashader_reflect::error::{ShaderCompileError, ShaderReflectError};
|
||||||
|
|
|
@ -71,7 +71,7 @@ impl From<wgpu_types::TextureFormat> for ImageFormat {
|
||||||
wgpu_types::TextureFormat::Rgba32Uint => ImageFormat::R32G32B32A32Uint,
|
wgpu_types::TextureFormat::Rgba32Uint => ImageFormat::R32G32B32A32Uint,
|
||||||
wgpu_types::TextureFormat::Rgba32Sint => ImageFormat::R32G32B32A32Sint,
|
wgpu_types::TextureFormat::Rgba32Sint => ImageFormat::R32G32B32A32Sint,
|
||||||
wgpu_types::TextureFormat::Rgba32Float => ImageFormat::R32G32B32A32Sfloat,
|
wgpu_types::TextureFormat::Rgba32Float => ImageFormat::R32G32B32A32Sfloat,
|
||||||
_ => ImageFormat::Unknown
|
_ => ImageFormat::Unknown,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -155,8 +155,6 @@ impl From<FilterMode> for wgpu_types::FilterMode {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
impl From<WrapMode> for wgpu_types::AddressMode {
|
impl From<WrapMode> for wgpu_types::AddressMode {
|
||||||
fn from(value: WrapMode) -> Self {
|
fn from(value: WrapMode) -> Self {
|
||||||
match value {
|
match value {
|
||||||
|
@ -176,4 +174,4 @@ impl From<Size<u32>> for wgpu_types::Extent3d {
|
||||||
depth_or_array_layers: 1,
|
depth_or_array_layers: 1,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,7 +5,6 @@ use core::slice;
|
||||||
|
|
||||||
/// Polyfill trait for [`Vec::extract_if`](https://github.com/rust-lang/rust/issues/43244).
|
/// Polyfill trait for [`Vec::extract_if`](https://github.com/rust-lang/rust/issues/43244).
|
||||||
pub(crate) trait MakeExtractIf<T> {
|
pub(crate) trait MakeExtractIf<T> {
|
||||||
|
|
||||||
/// Creates an iterator which uses a closure to determine if an element should be removed.
|
/// Creates an iterator which uses a closure to determine if an element should be removed.
|
||||||
///
|
///
|
||||||
/// If the closure returns true, then the element is removed and yielded.
|
/// If the closure returns true, then the element is removed and yielded.
|
||||||
|
@ -33,14 +32,14 @@ pub(crate) trait MakeExtractIf<T> {
|
||||||
/// assert_eq!(odds, vec![1, 3, 5, 9, 11, 13, 15]);
|
/// assert_eq!(odds, vec![1, 3, 5, 9, 11, 13, 15]);
|
||||||
/// ```
|
/// ```
|
||||||
fn extract_if<F>(&mut self, filter: F) -> ExtractIf<T, F>
|
fn extract_if<F>(&mut self, filter: F) -> ExtractIf<T, F>
|
||||||
where
|
where
|
||||||
F: FnMut(&mut T) -> bool;
|
F: FnMut(&mut T) -> bool;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> MakeExtractIf<T> for Vec<T> {
|
impl<T> MakeExtractIf<T> for Vec<T> {
|
||||||
fn extract_if<F>(&mut self, filter: F) -> ExtractIf<T, F>
|
fn extract_if<F>(&mut self, filter: F) -> ExtractIf<T, F>
|
||||||
where
|
where
|
||||||
F: FnMut(&mut T) -> bool,
|
F: FnMut(&mut T) -> bool,
|
||||||
{
|
{
|
||||||
let old_len = self.len();
|
let old_len = self.len();
|
||||||
|
|
||||||
|
@ -74,8 +73,8 @@ impl<T> MakeExtractIf<T> for Vec<T> {
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
#[must_use = "iterators are lazy and do nothing unless consumed"]
|
#[must_use = "iterators are lazy and do nothing unless consumed"]
|
||||||
pub struct ExtractIf<'a, T, F>
|
pub struct ExtractIf<'a, T, F>
|
||||||
where
|
where
|
||||||
F: FnMut(&mut T) -> bool,
|
F: FnMut(&mut T) -> bool,
|
||||||
{
|
{
|
||||||
vec: &'a mut Vec<T>,
|
vec: &'a mut Vec<T>,
|
||||||
/// The index of the item that will be inspected by the next call to `next`.
|
/// The index of the item that will be inspected by the next call to `next`.
|
||||||
|
@ -89,8 +88,8 @@ pub struct ExtractIf<'a, T, F>
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T, F> Iterator for ExtractIf<'_, T, F>
|
impl<T, F> Iterator for ExtractIf<'_, T, F>
|
||||||
where
|
where
|
||||||
F: FnMut(&mut T) -> bool,
|
F: FnMut(&mut T) -> bool,
|
||||||
{
|
{
|
||||||
type Item = T;
|
type Item = T;
|
||||||
|
|
||||||
|
@ -124,8 +123,8 @@ impl<T, F> Iterator for ExtractIf<'_, T, F>
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T, F> Drop for ExtractIf<'_, T, F>
|
impl<T, F> Drop for ExtractIf<'_, T, F>
|
||||||
where
|
where
|
||||||
F: FnMut(&mut T) -> bool,
|
F: FnMut(&mut T) -> bool,
|
||||||
{
|
{
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
unsafe {
|
unsafe {
|
||||||
|
@ -235,35 +234,30 @@ mod test {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn drain_filter_complex() {
|
fn drain_filter_complex() {
|
||||||
|
{
|
||||||
{ // [+xxx++++++xxxxx++++x+x++]
|
// [+xxx++++++xxxxx++++x+x++]
|
||||||
let mut vec = vec![1,
|
let mut vec = vec![
|
||||||
2, 4, 6,
|
1, 2, 4, 6, 7, 9, 11, 13, 15, 17, 18, 20, 22, 24, 26, 27, 29, 31, 33, 34, 35, 36,
|
||||||
7, 9, 11, 13, 15, 17,
|
37, 39,
|
||||||
18, 20, 22, 24, 26,
|
];
|
||||||
27, 29, 31, 33,
|
|
||||||
34,
|
|
||||||
35,
|
|
||||||
36,
|
|
||||||
37, 39];
|
|
||||||
|
|
||||||
let removed = vec.extract_if(|x| *x % 2 == 0).collect::<Vec<_>>();
|
let removed = vec.extract_if(|x| *x % 2 == 0).collect::<Vec<_>>();
|
||||||
assert_eq!(removed.len(), 10);
|
assert_eq!(removed.len(), 10);
|
||||||
assert_eq!(removed, vec![2, 4, 6, 18, 20, 22, 24, 26, 34, 36]);
|
assert_eq!(removed, vec![2, 4, 6, 18, 20, 22, 24, 26, 34, 36]);
|
||||||
|
|
||||||
assert_eq!(vec.len(), 14);
|
assert_eq!(vec.len(), 14);
|
||||||
assert_eq!(vec, vec![1, 7, 9, 11, 13, 15, 17, 27, 29, 31, 33, 35, 37, 39]);
|
assert_eq!(
|
||||||
|
vec,
|
||||||
|
vec![1, 7, 9, 11, 13, 15, 17, 27, 29, 31, 33, 35, 37, 39]
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
{ // [xxx++++++xxxxx++++x+x++]
|
{
|
||||||
let mut vec = vec![2, 4, 6,
|
// [xxx++++++xxxxx++++x+x++]
|
||||||
7, 9, 11, 13, 15, 17,
|
let mut vec = vec![
|
||||||
18, 20, 22, 24, 26,
|
2, 4, 6, 7, 9, 11, 13, 15, 17, 18, 20, 22, 24, 26, 27, 29, 31, 33, 34, 35, 36, 37,
|
||||||
27, 29, 31, 33,
|
39,
|
||||||
34,
|
];
|
||||||
35,
|
|
||||||
36,
|
|
||||||
37, 39];
|
|
||||||
|
|
||||||
let removed = vec.extract_if(|x| *x % 2 == 0).collect::<Vec<_>>();
|
let removed = vec.extract_if(|x| *x % 2 == 0).collect::<Vec<_>>();
|
||||||
assert_eq!(removed.len(), 10);
|
assert_eq!(removed.len(), 10);
|
||||||
|
@ -273,14 +267,11 @@ mod test {
|
||||||
assert_eq!(vec, vec![7, 9, 11, 13, 15, 17, 27, 29, 31, 33, 35, 37, 39]);
|
assert_eq!(vec, vec![7, 9, 11, 13, 15, 17, 27, 29, 31, 33, 35, 37, 39]);
|
||||||
}
|
}
|
||||||
|
|
||||||
{ // [xxx++++++xxxxx++++x+x]
|
{
|
||||||
let mut vec = vec![2, 4, 6,
|
// [xxx++++++xxxxx++++x+x]
|
||||||
7, 9, 11, 13, 15, 17,
|
let mut vec = vec![
|
||||||
18, 20, 22, 24, 26,
|
2, 4, 6, 7, 9, 11, 13, 15, 17, 18, 20, 22, 24, 26, 27, 29, 31, 33, 34, 35, 36,
|
||||||
27, 29, 31, 33,
|
];
|
||||||
34,
|
|
||||||
35,
|
|
||||||
36];
|
|
||||||
|
|
||||||
let removed = vec.extract_if(|x| *x % 2 == 0).collect::<Vec<_>>();
|
let removed = vec.extract_if(|x| *x % 2 == 0).collect::<Vec<_>>();
|
||||||
assert_eq!(removed.len(), 10);
|
assert_eq!(removed.len(), 10);
|
||||||
|
@ -290,9 +281,11 @@ mod test {
|
||||||
assert_eq!(vec, vec![7, 9, 11, 13, 15, 17, 27, 29, 31, 33, 35]);
|
assert_eq!(vec, vec![7, 9, 11, 13, 15, 17, 27, 29, 31, 33, 35]);
|
||||||
}
|
}
|
||||||
|
|
||||||
{ // [xxxxxxxxxx+++++++++++]
|
{
|
||||||
let mut vec = vec![2, 4, 6, 8, 10, 12, 14, 16, 18, 20,
|
// [xxxxxxxxxx+++++++++++]
|
||||||
1, 3, 5, 7, 9, 11, 13, 15, 17, 19];
|
let mut vec = vec![
|
||||||
|
2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 1, 3, 5, 7, 9, 11, 13, 15, 17, 19,
|
||||||
|
];
|
||||||
|
|
||||||
let removed = vec.extract_if(|x| *x % 2 == 0).collect::<Vec<_>>();
|
let removed = vec.extract_if(|x| *x % 2 == 0).collect::<Vec<_>>();
|
||||||
assert_eq!(removed.len(), 10);
|
assert_eq!(removed.len(), 10);
|
||||||
|
@ -302,9 +295,11 @@ mod test {
|
||||||
assert_eq!(vec, vec![1, 3, 5, 7, 9, 11, 13, 15, 17, 19]);
|
assert_eq!(vec, vec![1, 3, 5, 7, 9, 11, 13, 15, 17, 19]);
|
||||||
}
|
}
|
||||||
|
|
||||||
{ // [+++++++++++xxxxxxxxxx]
|
{
|
||||||
let mut vec = vec![1, 3, 5, 7, 9, 11, 13, 15, 17, 19,
|
// [+++++++++++xxxxxxxxxx]
|
||||||
2, 4, 6, 8, 10, 12, 14, 16, 18, 20];
|
let mut vec = vec![
|
||||||
|
1, 3, 5, 7, 9, 11, 13, 15, 17, 19, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20,
|
||||||
|
];
|
||||||
|
|
||||||
let removed = vec.extract_if(|x| *x % 2 == 0).collect::<Vec<_>>();
|
let removed = vec.extract_if(|x| *x % 2 == 0).collect::<Vec<_>>();
|
||||||
assert_eq!(removed.len(), 10);
|
assert_eq!(removed.len(), 10);
|
||||||
|
@ -314,4 +309,4 @@ mod test {
|
||||||
assert_eq!(vec, vec![1, 3, 5, 7, 9, 11, 13, 15, 17, 19]);
|
assert_eq!(vec, vec![1, 3, 5, 7, 9, 11, 13, 15, 17, 19]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,9 +11,9 @@
|
||||||
#![allow(unstable_name_collisions)]
|
#![allow(unstable_name_collisions)]
|
||||||
|
|
||||||
mod error;
|
mod error;
|
||||||
|
mod extract_if;
|
||||||
mod parse;
|
mod parse;
|
||||||
mod preset;
|
mod preset;
|
||||||
mod extract_if;
|
|
||||||
|
|
||||||
pub use error::*;
|
pub use error::*;
|
||||||
pub use preset::*;
|
pub use preset::*;
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
|
use crate::extract_if::MakeExtractIf;
|
||||||
use crate::parse::remove_if;
|
use crate::parse::remove_if;
|
||||||
use crate::parse::value::Value;
|
use crate::parse::value::Value;
|
||||||
use crate::{ParameterConfig, Scale2D, Scaling, ShaderPassConfig, ShaderPreset, TextureConfig};
|
use crate::{ParameterConfig, Scale2D, Scaling, ShaderPassConfig, ShaderPreset, TextureConfig};
|
||||||
use crate::extract_if::MakeExtractIf;
|
|
||||||
|
|
||||||
pub fn resolve_values(mut values: Vec<Value>) -> ShaderPreset {
|
pub fn resolve_values(mut values: Vec<Value>) -> ShaderPreset {
|
||||||
let textures: Vec<TextureConfig> = values
|
let textures: Vec<TextureConfig> = values
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
use crate::error::{SemanticsErrorKind, ShaderCompileError, ShaderReflectError};
|
use crate::error::{SemanticsErrorKind, ShaderCompileError, ShaderReflectError};
|
||||||
use crate::front::GlslangCompilation;
|
use crate::front::GlslangCompilation;
|
||||||
use crate::reflect::semantics::{
|
use crate::reflect::semantics::{
|
||||||
BindingMeta, BindingStage, MemberOffset, ShaderReflection, ShaderSemantics,
|
BindingMeta, BindingStage, BufferReflection, MemberOffset, ShaderReflection, ShaderSemantics,
|
||||||
TextureBinding, TextureSemanticMap, TextureSemantics, TextureSizeMeta, TypeInfo, BufferReflection,
|
TextureBinding, TextureSemanticMap, TextureSemantics, TextureSizeMeta, TypeInfo,
|
||||||
UniformMemberBlock, UniqueSemanticMap, UniqueSemantics, ValidateTypeSemantics, VariableMeta,
|
UniformMemberBlock, UniqueSemanticMap, UniqueSemantics, ValidateTypeSemantics, VariableMeta,
|
||||||
MAX_BINDINGS_COUNT, MAX_PUSH_BUFFER_SIZE,
|
MAX_BINDINGS_COUNT, MAX_PUSH_BUFFER_SIZE,
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,13 +1,16 @@
|
||||||
use crate::error::{SemanticsErrorKind, ShaderReflectError};
|
use crate::error::{SemanticsErrorKind, ShaderReflectError};
|
||||||
|
|
||||||
use naga::{AddressSpace, Binding, GlobalVariable, Handle, ImageClass, Module, ResourceBinding, Scalar, ScalarKind, TypeInner, VectorSize};
|
use naga::{
|
||||||
|
AddressSpace, Binding, GlobalVariable, Handle, ImageClass, Module, ResourceBinding, Scalar,
|
||||||
|
ScalarKind, TypeInner, VectorSize,
|
||||||
|
};
|
||||||
|
|
||||||
use crate::reflect::helper::{SemanticErrorBlame, TextureData, UboData};
|
use crate::reflect::helper::{SemanticErrorBlame, TextureData, UboData};
|
||||||
use crate::reflect::semantics::{
|
use crate::reflect::semantics::{
|
||||||
BindingMeta, BindingStage, MemberOffset, ShaderSemantics, TextureBinding,
|
BindingMeta, BindingStage, BufferReflection, MemberOffset, ShaderSemantics, TextureBinding,
|
||||||
TextureSemanticMap, TextureSemantics, TextureSizeMeta, TypeInfo, BufferReflection,
|
TextureSemanticMap, TextureSemantics, TextureSizeMeta, TypeInfo, UniformMemberBlock,
|
||||||
UniformMemberBlock, UniqueSemanticMap, UniqueSemantics, ValidateTypeSemantics, VariableMeta,
|
UniqueSemanticMap, UniqueSemantics, ValidateTypeSemantics, VariableMeta, MAX_BINDINGS_COUNT,
|
||||||
MAX_BINDINGS_COUNT, MAX_PUSH_BUFFER_SIZE,
|
MAX_PUSH_BUFFER_SIZE,
|
||||||
};
|
};
|
||||||
use crate::reflect::{align_uniform_size, ReflectShader, ShaderReflection};
|
use crate::reflect::{align_uniform_size, ReflectShader, ShaderReflection};
|
||||||
|
|
||||||
|
@ -82,7 +85,11 @@ impl ValidateTypeSemantics<&TypeInner> for UniqueSemantics {
|
||||||
|
|
||||||
impl ValidateTypeSemantics<&TypeInner> for TextureSemantics {
|
impl ValidateTypeSemantics<&TypeInner> for TextureSemantics {
|
||||||
fn validate_type(&self, ty: &&TypeInner) -> Option<TypeInfo> {
|
fn validate_type(&self, ty: &&TypeInner) -> Option<TypeInfo> {
|
||||||
let TypeInner::Vector { scalar: Scalar { width, kind }, size } = ty else {
|
let TypeInner::Vector {
|
||||||
|
scalar: Scalar { width, kind },
|
||||||
|
size,
|
||||||
|
} = ty
|
||||||
|
else {
|
||||||
return None;
|
return None;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -185,10 +192,9 @@ impl NagaReflect {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_next_binding(&self, bind_group: u32) -> u32{
|
fn get_next_binding(&self, bind_group: u32) -> u32 {
|
||||||
let mut max_bind = 0;
|
let mut max_bind = 0;
|
||||||
for (_, gv) in self.vertex
|
for (_, gv) in self.vertex.global_variables.iter() {
|
||||||
.global_variables.iter() {
|
|
||||||
let Some(binding) = &gv.binding else {
|
let Some(binding) = &gv.binding else {
|
||||||
continue;
|
continue;
|
||||||
};
|
};
|
||||||
|
@ -198,8 +204,7 @@ impl NagaReflect {
|
||||||
max_bind = std::cmp::max(max_bind, binding.binding);
|
max_bind = std::cmp::max(max_bind, binding.binding);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (_, gv) in self.fragment
|
for (_, gv) in self.fragment.global_variables.iter() {
|
||||||
.global_variables.iter() {
|
|
||||||
let Some(binding) = &gv.binding else {
|
let Some(binding) = &gv.binding else {
|
||||||
continue;
|
continue;
|
||||||
};
|
};
|
||||||
|
@ -234,18 +239,12 @@ impl NagaReflect {
|
||||||
// Reassign to UBO later if we want during compilation.
|
// Reassign to UBO later if we want during compilation.
|
||||||
if let Some(vertex_pcb) = vertex_pcb {
|
if let Some(vertex_pcb) = vertex_pcb {
|
||||||
let ubo = &mut self.vertex.global_variables[vertex_pcb];
|
let ubo = &mut self.vertex.global_variables[vertex_pcb];
|
||||||
ubo.binding = Some(ResourceBinding {
|
ubo.binding = Some(ResourceBinding { group: 0, binding });
|
||||||
group: 0,
|
|
||||||
binding,
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(fragment_pcb) = fragment_pcb {
|
if let Some(fragment_pcb) = fragment_pcb {
|
||||||
let ubo = &mut self.fragment.global_variables[fragment_pcb];
|
let ubo = &mut self.fragment.global_variables[fragment_pcb];
|
||||||
ubo.binding = Some(ResourceBinding {
|
ubo.binding = Some(ResourceBinding { group: 0, binding });
|
||||||
group: 0,
|
|
||||||
binding,
|
|
||||||
});
|
|
||||||
};
|
};
|
||||||
|
|
||||||
match (vertex_pcb, fragment_pcb) {
|
match (vertex_pcb, fragment_pcb) {
|
||||||
|
|
|
@ -13,7 +13,7 @@ use librashader_common::{ImageFormat, Size};
|
||||||
use librashader_presets::{Scale2D, TextureConfig};
|
use librashader_presets::{Scale2D, TextureConfig};
|
||||||
use librashader_reflect::back::cross::CrossGlslContext;
|
use librashader_reflect::back::cross::CrossGlslContext;
|
||||||
use librashader_reflect::back::ShaderCompilerOutput;
|
use librashader_reflect::back::ShaderCompilerOutput;
|
||||||
use librashader_reflect::reflect::semantics::{TextureBinding, BufferReflection};
|
use librashader_reflect::reflect::semantics::{BufferReflection, TextureBinding};
|
||||||
use librashader_runtime::uniforms::UniformStorageAccess;
|
use librashader_runtime::uniforms::UniformStorageAccess;
|
||||||
use rustc_hash::FxHashMap;
|
use rustc_hash::FxHashMap;
|
||||||
|
|
||||||
|
|
|
@ -124,9 +124,7 @@ impl FilterPass {
|
||||||
|
|
||||||
output.output.begin_pass(cmd);
|
output.output.begin_pass(cmd);
|
||||||
|
|
||||||
let residual = self
|
let residual = self.graphics_pipeline.begin_rendering(output, cmd)?;
|
||||||
.graphics_pipeline
|
|
||||||
.begin_rendering(output, cmd)?;
|
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
parent.device.cmd_bind_pipeline(
|
parent.device.cmd_bind_pipeline(
|
||||||
|
|
|
@ -7,7 +7,7 @@ use crate::render_pass::VulkanRenderPass;
|
||||||
use ash::vk::PushConstantRange;
|
use ash::vk::PushConstantRange;
|
||||||
use librashader_cache::cache_pipeline;
|
use librashader_cache::cache_pipeline;
|
||||||
use librashader_reflect::back::ShaderCompilerOutput;
|
use librashader_reflect::back::ShaderCompilerOutput;
|
||||||
use librashader_reflect::reflect::semantics::{TextureBinding, BufferReflection};
|
use librashader_reflect::reflect::semantics::{BufferReflection, TextureBinding};
|
||||||
use librashader_reflect::reflect::ShaderReflection;
|
use librashader_reflect::reflect::ShaderReflection;
|
||||||
use librashader_runtime::render_target::RenderTarget;
|
use librashader_runtime::render_target::RenderTarget;
|
||||||
use std::ffi::CStr;
|
use std::ffi::CStr;
|
||||||
|
@ -31,7 +31,9 @@ impl PipelineDescriptors {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn add_ubo_binding(&mut self, ubo_meta: Option<&BufferReflection<u32>>) {
|
pub fn add_ubo_binding(&mut self, ubo_meta: Option<&BufferReflection<u32>>) {
|
||||||
if let Some(ubo_meta) = ubo_meta && !ubo_meta.stage_mask.is_empty() {
|
if let Some(ubo_meta) = ubo_meta
|
||||||
|
&& !ubo_meta.stage_mask.is_empty()
|
||||||
|
{
|
||||||
let ubo_mask = util::binding_stage_to_vulkan_stage(ubo_meta.stage_mask);
|
let ubo_mask = util::binding_stage_to_vulkan_stage(ubo_meta.stage_mask);
|
||||||
|
|
||||||
self.layout_bindings.push(vk::DescriptorSetLayoutBinding {
|
self.layout_bindings.push(vk::DescriptorSetLayoutBinding {
|
||||||
|
@ -417,7 +419,11 @@ impl VulkanGraphicsPipeline {
|
||||||
extent: output.output.size.into(),
|
extent: output.output.size.into(),
|
||||||
});
|
});
|
||||||
unsafe {
|
unsafe {
|
||||||
self.device.cmd_begin_render_pass(cmd, &render_pass_info, vk::SubpassContents::INLINE);
|
self.device.cmd_begin_render_pass(
|
||||||
|
cmd,
|
||||||
|
&render_pass_info,
|
||||||
|
vk::SubpassContents::INLINE,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
Ok(Some(framebuffer))
|
Ok(Some(framebuffer))
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -23,7 +23,7 @@ fn triangle_vk() {
|
||||||
disable_cache: false,
|
disable_cache: false,
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
hello_triangle::main(base, filter)
|
hello_triangle::main(base, filter)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
|
use parking_lot::RwLock;
|
||||||
use std::ops::{Deref, DerefMut};
|
use std::ops::{Deref, DerefMut};
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use parking_lot::RwLock;
|
|
||||||
|
|
||||||
pub struct WgpuStagedBuffer {
|
pub struct WgpuStagedBuffer {
|
||||||
buffer: wgpu::Buffer,
|
buffer: wgpu::Buffer,
|
||||||
|
|
|
@ -16,15 +16,13 @@ use std::sync::Arc;
|
||||||
|
|
||||||
use crate::buffer::WgpuStagedBuffer;
|
use crate::buffer::WgpuStagedBuffer;
|
||||||
use crate::draw_quad::DrawQuad;
|
use crate::draw_quad::DrawQuad;
|
||||||
use librashader_common::{ImageFormat, Size, Viewport};
|
use librashader_common::{FilterMode, ImageFormat, Size, Viewport, WrapMode};
|
||||||
use librashader_reflect::back::wgsl::WgslCompileOptions;
|
use librashader_reflect::back::wgsl::WgslCompileOptions;
|
||||||
use librashader_runtime::framebuffer::FramebufferInit;
|
use librashader_runtime::framebuffer::FramebufferInit;
|
||||||
use librashader_runtime::render_target::RenderTarget;
|
use librashader_runtime::render_target::RenderTarget;
|
||||||
use librashader_runtime::scaling::ScaleFramebuffer;
|
use librashader_runtime::scaling::ScaleFramebuffer;
|
||||||
use rayon::prelude::*;
|
use rayon::prelude::*;
|
||||||
use wgpu::{
|
use wgpu::{Device, TextureFormat};
|
||||||
Device, TextureFormat,
|
|
||||||
};
|
|
||||||
|
|
||||||
use crate::error;
|
use crate::error;
|
||||||
use crate::error::FilterChainError;
|
use crate::error::FilterChainError;
|
||||||
|
@ -32,6 +30,7 @@ use crate::filter_pass::FilterPass;
|
||||||
use crate::framebuffer::OutputView;
|
use crate::framebuffer::OutputView;
|
||||||
use crate::graphics_pipeline::WgpuGraphicsPipeline;
|
use crate::graphics_pipeline::WgpuGraphicsPipeline;
|
||||||
use crate::luts::LutTexture;
|
use crate::luts::LutTexture;
|
||||||
|
use crate::mipmap::MipmapGen;
|
||||||
use crate::options::FrameOptionsWGPU;
|
use crate::options::FrameOptionsWGPU;
|
||||||
use crate::samplers::SamplerSet;
|
use crate::samplers::SamplerSet;
|
||||||
use crate::texture::{Handle, InputImage, OwnedImage};
|
use crate::texture::{Handle, InputImage, OwnedImage};
|
||||||
|
@ -56,6 +55,7 @@ pub struct FilterChainWGPU {
|
||||||
history_framebuffers: VecDeque<OwnedImage>,
|
history_framebuffers: VecDeque<OwnedImage>,
|
||||||
disable_mipmaps: bool,
|
disable_mipmaps: bool,
|
||||||
// residuals: Box<[FrameResiduals]>,
|
// residuals: Box<[FrameResiduals]>,
|
||||||
|
mipmapper: MipmapGen,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct FilterMutable {
|
pub struct FilterMutable {
|
||||||
|
@ -73,7 +73,7 @@ pub(crate) struct FilterCommon {
|
||||||
pub internal_frame_count: i32,
|
pub internal_frame_count: i32,
|
||||||
pub(crate) draw_quad: DrawQuad,
|
pub(crate) draw_quad: DrawQuad,
|
||||||
device: Arc<Device>,
|
device: Arc<Device>,
|
||||||
pub(crate) queue: Arc<wgpu::Queue>
|
pub(crate) queue: Arc<wgpu::Queue>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FilterChainWGPU {
|
impl FilterChainWGPU {
|
||||||
|
@ -86,7 +86,7 @@ impl FilterChainWGPU {
|
||||||
/// graphics queue. The command buffer must be completely executed before calling [`frame`](Self::frame).
|
/// graphics queue. The command buffer must be completely executed before calling [`frame`](Self::frame).
|
||||||
pub fn load_from_preset_deferred(
|
pub fn load_from_preset_deferred(
|
||||||
device: Arc<Device>,
|
device: Arc<Device>,
|
||||||
queue: Arc<wgpu::Queue>,
|
queue: Arc<wgpu::Queue>,
|
||||||
cmd: &mut wgpu::CommandEncoder,
|
cmd: &mut wgpu::CommandEncoder,
|
||||||
preset: ShaderPreset,
|
preset: ShaderPreset,
|
||||||
) -> error::Result<FilterChainWGPU> {
|
) -> error::Result<FilterChainWGPU> {
|
||||||
|
@ -94,9 +94,17 @@ impl FilterChainWGPU {
|
||||||
|
|
||||||
// // initialize passes
|
// // initialize passes
|
||||||
let filters = Self::init_passes(Arc::clone(&device), passes, &semantics)?;
|
let filters = Self::init_passes(Arc::clone(&device), passes, &semantics)?;
|
||||||
//
|
|
||||||
let luts = FilterChainWGPU::load_luts(&device, &queue, cmd, &preset.textures)?;
|
|
||||||
let samplers = SamplerSet::new(&device);
|
let samplers = SamplerSet::new(&device);
|
||||||
|
let mut mipmapper = MipmapGen::new(Arc::clone(&device));
|
||||||
|
let luts = FilterChainWGPU::load_luts(
|
||||||
|
&device,
|
||||||
|
&queue,
|
||||||
|
cmd,
|
||||||
|
&mut mipmapper,
|
||||||
|
&samplers,
|
||||||
|
&preset.textures,
|
||||||
|
)?;
|
||||||
//
|
//
|
||||||
let framebuffer_gen = || {
|
let framebuffer_gen = || {
|
||||||
Ok::<_, error::FilterChainError>(OwnedImage::new(
|
Ok::<_, error::FilterChainError>(OwnedImage::new(
|
||||||
|
@ -123,11 +131,6 @@ impl FilterChainWGPU {
|
||||||
//
|
//
|
||||||
// initialize history
|
// initialize history
|
||||||
let (history_framebuffers, history_textures) = framebuffer_init.init_history()?;
|
let (history_framebuffers, history_textures) = framebuffer_init.init_history()?;
|
||||||
//
|
|
||||||
// let mut intermediates = Vec::new();
|
|
||||||
// intermediates.resize_with(frames_in_flight as usize, || {
|
|
||||||
// FrameResiduals::new(&device.device)
|
|
||||||
// });
|
|
||||||
|
|
||||||
let draw_quad = DrawQuad::new(&device);
|
let draw_quad = DrawQuad::new(&device);
|
||||||
|
|
||||||
|
@ -156,6 +159,7 @@ impl FilterChainWGPU {
|
||||||
feedback_framebuffers,
|
feedback_framebuffers,
|
||||||
history_framebuffers,
|
history_framebuffers,
|
||||||
disable_mipmaps: false, // todo: force no mipmaps,
|
disable_mipmaps: false, // todo: force no mipmaps,
|
||||||
|
mipmapper,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -163,6 +167,8 @@ impl FilterChainWGPU {
|
||||||
device: &wgpu::Device,
|
device: &wgpu::Device,
|
||||||
queue: &wgpu::Queue,
|
queue: &wgpu::Queue,
|
||||||
cmd: &mut wgpu::CommandEncoder,
|
cmd: &mut wgpu::CommandEncoder,
|
||||||
|
mipmapper: &mut MipmapGen,
|
||||||
|
sampler_set: &SamplerSet,
|
||||||
textures: &[TextureConfig],
|
textures: &[TextureConfig],
|
||||||
) -> error::Result<FxHashMap<usize, LutTexture>> {
|
) -> error::Result<FxHashMap<usize, LutTexture>> {
|
||||||
let mut luts = FxHashMap::default();
|
let mut luts = FxHashMap::default();
|
||||||
|
@ -171,7 +177,8 @@ impl FilterChainWGPU {
|
||||||
.map(|texture| Image::load(&texture.path, UVDirection::TopLeft))
|
.map(|texture| Image::load(&texture.path, UVDirection::TopLeft))
|
||||||
.collect::<Result<Vec<Image>, ImageError>>()?;
|
.collect::<Result<Vec<Image>, ImageError>>()?;
|
||||||
for (index, (texture, image)) in textures.iter().zip(images).enumerate() {
|
for (index, (texture, image)) in textures.iter().zip(images).enumerate() {
|
||||||
let texture = LutTexture::new(device, queue, cmd, image, texture);
|
let texture =
|
||||||
|
LutTexture::new(device, queue, cmd, image, texture, mipmapper, sampler_set);
|
||||||
luts.insert(index, texture);
|
luts.insert(index, texture);
|
||||||
}
|
}
|
||||||
Ok(luts)
|
Ok(luts)
|
||||||
|
@ -375,7 +382,13 @@ impl FilterChainWGPU {
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
if target.max_miplevels > 1 && !self.disable_mipmaps {
|
if target.max_miplevels > 1 && !self.disable_mipmaps {
|
||||||
target.generate_mipmaps(cmd);
|
let sampler = self.common.samplers.get(
|
||||||
|
WrapMode::ClampToEdge,
|
||||||
|
FilterMode::Linear,
|
||||||
|
FilterMode::Nearest,
|
||||||
|
);
|
||||||
|
|
||||||
|
target.generate_mipmaps(cmd, &mut self.mipmapper, &sampler);
|
||||||
}
|
}
|
||||||
|
|
||||||
source = self.common.output_textures[index].clone().unwrap();
|
source = self.common.output_textures[index].clone().unwrap();
|
||||||
|
|
|
@ -16,5 +16,3 @@ impl<'a> OutputView<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -6,13 +6,13 @@ use winit::{
|
||||||
window::{Window, WindowBuilder},
|
window::{Window, WindowBuilder},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
use librashader_common::Viewport;
|
||||||
use librashader_presets::ShaderPreset;
|
use librashader_presets::ShaderPreset;
|
||||||
use librashader_runtime_wgpu::FilterChainWGPU;
|
use librashader_runtime_wgpu::FilterChainWGPU;
|
||||||
use wgpu::util::DeviceExt;
|
use wgpu::util::DeviceExt;
|
||||||
use winit::event_loop::EventLoopBuilder;
|
use winit::event_loop::EventLoopBuilder;
|
||||||
use winit::keyboard::{Key, KeyCode, PhysicalKey};
|
use winit::keyboard::{Key, KeyCode, PhysicalKey};
|
||||||
use winit::platform::windows::EventLoopBuilderExtWindows;
|
use winit::platform::windows::EventLoopBuilderExtWindows;
|
||||||
use librashader_common::Viewport;
|
|
||||||
|
|
||||||
#[cfg(target_arch = "wasm32")]
|
#[cfg(target_arch = "wasm32")]
|
||||||
use wasm_bindgen::prelude::*;
|
use wasm_bindgen::prelude::*;
|
||||||
|
@ -75,7 +75,7 @@ struct State<'a> {
|
||||||
vertex_buffer: wgpu::Buffer,
|
vertex_buffer: wgpu::Buffer,
|
||||||
num_vertices: u32,
|
num_vertices: u32,
|
||||||
chain: FilterChainWGPU,
|
chain: FilterChainWGPU,
|
||||||
frame_count: usize
|
frame_count: usize,
|
||||||
}
|
}
|
||||||
impl<'a> State<'a> {
|
impl<'a> State<'a> {
|
||||||
async fn new(window: &'a Window) -> Self {
|
async fn new(window: &'a Window) -> Self {
|
||||||
|
@ -228,44 +228,37 @@ impl<'a> State<'a> {
|
||||||
fn render(&mut self) -> Result<(), wgpu::SurfaceError> {
|
fn render(&mut self) -> Result<(), wgpu::SurfaceError> {
|
||||||
let output = self.surface.get_current_texture()?;
|
let output = self.surface.get_current_texture()?;
|
||||||
|
|
||||||
let render_output = Arc::new(self.device.create_texture(
|
let render_output = Arc::new(self.device.create_texture(&wgpu::TextureDescriptor {
|
||||||
&wgpu::TextureDescriptor {
|
label: Some("rendertexture"),
|
||||||
label: Some("rendertexture"),
|
size: output.texture.size(),
|
||||||
size: output.texture.size(),
|
mip_level_count: output.texture.mip_level_count(),
|
||||||
mip_level_count: output.texture.mip_level_count(),
|
sample_count: output.texture.sample_count(),
|
||||||
sample_count: output.texture.sample_count(),
|
dimension: output.texture.dimension(),
|
||||||
dimension: output.texture.dimension(),
|
format: output.texture.format(),
|
||||||
format: output.texture.format(),
|
usage: wgpu::TextureUsages::TEXTURE_BINDING
|
||||||
usage: wgpu::TextureUsages::TEXTURE_BINDING
|
| wgpu::TextureUsages::RENDER_ATTACHMENT
|
||||||
| wgpu::TextureUsages::RENDER_ATTACHMENT
|
| wgpu::TextureUsages::COPY_DST
|
||||||
| wgpu::TextureUsages::COPY_DST
|
| wgpu::TextureUsages::COPY_SRC,
|
||||||
| wgpu::TextureUsages::COPY_SRC,
|
view_formats: &[output.texture.format()],
|
||||||
view_formats: &[output.texture.format()],
|
}));
|
||||||
}
|
|
||||||
));
|
|
||||||
|
|
||||||
let filter_output = Arc::new(self.device.create_texture(
|
let filter_output = Arc::new(self.device.create_texture(&wgpu::TextureDescriptor {
|
||||||
&wgpu::TextureDescriptor {
|
label: Some("filteroutput"),
|
||||||
label: Some("filteroutput"),
|
size: output.texture.size(),
|
||||||
size: output.texture.size(),
|
mip_level_count: output.texture.mip_level_count(),
|
||||||
mip_level_count: output.texture.mip_level_count(),
|
sample_count: output.texture.sample_count(),
|
||||||
sample_count: output.texture.sample_count(),
|
dimension: output.texture.dimension(),
|
||||||
dimension: output.texture.dimension(),
|
format: output.texture.format(),
|
||||||
format: output.texture.format(),
|
usage: wgpu::TextureUsages::TEXTURE_BINDING
|
||||||
usage: wgpu::TextureUsages::TEXTURE_BINDING
|
| wgpu::TextureUsages::RENDER_ATTACHMENT
|
||||||
| wgpu::TextureUsages::RENDER_ATTACHMENT
|
| wgpu::TextureUsages::COPY_DST
|
||||||
| wgpu::TextureUsages::COPY_DST
|
| wgpu::TextureUsages::COPY_SRC,
|
||||||
| wgpu::TextureUsages::COPY_SRC,
|
view_formats: &[output.texture.format()],
|
||||||
view_formats: &[output.texture.format()],
|
}));
|
||||||
}
|
|
||||||
));
|
|
||||||
|
|
||||||
|
let view = render_output.create_view(&wgpu::TextureViewDescriptor::default());
|
||||||
|
|
||||||
let view = render_output
|
let filter_view = filter_output.create_view(&wgpu::TextureViewDescriptor::default());
|
||||||
.create_view(&wgpu::TextureViewDescriptor::default());
|
|
||||||
|
|
||||||
let filter_view = filter_output
|
|
||||||
.create_view(&wgpu::TextureViewDescriptor::default());
|
|
||||||
|
|
||||||
let mut encoder = self
|
let mut encoder = self
|
||||||
.device
|
.device
|
||||||
|
@ -274,8 +267,7 @@ impl<'a> State<'a> {
|
||||||
});
|
});
|
||||||
|
|
||||||
{
|
{
|
||||||
let mut render_pass =
|
let mut render_pass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
|
||||||
encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
|
|
||||||
label: Some("Render Pass"),
|
label: Some("Render Pass"),
|
||||||
color_attachments: &[Some(wgpu::RenderPassColorAttachment {
|
color_attachments: &[Some(wgpu::RenderPassColorAttachment {
|
||||||
view: &view,
|
view: &view,
|
||||||
|
@ -295,25 +287,28 @@ impl<'a> State<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
self.chain
|
self.chain
|
||||||
.frame(Arc::clone(&render_output),
|
.frame(
|
||||||
&Viewport {
|
Arc::clone(&render_output),
|
||||||
x: 0.0,
|
&Viewport {
|
||||||
y: 0.0,
|
x: 0.0,
|
||||||
mvp: None,
|
y: 0.0,
|
||||||
output: librashader_runtime_wgpu::OutputView {
|
mvp: None,
|
||||||
size: filter_output.size().into(),
|
output: librashader_runtime_wgpu::OutputView {
|
||||||
view: &filter_view,
|
size: filter_output.size().into(),
|
||||||
format: filter_output.format(),
|
view: &filter_view,
|
||||||
},
|
format: filter_output.format(),
|
||||||
},
|
},
|
||||||
&mut encoder,
|
},
|
||||||
self.frame_count, None
|
&mut encoder,
|
||||||
).expect("failed to draw frame");
|
self.frame_count,
|
||||||
|
None,
|
||||||
|
)
|
||||||
|
.expect("failed to draw frame");
|
||||||
|
|
||||||
encoder.copy_texture_to_texture(
|
encoder.copy_texture_to_texture(
|
||||||
filter_output.as_image_copy(),
|
filter_output.as_image_copy(),
|
||||||
output.texture.as_image_copy(),
|
output.texture.as_image_copy(),
|
||||||
output.texture.size()
|
output.texture.size(),
|
||||||
);
|
);
|
||||||
|
|
||||||
self.queue.submit(std::iter::once(encoder.finish()));
|
self.queue.submit(std::iter::once(encoder.finish()));
|
||||||
|
|
|
@ -21,7 +21,9 @@ impl<'a, T, const N: usize> ArrayChunksMut<'a, T, N> {
|
||||||
#[inline]
|
#[inline]
|
||||||
pub(super) fn new(slice: &'a mut [T]) -> Self {
|
pub(super) fn new(slice: &'a mut [T]) -> Self {
|
||||||
let (array_slice, _rem) = as_chunks_mut(slice);
|
let (array_slice, _rem) = as_chunks_mut(slice);
|
||||||
Self { iter: array_slice.iter_mut() }
|
Self {
|
||||||
|
iter: array_slice.iter_mut(),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -54,7 +56,6 @@ impl<'a, T, const N: usize> Iterator for ArrayChunksMut<'a, T, N> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// Splits the slice into a slice of `N`-element arrays,
|
/// Splits the slice into a slice of `N`-element arrays,
|
||||||
/// starting at the beginning of the slice,
|
/// starting at the beginning of the slice,
|
||||||
/// and a remainder slice with length strictly less than `N`.
|
/// and a remainder slice with length strictly less than `N`.
|
||||||
|
@ -69,7 +70,7 @@ impl<'a, T, const N: usize> Iterator for ArrayChunksMut<'a, T, N> {
|
||||||
fn as_chunks_mut<T, const N: usize>(slice: &mut [T]) -> (&mut [[T; N]], &mut [T]) {
|
fn as_chunks_mut<T, const N: usize>(slice: &mut [T]) -> (&mut [[T; N]], &mut [T]) {
|
||||||
unsafe fn as_chunks_unchecked_mut<T, const N: usize>(slice: &mut [T]) -> &mut [[T; N]] {
|
unsafe fn as_chunks_unchecked_mut<T, const N: usize>(slice: &mut [T]) -> &mut [[T; N]] {
|
||||||
// SAFETY: Caller must guarantee that `N` is nonzero and exactly divides the slice length
|
// SAFETY: Caller must guarantee that `N` is nonzero and exactly divides the slice length
|
||||||
let new_len = slice.len() / N;
|
let new_len = slice.len() / N;
|
||||||
|
|
||||||
// SAFETY: We cast a slice of `new_len * N` elements into
|
// SAFETY: We cast a slice of `new_len * N` elements into
|
||||||
// a slice of `new_len` many `N` elements chunks.
|
// a slice of `new_len` many `N` elements chunks.
|
||||||
|
@ -83,4 +84,4 @@ fn as_chunks_mut<T, const N: usize>(slice: &mut [T]) -> (&mut [[T; N]], &mut [T]
|
||||||
// that the length of the subslice is a multiple of N.
|
// that the length of the subslice is a multiple of N.
|
||||||
let array_slice = unsafe { as_chunks_unchecked_mut(multiple_of_n) };
|
let array_slice = unsafe { as_chunks_unchecked_mut(multiple_of_n) };
|
||||||
(array_slice, remainder)
|
(array_slice, remainder)
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,8 +2,8 @@ pub use image::ImageError;
|
||||||
use librashader_common::Size;
|
use librashader_common::Size;
|
||||||
use std::marker::PhantomData;
|
use std::marker::PhantomData;
|
||||||
|
|
||||||
use std::path::Path;
|
|
||||||
use crate::array_chunks_mut::ArrayChunksMut;
|
use crate::array_chunks_mut::ArrayChunksMut;
|
||||||
|
use std::path::Path;
|
||||||
|
|
||||||
/// An uncompressed raw image ready to upload to GPU buffers.
|
/// An uncompressed raw image ready to upload to GPU buffers.
|
||||||
pub struct Image<P: PixelFormat = RGBA8> {
|
pub struct Image<P: PixelFormat = RGBA8> {
|
||||||
|
|
Loading…
Reference in a new issue