use renderer_resources
This commit is contained in:
parent
e7a6536df5
commit
d367b4d05b
|
|
@ -5,3 +5,5 @@ edition = "2024"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
ash.workspace = true
|
ash.workspace = true
|
||||||
|
renderer_resources = { path = "../renderer_resources" }
|
||||||
|
ash-formats = { git = "https://github.com/janis-bhm/ash-formats", branch = "main" }
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,13 @@
|
||||||
use std::collections::{BTreeMap, BTreeSet};
|
use std::{
|
||||||
|
collections::{BTreeMap, BTreeSet, HashMap},
|
||||||
|
sync::Arc,
|
||||||
|
};
|
||||||
|
|
||||||
use ash::vk;
|
use ash::vk;
|
||||||
|
use ash_formats::FormatExt;
|
||||||
|
use renderer_resources::{
|
||||||
|
Device, buffers::Buffer as BufferResource, images::Image as ImageResource,
|
||||||
|
};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
recorder::{CommandIndex, CommandList, CommandRecorder, RecordError, scope_range},
|
recorder::{CommandIndex, CommandList, CommandRecorder, RecordError, scope_range},
|
||||||
|
|
@ -65,28 +72,34 @@ impl RenderGraph {
|
||||||
id
|
id
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn create_buffer(&mut self, desc: crate::resources::BufferDesc) -> Buffer {
|
pub fn create_buffer(&mut self, desc: renderer_resources::buffers::BufferDesc) -> Buffer {
|
||||||
Buffer(self.add_resource(ResourceDesc::CreatedBuffer(desc)))
|
Buffer(self.add_resource(ResourceDesc::CreatedBuffer(desc)))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn create_texture(&mut self, desc: crate::resources::TextureDesc) -> Texture {
|
pub fn create_texture(&mut self, desc: renderer_resources::images::ImageDesc) -> Texture {
|
||||||
Texture(self.add_resource(ResourceDesc::CreatedTexture(desc)))
|
Texture(self.add_resource(ResourceDesc::CreatedTexture(desc)))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn import_buffer(
|
pub fn import_buffer(
|
||||||
&mut self,
|
&mut self,
|
||||||
handle: vk::Buffer,
|
resource: impl Into<Arc<BufferResource>>,
|
||||||
initial: crate::resources::ResourceState,
|
initial: crate::resources::ResourceState,
|
||||||
) -> Buffer {
|
) -> Buffer {
|
||||||
Buffer(self.add_resource(ResourceDesc::ImportedBuffer { handle, initial }))
|
Buffer(self.add_resource(ResourceDesc::ImportedBuffer {
|
||||||
|
resource: resource.into(),
|
||||||
|
initial,
|
||||||
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn import_texture(
|
pub fn import_texture(
|
||||||
&mut self,
|
&mut self,
|
||||||
handle: vk::Image,
|
resource: impl Into<Arc<ImageResource>>,
|
||||||
initial: crate::resources::ResourceState,
|
initial: crate::resources::ResourceState,
|
||||||
) -> Texture {
|
) -> Texture {
|
||||||
Texture(self.add_resource(ResourceDesc::ImportedTexture { handle, initial }))
|
Texture(self.add_resource(ResourceDesc::ImportedTexture {
|
||||||
|
resource: resource.into(),
|
||||||
|
initial,
|
||||||
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn push<C: crate::commands::Command + 'static>(&mut self, command: C) -> CommandIndex {
|
pub fn push<C: crate::commands::Command + 'static>(&mut self, command: C) -> CommandIndex {
|
||||||
|
|
@ -144,6 +157,7 @@ impl RenderGraph {
|
||||||
|
|
||||||
Ok(CompiledGraph {
|
Ok(CompiledGraph {
|
||||||
resources: self.resources,
|
resources: self.resources,
|
||||||
|
resolved: HashMap::new(),
|
||||||
commands: self.commands,
|
commands: self.commands,
|
||||||
order,
|
order,
|
||||||
barriers,
|
barriers,
|
||||||
|
|
@ -160,10 +174,16 @@ impl Default for RenderGraph {
|
||||||
|
|
||||||
pub struct CompiledGraph {
|
pub struct CompiledGraph {
|
||||||
resources: BTreeMap<ResourceId, ResourceDesc>,
|
resources: BTreeMap<ResourceId, ResourceDesc>,
|
||||||
|
resolved: HashMap<ResourceId, ResolvedResource>,
|
||||||
commands: CommandList,
|
commands: CommandList,
|
||||||
order: Vec<CommandIndex>,
|
order: Vec<CommandIndex>,
|
||||||
barriers: Vec<PipelineBarrier>,
|
barriers: Vec<PipelineBarrier>,
|
||||||
lifetimes: BTreeMap<ResourceId, ResourceLifetime>,
|
lifetimes: HashMap<ResourceId, ResourceLifetime>,
|
||||||
|
}
|
||||||
|
|
||||||
|
enum ResolvedResource {
|
||||||
|
Buffer(Arc<BufferResource>),
|
||||||
|
Image(Arc<ImageResource>),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl CompiledGraph {
|
impl CompiledGraph {
|
||||||
|
|
@ -175,27 +195,64 @@ impl CompiledGraph {
|
||||||
&self.barriers
|
&self.barriers
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn resource_lifetimes(&self) -> &BTreeMap<ResourceId, ResourceLifetime> {
|
pub fn resource_lifetimes(&self) -> &HashMap<ResourceId, ResourceLifetime> {
|
||||||
&self.lifetimes
|
&self.lifetimes
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Create the graph's transient resources. Compilation remains independent
|
||||||
|
/// of a Vulkan device, while command recording requires this resolution step
|
||||||
|
/// for any created resources used by commands.
|
||||||
|
pub fn resolve(&mut self, device: &Device) -> renderer_resources::Result<()> {
|
||||||
|
for (&id, desc) in &self.resources {
|
||||||
|
if self.resolved.contains_key(&id) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
let resource = match desc {
|
||||||
|
ResourceDesc::CreatedBuffer(desc) => ResolvedResource::Buffer(Arc::new(
|
||||||
|
BufferResource::new(device.clone(), desc.clone())?,
|
||||||
|
)),
|
||||||
|
ResourceDesc::CreatedTexture(desc) => ResolvedResource::Image(Arc::new(
|
||||||
|
ImageResource::new(device.clone(), desc.clone())?,
|
||||||
|
)),
|
||||||
|
ResourceDesc::ImportedBuffer { .. } | ResourceDesc::ImportedTexture { .. } => {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
self.resolved.insert(id, resource);
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
/// Record the compiled order into a real Vulkan command buffer. Imported
|
/// Record the compiled order into a real Vulkan command buffer. Imported
|
||||||
/// handles are automatically bound. Created resources require a future
|
/// handles are automatically bound. Created resources must first be
|
||||||
/// allocator integration and currently return a missing-handle error when
|
/// resolved with a device.
|
||||||
/// used by a command.
|
|
||||||
pub fn record_commands(
|
pub fn record_commands(
|
||||||
&mut self,
|
&mut self,
|
||||||
recorder: &mut CommandRecorder<'_>,
|
recorder: &mut CommandRecorder<'_>,
|
||||||
) -> Result<(), RecordError> {
|
) -> Result<(), RecordError> {
|
||||||
for (&id, &desc) in &self.resources {
|
for (&id, desc) in &self.resources {
|
||||||
|
if !self.lifetimes.contains_key(&id) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
match desc {
|
match desc {
|
||||||
ResourceDesc::ImportedBuffer { handle, .. } => {
|
ResourceDesc::ImportedBuffer { resource, .. } => {
|
||||||
recorder.buffers.insert(id, handle);
|
recorder.buffers.insert(id, resource.raw());
|
||||||
}
|
}
|
||||||
ResourceDesc::ImportedTexture { handle, .. } => {
|
ResourceDesc::ImportedTexture { resource, .. } => {
|
||||||
recorder.images.insert(id, handle);
|
recorder.images.insert(id, resource.raw());
|
||||||
}
|
}
|
||||||
ResourceDesc::CreatedBuffer(_) | ResourceDesc::CreatedTexture(_) => {}
|
ResourceDesc::CreatedBuffer(_) => match self.resolved.get(&id) {
|
||||||
|
Some(ResolvedResource::Buffer(resource)) => {
|
||||||
|
recorder.buffers.insert(id, resource.raw());
|
||||||
|
}
|
||||||
|
_ => return Err(RecordError::UnresolvedCreatedBuffer(id)),
|
||||||
|
},
|
||||||
|
ResourceDesc::CreatedTexture(_) => match self.resolved.get(&id) {
|
||||||
|
Some(ResolvedResource::Image(resource)) => {
|
||||||
|
recorder.images.insert(id, resource.raw());
|
||||||
|
}
|
||||||
|
_ => return Err(RecordError::UnresolvedCreatedImage(id)),
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -245,7 +302,7 @@ fn build_barriers(
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
let desc = resource_descs[¤t.resource];
|
let desc = &resource_descs[¤t.resource];
|
||||||
let initial = desc.initial_state();
|
let initial = desc.initial_state();
|
||||||
let (old_layout, new_layout) = layouts_from_state(initial, current.scope);
|
let (old_layout, new_layout) = layouts_from_state(initial, current.scope);
|
||||||
let layout_transition = old_layout != new_layout && new_layout.is_some();
|
let layout_transition = old_layout != new_layout && new_layout.is_some();
|
||||||
|
|
@ -303,8 +360,8 @@ fn layouts_from_state(
|
||||||
fn bind_resources(
|
fn bind_resources(
|
||||||
resources: &BTreeMap<ResourceId, ResourceDesc>,
|
resources: &BTreeMap<ResourceId, ResourceDesc>,
|
||||||
accesses: &[Vec<crate::recorder::ResourceAccess>],
|
accesses: &[Vec<crate::recorder::ResourceAccess>],
|
||||||
) -> BTreeMap<ResourceId, ResourceLifetime> {
|
) -> HashMap<ResourceId, ResourceLifetime> {
|
||||||
let mut lifetimes = BTreeMap::new();
|
let mut lifetimes = HashMap::new();
|
||||||
for (command, command_accesses) in accesses.iter().enumerate() {
|
for (command, command_accesses) in accesses.iter().enumerate() {
|
||||||
for access in command_accesses {
|
for access in command_accesses {
|
||||||
lifetimes
|
lifetimes
|
||||||
|
|
@ -328,12 +385,19 @@ fn bind_resources(
|
||||||
ids.sort_by_key(|id| lifetimes[id].first_command);
|
ids.sort_by_key(|id| lifetimes[id].first_command);
|
||||||
for id in ids {
|
for id in ids {
|
||||||
let lifetime = lifetimes.get_mut(&id).expect("lifetime key exists");
|
let lifetime = lifetimes.get_mut(&id).expect("lifetime key exists");
|
||||||
let size = match resources[&id] {
|
let size = match &resources[&id] {
|
||||||
ResourceDesc::CreatedBuffer(desc) => desc.size,
|
ResourceDesc::CreatedBuffer(desc) => desc.size,
|
||||||
ResourceDesc::CreatedTexture(desc) => u64::from(desc.extent.width)
|
ResourceDesc::CreatedTexture(desc) => {
|
||||||
|
let texels_per_block = u64::from(desc.format.texels_per_block()).max(1);
|
||||||
|
let block_size = u64::from(desc.format.block_size());
|
||||||
|
u64::from(desc.extent.width)
|
||||||
.saturating_mul(u64::from(desc.extent.height))
|
.saturating_mul(u64::from(desc.extent.height))
|
||||||
.saturating_mul(u64::from(desc.extent.depth))
|
.saturating_mul(u64::from(desc.extent.depth))
|
||||||
.saturating_mul(4),
|
.div_ceil(texels_per_block)
|
||||||
|
.saturating_mul(block_size)
|
||||||
|
.saturating_mul(u64::from(desc.array_layers))
|
||||||
|
.saturating_mul(u64::from(desc.samples.as_raw().max(1)))
|
||||||
|
}
|
||||||
ResourceDesc::ImportedBuffer { .. } | ResourceDesc::ImportedTexture { .. } => 0,
|
ResourceDesc::ImportedBuffer { .. } | ResourceDesc::ImportedTexture { .. } => 0,
|
||||||
};
|
};
|
||||||
if resources[&id].is_created()
|
if resources[&id].is_created()
|
||||||
|
|
@ -358,18 +422,23 @@ fn bind_resources(
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::{commands::CopyBuffer, resources::BufferRange};
|
use crate::{
|
||||||
|
commands::{ClearTexture, CopyBuffer},
|
||||||
|
resources::BufferRange,
|
||||||
|
};
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn copy_buffer_compiles_with_dependency_and_barrier() {
|
fn copy_buffer_compiles_with_dependency_and_barrier() {
|
||||||
let mut graph = RenderGraph::new();
|
let mut graph = RenderGraph::new();
|
||||||
let src = graph.create_buffer(crate::resources::BufferDesc {
|
let src = graph.create_buffer(renderer_resources::buffers::BufferDesc {
|
||||||
size: 64,
|
size: 64,
|
||||||
usage: vk::BufferUsageFlags::TRANSFER_SRC,
|
usage: vk::BufferUsageFlags::TRANSFER_SRC,
|
||||||
|
..Default::default()
|
||||||
});
|
});
|
||||||
let dst = graph.create_buffer(crate::resources::BufferDesc {
|
let dst = graph.create_buffer(renderer_resources::buffers::BufferDesc {
|
||||||
size: 64,
|
size: 64,
|
||||||
usage: vk::BufferUsageFlags::TRANSFER_DST,
|
usage: vk::BufferUsageFlags::TRANSFER_DST,
|
||||||
|
..Default::default()
|
||||||
});
|
});
|
||||||
graph.push(CopyBuffer {
|
graph.push(CopyBuffer {
|
||||||
src,
|
src,
|
||||||
|
|
@ -393,17 +462,20 @@ mod tests {
|
||||||
#[test]
|
#[test]
|
||||||
fn write_then_read_creates_order_and_barrier() {
|
fn write_then_read_creates_order_and_barrier() {
|
||||||
let mut graph = RenderGraph::new();
|
let mut graph = RenderGraph::new();
|
||||||
let a = graph.create_buffer(crate::resources::BufferDesc {
|
let a = graph.create_buffer(renderer_resources::buffers::BufferDesc {
|
||||||
size: 32,
|
size: 32,
|
||||||
usage: vk::BufferUsageFlags::TRANSFER_SRC | vk::BufferUsageFlags::TRANSFER_DST,
|
usage: vk::BufferUsageFlags::TRANSFER_SRC | vk::BufferUsageFlags::TRANSFER_DST,
|
||||||
|
..Default::default()
|
||||||
});
|
});
|
||||||
let b = graph.create_buffer(crate::resources::BufferDesc {
|
let b = graph.create_buffer(renderer_resources::buffers::BufferDesc {
|
||||||
size: 32,
|
size: 32,
|
||||||
usage: vk::BufferUsageFlags::TRANSFER_DST,
|
usage: vk::BufferUsageFlags::TRANSFER_DST,
|
||||||
|
..Default::default()
|
||||||
});
|
});
|
||||||
let c = graph.create_buffer(crate::resources::BufferDesc {
|
let c = graph.create_buffer(renderer_resources::buffers::BufferDesc {
|
||||||
size: 32,
|
size: 32,
|
||||||
usage: vk::BufferUsageFlags::TRANSFER_DST,
|
usage: vk::BufferUsageFlags::TRANSFER_DST,
|
||||||
|
..Default::default()
|
||||||
});
|
});
|
||||||
graph.push(CopyBuffer {
|
graph.push(CopyBuffer {
|
||||||
src: a,
|
src: a,
|
||||||
|
|
@ -439,4 +511,56 @@ mod tests {
|
||||||
assert_eq!(compiled.barriers()[0].before_command, CommandIndex(1));
|
assert_eq!(compiled.barriers()[0].before_command, CommandIndex(1));
|
||||||
assert_eq!(compiled.barriers()[0].resources[0].id, b.id());
|
assert_eq!(compiled.barriers()[0].resources[0].id, b.id());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn texture_aliasing_size_uses_format_block_size() {
|
||||||
|
let mut graph = RenderGraph::new();
|
||||||
|
let texture = graph.create_texture(renderer_resources::images::ImageDesc {
|
||||||
|
format: vk::Format::R8G8B8A8_UNORM,
|
||||||
|
extent: vk::Extent3D {
|
||||||
|
width: 4,
|
||||||
|
height: 4,
|
||||||
|
depth: 1,
|
||||||
|
},
|
||||||
|
usage: vk::ImageUsageFlags::TRANSFER_DST,
|
||||||
|
..Default::default()
|
||||||
|
});
|
||||||
|
let buffer = graph.create_buffer(renderer_resources::buffers::BufferDesc {
|
||||||
|
size: 8,
|
||||||
|
usage: vk::BufferUsageFlags::TRANSFER_DST,
|
||||||
|
..Default::default()
|
||||||
|
});
|
||||||
|
graph.push(ClearTexture {
|
||||||
|
texture,
|
||||||
|
range: vk::ImageSubresourceRange {
|
||||||
|
aspect_mask: vk::ImageAspectFlags::COLOR,
|
||||||
|
base_mip_level: 0,
|
||||||
|
level_count: 1,
|
||||||
|
base_array_layer: 0,
|
||||||
|
layer_count: 1,
|
||||||
|
},
|
||||||
|
layout: vk::ImageLayout::TRANSFER_DST_OPTIMAL,
|
||||||
|
color: [0.0; 4],
|
||||||
|
});
|
||||||
|
// Keep the buffer live in the same command, so its slot follows the image.
|
||||||
|
graph.commands.side_effects.insert(
|
||||||
|
CommandIndex(0),
|
||||||
|
buffer.id(),
|
||||||
|
SubresourceScope {
|
||||||
|
stage: vk::PipelineStageFlags2::CLEAR,
|
||||||
|
access: vk::AccessFlags2::TRANSFER_WRITE,
|
||||||
|
subresource: SubresourceScopeInner::Buffer(BufferRange { offset: 0, size: 8 }),
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
let compiled = graph.compile().expect("graph compiles");
|
||||||
|
assert_eq!(
|
||||||
|
compiled.resource_lifetimes()[&texture.id()].memory_offset,
|
||||||
|
0
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
compiled.resource_lifetimes()[&buffer.id()].memory_offset,
|
||||||
|
64
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -121,10 +121,11 @@ impl Default for CommandList {
|
||||||
pub enum RecordError {
|
pub enum RecordError {
|
||||||
MissingBuffer(ResourceId),
|
MissingBuffer(ResourceId),
|
||||||
MissingImage(ResourceId),
|
MissingImage(ResourceId),
|
||||||
|
UnresolvedCreatedBuffer(ResourceId),
|
||||||
|
UnresolvedCreatedImage(ResourceId),
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Vulkan recording context. Handle maps are populated for imported resources;
|
/// Vulkan recording context. Handle maps are populated by the compiled graph.
|
||||||
/// transient allocation is intentionally left to a later allocator integration.
|
|
||||||
pub struct CommandRecorder<'a> {
|
pub struct CommandRecorder<'a> {
|
||||||
pub device: &'a ash::Device,
|
pub device: &'a ash::Device,
|
||||||
pub command_buffer: vk::CommandBuffer,
|
pub command_buffer: vk::CommandBuffer,
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,7 @@
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
use ash::vk;
|
use ash::vk;
|
||||||
|
use renderer_resources::{buffers::Buffer as BufferResource, images::Image as ImageResource};
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||||
#[repr(transparent)]
|
#[repr(transparent)]
|
||||||
|
|
@ -190,19 +193,6 @@ pub fn access_flag_is_write(access: vk::AccessFlags2) -> bool {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy)]
|
|
||||||
pub struct BufferDesc {
|
|
||||||
pub size: u64,
|
|
||||||
pub usage: vk::BufferUsageFlags,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy)]
|
|
||||||
pub struct TextureDesc {
|
|
||||||
pub format: vk::Format,
|
|
||||||
pub extent: vk::Extent3D,
|
|
||||||
pub usage: vk::ImageUsageFlags,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy)]
|
#[derive(Debug, Clone, Copy)]
|
||||||
pub struct ResourceState {
|
pub struct ResourceState {
|
||||||
pub stage: vk::PipelineStageFlags2,
|
pub stage: vk::PipelineStageFlags2,
|
||||||
|
|
@ -220,29 +210,31 @@ impl Default for ResourceState {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy)]
|
#[derive(Debug, Clone)]
|
||||||
pub enum ResourceDesc {
|
pub enum ResourceDesc {
|
||||||
CreatedBuffer(BufferDesc),
|
CreatedBuffer(renderer_resources::buffers::BufferDesc),
|
||||||
CreatedTexture(TextureDesc),
|
CreatedTexture(renderer_resources::images::ImageDesc),
|
||||||
ImportedBuffer {
|
ImportedBuffer {
|
||||||
handle: vk::Buffer,
|
resource: Arc<BufferResource>,
|
||||||
initial: ResourceState,
|
initial: ResourceState,
|
||||||
},
|
},
|
||||||
ImportedTexture {
|
ImportedTexture {
|
||||||
handle: vk::Image,
|
resource: Arc<ImageResource>,
|
||||||
initial: ResourceState,
|
initial: ResourceState,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ResourceDesc {
|
impl ResourceDesc {
|
||||||
pub fn initial_state(self) -> ResourceState {
|
pub fn initial_state(&self) -> ResourceState {
|
||||||
match self {
|
match self {
|
||||||
Self::ImportedBuffer { initial, .. } | Self::ImportedTexture { initial, .. } => initial,
|
Self::ImportedBuffer { initial, .. } | Self::ImportedTexture { initial, .. } => {
|
||||||
|
*initial
|
||||||
|
}
|
||||||
Self::CreatedBuffer(_) | Self::CreatedTexture(_) => ResourceState::default(),
|
Self::CreatedBuffer(_) | Self::CreatedTexture(_) => ResourceState::default(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn is_created(self) -> bool {
|
pub fn is_created(&self) -> bool {
|
||||||
matches!(self, Self::CreatedBuffer(_) | Self::CreatedTexture(_))
|
matches!(self, Self::CreatedBuffer(_) | Self::CreatedTexture(_))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue