Skip to content

Commit 9794870

Browse files
authored
hal/vulkan: generate separate hash identity for Texture/TextureViews (#7972)
1 parent c95b7fe commit 9794870

File tree

5 files changed

+139
-12
lines changed

5 files changed

+139
-12
lines changed

wgpu-hal/src/vulkan/adapter.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2162,6 +2162,9 @@ impl super::Adapter {
21622162
self.private_caps.maximum_samplers,
21632163
)),
21642164
memory_allocations_counter: Default::default(),
2165+
2166+
texture_identity_factory: super::ResourceIdentityFactory::new(),
2167+
texture_view_identity_factory: super::ResourceIdentityFactory::new(),
21652168
});
21662169

21672170
let relay_semaphores = super::RelaySemaphores::new(&shared)?;

wgpu-hal/src/vulkan/command.rs

Lines changed: 16 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,8 @@ impl super::CommandEncoder {
6161
Entry::Vacant(e) => {
6262
let super::FramebufferKey {
6363
raw_pass,
64-
ref attachments,
64+
ref attachment_views,
65+
attachment_identities: _,
6566
extent,
6667
} = *e.key();
6768

@@ -70,7 +71,7 @@ impl super::CommandEncoder {
7071
.width(extent.width)
7172
.height(extent.height)
7273
.layers(extent.depth_or_array_layers)
73-
.attachments(attachments);
74+
.attachments(attachment_views);
7475

7576
let raw = unsafe { self.device.raw.create_framebuffer(&vk_info, None).unwrap() };
7677
*e.insert(raw)
@@ -81,12 +82,13 @@ impl super::CommandEncoder {
8182
fn make_temp_texture_view(
8283
&mut self,
8384
key: super::TempTextureViewKey,
84-
) -> Result<vk::ImageView, crate::DeviceError> {
85+
) -> Result<super::IdentifiedTextureView, crate::DeviceError> {
8586
Ok(match self.temp_texture_views.entry(key) {
8687
Entry::Occupied(e) => *e.get(),
8788
Entry::Vacant(e) => {
8889
let super::TempTextureViewKey {
8990
texture,
91+
texture_identity: _,
9092
format,
9193
mip_level,
9294
depth_slice,
@@ -105,7 +107,10 @@ impl super::CommandEncoder {
105107
});
106108
let raw = unsafe { self.device.raw.create_image_view(&vk_info, None) }
107109
.map_err(super::map_host_device_oom_and_ioca_err)?;
108-
*e.insert(raw)
110+
111+
let identity = self.device.texture_view_identity_factory.next();
112+
113+
*e.insert(super::IdentifiedTextureView { raw, identity })
109114
}
110115
})
111116
}
@@ -779,7 +784,8 @@ impl crate::CommandEncoder for super::CommandEncoder {
779784
};
780785
let mut fb_key = super::FramebufferKey {
781786
raw_pass: vk::RenderPass::null(),
782-
attachments: ArrayVec::default(),
787+
attachment_views: ArrayVec::default(),
788+
attachment_identities: ArrayVec::default(),
783789
extent: desc.extent,
784790
};
785791

@@ -788,13 +794,14 @@ impl crate::CommandEncoder for super::CommandEncoder {
788794
let color_view = if cat.target.view.dimension == wgt::TextureViewDimension::D3 {
789795
let key = super::TempTextureViewKey {
790796
texture: cat.target.view.raw_texture,
797+
texture_identity: cat.target.view.texture_identity,
791798
format: cat.target.view.raw_format,
792799
mip_level: cat.target.view.base_mip_level,
793800
depth_slice: cat.depth_slice.unwrap(),
794801
};
795802
self.make_temp_texture_view(key)?
796803
} else {
797-
cat.target.view.raw
804+
cat.target.view.identified_raw_view()
798805
};
799806

800807
vk_clear_values.push(vk::ClearValue {
@@ -809,10 +816,10 @@ impl crate::CommandEncoder for super::CommandEncoder {
809816
};
810817

811818
rp_key.colors.push(Some(color));
812-
fb_key.attachments.push(color_view);
819+
fb_key.push_view(color_view);
813820
if let Some(ref at) = cat.resolve_target {
814821
vk_clear_values.push(unsafe { mem::zeroed() });
815-
fb_key.attachments.push(at.view.raw);
822+
fb_key.push_view(at.view.identified_raw_view());
816823
}
817824

818825
// Assert this attachment is valid for the detected multiview, as a sanity check
@@ -838,7 +845,7 @@ impl crate::CommandEncoder for super::CommandEncoder {
838845
base: ds.target.make_attachment_key(ds.depth_ops),
839846
stencil_ops: ds.stencil_ops,
840847
});
841-
fb_key.attachments.push(ds.target.view.raw);
848+
fb_key.push_view(ds.target.view.identified_raw_view());
842849

843850
// Assert this attachment is valid for the detected multiview, as a sanity check
844851
// The driver crash for this is really bad on AMD, so the check is worth it

wgpu-hal/src/vulkan/device.rs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -603,6 +603,7 @@ impl super::Device {
603603
/// `drop_callback` is [`Some`], `vk_image` must be valid until the callback is called.
604604
/// - If the `ImageCreateFlags` does not contain `MUTABLE_FORMAT`, the `view_formats` of `desc` must be empty.
605605
pub unsafe fn texture_from_raw(
606+
&self,
606607
vk_image: vk::Image,
607608
desc: &crate::TextureDescriptor,
608609
drop_callback: Option<crate::DropCallback>,
@@ -624,6 +625,8 @@ impl super::Device {
624625
raw_flags |= vk::ImageCreateFlags::MUTABLE_FORMAT;
625626
}
626627

628+
let identity = self.shared.texture_identity_factory.next();
629+
627630
let drop_guard = crate::DropGuard::from_option(drop_callback);
628631

629632
super::Texture {
@@ -633,6 +636,7 @@ impl super::Device {
633636
block: None,
634637
format: desc.format,
635638
copy_size: desc.copy_extent(),
639+
identity,
636640
}
637641
}
638642

@@ -796,6 +800,8 @@ impl super::Device {
796800
unsafe { self.shared.set_object_name(image.raw, label) };
797801
}
798802

803+
let identity = self.shared.texture_identity_factory.next();
804+
799805
self.counters.textures.add(1);
800806

801807
Ok(super::Texture {
@@ -805,6 +811,7 @@ impl super::Device {
805811
block: None,
806812
format: desc.format,
807813
copy_size: image.copy_size,
814+
identity,
808815
})
809816
}
810817

@@ -1274,6 +1281,8 @@ impl crate::Device for super::Device {
12741281
unsafe { self.shared.set_object_name(image.raw, label) };
12751282
}
12761283

1284+
let identity = self.shared.texture_identity_factory.next();
1285+
12771286
self.counters.textures.add(1);
12781287

12791288
Ok(super::Texture {
@@ -1283,6 +1292,7 @@ impl crate::Device for super::Device {
12831292
block: Some(block),
12841293
format: desc.format,
12851294
copy_size: image.copy_size,
1295+
identity,
12861296
})
12871297
}
12881298
unsafe fn destroy_texture(&self, texture: super::Texture) {
@@ -1335,6 +1345,8 @@ impl crate::Device for super::Device {
13351345
unsafe { self.shared.set_object_name(raw, label) };
13361346
}
13371347

1348+
let identity = self.shared.texture_view_identity_factory.next();
1349+
13381350
self.counters.texture_views.add(1);
13391351

13401352
Ok(super::TextureView {
@@ -1345,6 +1357,8 @@ impl crate::Device for super::Device {
13451357
raw_format,
13461358
base_mip_level: desc.range.base_mip_level,
13471359
dimension: desc.dimension,
1360+
texture_identity: texture.identity,
1361+
view_identity: identity,
13481362
})
13491363
}
13501364
unsafe fn destroy_texture_view(&self, view: super::TextureView) {

wgpu-hal/src/vulkan/instance.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1139,6 +1139,8 @@ impl crate::Surface for super::Surface {
11391139
return Err(crate::SurfaceError::Outdated);
11401140
}
11411141

1142+
let identity = swapchain.device.texture_identity_factory.next();
1143+
11421144
let texture = super::SurfaceTexture {
11431145
index,
11441146
texture: super::Texture {
@@ -1152,6 +1154,7 @@ impl crate::Surface for super::Surface {
11521154
height: swapchain.config.extent.height,
11531155
depth: 1,
11541156
},
1157+
identity,
11551158
},
11561159
surface_semaphores: swapchain_semaphores_arc,
11571160
};

wgpu-hal/src/vulkan/mod.rs

Lines changed: 103 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -651,6 +651,14 @@ struct DeviceShared {
651651
render_passes: Mutex<FastHashMap<RenderPassKey, vk::RenderPass>>,
652652
sampler_cache: Mutex<sampler::SamplerCache>,
653653
memory_allocations_counter: InternalCounter,
654+
655+
/// Because we have cached framebuffers which are not deleted from until
656+
/// the device is destroyed, if the implementation of vulkan re-uses handles
657+
/// we need some way to differentiate between the old handle and the new handle.
658+
/// This factory allows us to have a dedicated identity value for each texture.
659+
texture_identity_factory: ResourceIdentityFactory<vk::Image>,
660+
/// As above, for texture views.
661+
texture_view_identity_factory: ResourceIdentityFactory<vk::ImageView>,
654662
}
655663

656664
impl Drop for DeviceShared {
@@ -864,6 +872,7 @@ pub struct Texture {
864872
block: Option<gpu_alloc::MemoryBlock<vk::DeviceMemory>>,
865873
format: wgt::TextureFormat,
866874
copy_size: crate::CopyExtent,
875+
identity: ResourceIdentity<vk::Image>,
867876
}
868877

869878
impl crate::DynTexture for Texture {}
@@ -886,6 +895,8 @@ pub struct TextureView {
886895
raw_format: vk::Format,
887896
base_mip_level: u32,
888897
dimension: wgt::TextureViewDimension,
898+
texture_identity: ResourceIdentity<vk::Image>,
899+
view_identity: ResourceIdentity<vk::ImageView>,
889900
}
890901

891902
impl crate::DynTextureView for TextureView {}
@@ -897,6 +908,14 @@ impl TextureView {
897908
pub unsafe fn raw_handle(&self) -> vk::ImageView {
898909
self.raw
899910
}
911+
912+
/// Returns the raw texture view, along with its identity.
913+
fn identified_raw_view(&self) -> IdentifiedTextureView {
914+
IdentifiedTextureView {
915+
raw: self.raw,
916+
identity: self.view_identity,
917+
}
918+
}
900919
}
901920

902921
#[derive(Debug)]
@@ -956,16 +975,97 @@ impl Temp {
956975
}
957976
}
958977

978+
/// Generates unique IDs for each resource of type `T`.
979+
///
980+
/// Because vk handles are not permanently unique, this
981+
/// provides a way to generate unique IDs for each resource.
982+
struct ResourceIdentityFactory<T> {
983+
#[cfg(not(target_has_atomic = "64"))]
984+
next_id: Mutex<u64>,
985+
#[cfg(target_has_atomic = "64")]
986+
next_id: core::sync::atomic::AtomicU64,
987+
_phantom: PhantomData<T>,
988+
}
989+
990+
impl<T> ResourceIdentityFactory<T> {
991+
fn new() -> Self {
992+
Self {
993+
#[cfg(not(target_has_atomic = "64"))]
994+
next_id: Mutex::new(0),
995+
#[cfg(target_has_atomic = "64")]
996+
next_id: core::sync::atomic::AtomicU64::new(0),
997+
_phantom: PhantomData,
998+
}
999+
}
1000+
1001+
/// Returns a new unique ID for a resource of type `T`.
1002+
fn next(&self) -> ResourceIdentity<T> {
1003+
#[cfg(not(target_has_atomic = "64"))]
1004+
{
1005+
let mut next_id = self.next_id.lock();
1006+
let id = *next_id;
1007+
*next_id += 1;
1008+
ResourceIdentity {
1009+
id,
1010+
_phantom: PhantomData,
1011+
}
1012+
}
1013+
1014+
#[cfg(target_has_atomic = "64")]
1015+
ResourceIdentity {
1016+
id: self
1017+
.next_id
1018+
.fetch_add(1, core::sync::atomic::Ordering::Relaxed),
1019+
_phantom: PhantomData,
1020+
}
1021+
}
1022+
}
1023+
1024+
/// A unique identifier for a resource of type `T`.
1025+
///
1026+
/// This is used as a hashable key for resources, which
1027+
/// is permanently unique through the lifetime of the program.
1028+
#[derive(Debug, Copy, Clone, Eq, Hash, PartialEq)]
1029+
struct ResourceIdentity<T> {
1030+
id: u64,
1031+
_phantom: PhantomData<T>,
1032+
}
1033+
9591034
#[derive(Clone, Eq, Hash, PartialEq)]
9601035
struct FramebufferKey {
9611036
raw_pass: vk::RenderPass,
962-
attachments: ArrayVec<vk::ImageView, { MAX_TOTAL_ATTACHMENTS }>,
1037+
/// Because this is used as a key in a hash map, we need to include the identity
1038+
/// so that this hashes differently, even if the ImageView handles are the same
1039+
/// between different views.
1040+
attachment_identities: ArrayVec<ResourceIdentity<vk::ImageView>, { MAX_TOTAL_ATTACHMENTS }>,
1041+
/// While this is redundant for calculating the hash, we need access to an array
1042+
/// of all the raw ImageViews when we are creating the actual framebuffer,
1043+
/// so we store this here.
1044+
attachment_views: ArrayVec<vk::ImageView, { MAX_TOTAL_ATTACHMENTS }>,
9631045
extent: wgt::Extent3d,
9641046
}
9651047

1048+
impl FramebufferKey {
1049+
fn push_view(&mut self, view: IdentifiedTextureView) {
1050+
self.attachment_identities.push(view.identity);
1051+
self.attachment_views.push(view.raw);
1052+
}
1053+
}
1054+
1055+
/// A texture view paired with its identity.
1056+
#[derive(Copy, Clone)]
1057+
struct IdentifiedTextureView {
1058+
raw: vk::ImageView,
1059+
identity: ResourceIdentity<vk::ImageView>,
1060+
}
1061+
9661062
#[derive(Clone, Eq, Hash, PartialEq)]
9671063
struct TempTextureViewKey {
9681064
texture: vk::Image,
1065+
/// As this is used in a hashmap, we need to
1066+
/// include the identity so that this hashes differently,
1067+
/// even if the Image handles are the same between different images.
1068+
texture_identity: ResourceIdentity<vk::Image>,
9691069
format: vk::Format,
9701070
mip_level: u32,
9711071
depth_slice: u32,
@@ -1008,7 +1108,7 @@ pub struct CommandEncoder {
10081108
end_of_pass_timer_query: Option<(vk::QueryPool, u32)>,
10091109

10101110
framebuffers: FastHashMap<FramebufferKey, vk::Framebuffer>,
1011-
temp_texture_views: FastHashMap<TempTextureViewKey, vk::ImageView>,
1111+
temp_texture_views: FastHashMap<TempTextureViewKey, IdentifiedTextureView>,
10121112

10131113
counters: Arc<wgt::HalCounters>,
10141114
}
@@ -1037,7 +1137,7 @@ impl Drop for CommandEncoder {
10371137
}
10381138

10391139
for (_, view) in self.temp_texture_views.drain() {
1040-
unsafe { self.device.raw.destroy_image_view(view, None) };
1140+
unsafe { self.device.raw.destroy_image_view(view.raw, None) };
10411141
}
10421142

10431143
self.counters.command_encoders.sub(1);

0 commit comments

Comments
 (0)