Skip to content

Commit

Permalink
Add VkPhysicalDevice aliasing support
Browse files Browse the repository at this point in the history
Vulkan captures unwrapped physical device handles, Layered API (like OpenXR)
captures wrapped handles.  During replay two HandleId's will reference the
same VkPhysical device.  The vulkan_alias is the handleId as known by the
vulkan_consumer, which will be created/updated, etc, by all Vulkan replay
calls.
  • Loading branch information
jzulauf-lunarg committed Oct 31, 2024
1 parent 267d30b commit fe0b46d
Show file tree
Hide file tree
Showing 4 changed files with 126 additions and 30 deletions.
10 changes: 10 additions & 0 deletions framework/decode/vulkan_object_info.h
Original file line number Diff line number Diff line change
Expand Up @@ -288,6 +288,16 @@ struct VulkanPhysicalDeviceInfo : public VulkanObjectInfo<VkPhysicalDevice>

// Closest matching replay device.
VulkanReplayDeviceInfo* replay_device_info{ nullptr };

// Because Vulkan captures unwrapped handles, and layered APIs (like OpenXR)
// capture wrapped handles, during replay two HandleId values will reference
// the same VkPhysical device. The vulkan_alias is the handleId as known by
// the vulkan_consumers, which will be created/updated, etc, by all Vulkan replay
// calls, s.t. the information known by the vulkan_consumer need not be duplicated.
// Operations on this, will use the vulkan_alias as the effective HandleId when set.

// When Non-null, the GetVkObject will recur on the alias Id
format::HandleId vulkan_alias{ format::kNullHandleId };
};

struct VulkanDeviceInfo : public VulkanObjectInfo<VkDevice>
Expand Down
99 changes: 69 additions & 30 deletions framework/decode/vulkan_object_info_table_base.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@

#include <cassert>
#include <functional>
#include <type_traits>
#include <unordered_map>

GFXRECON_BEGIN_NAMESPACE(gfxrecon)
Expand All @@ -49,6 +50,72 @@ struct has_handle_future<T, decltype((void)T::future, 0)>
template <typename T>
inline constexpr bool has_handle_future_v = has_handle_future<T>::value;

// NOTE: There's nothing VulkanSpecific in these utilities
// TODO: Find a better home for these

// Utility functors to implement const and non-const versions of getters in a common impl
template <typename Container>
using ConstCorrectMappedTypePtr = decltype(&(std::declval<Container>().begin()->second));

struct ObjectInfoGetterBase
{
template <typename Map, typename MappedTypePtr>
MappedTypePtr GetObjectInfoImpl(format::HandleId id, Map* map)
{
assert(map != nullptr);

MappedTypePtr object_info = nullptr;

if (id != 0)
{
const auto entry = map->find(id);

if (entry != map->end())
{
object_info = &entry->second;
}
}

return object_info;
}
template <typename Map, typename MappedTypePtr>
MappedTypePtr GetAliasingObjectInfoImpl(format::HandleId id, Map* map)
{
MappedTypePtr object_info = GetObjectInfoImpl<Map, MappedTypePtr>(id, map);
if (object_info && (object_info->vulkan_alias != format::kNullHandleId))
{
object_info = GetObjectInfoImpl<Map, MappedTypePtr>(object_info->vulkan_alias, map);
// Note: if id has an alias and the alias is valid, the alias must not alias. Aliasing is single level.
assert(!object_info || (object_info->vulkan_alias == format::kNullHandleId));
}
return object_info;
}
};

// Because of " explicit specialization in non-namespace scope" these must be implemented outside the class below
template <typename T>
struct ObjectInfoGetter : public ObjectInfoGetterBase
{
template <typename Map, typename MappedTypePtr = ConstCorrectMappedTypePtr<Map>>
MappedTypePtr operator()(format::HandleId id, Map* map)
{
return GetObjectInfoImpl<Map, MappedTypePtr>(id, map);
}
};

// Specialize to handle physical device aliasing. See comments for VulkanPhysicalDeviceInfo::vulkan_alias
// Note: could do SFINAE a "has member" check on vulkan_alias, but as only physical device needs aliasing support at
// this time, it's simpler just to specialize for VulkanPhysicalDeviceInfo
template <>
struct ObjectInfoGetter<VulkanPhysicalDeviceInfo> : public ObjectInfoGetterBase
{
template <typename Map, typename MappedTypePtr = ConstCorrectMappedTypePtr<Map>>
MappedTypePtr operator()(format::HandleId id, Map* map)
{
return GetAliasingObjectInfoImpl<Map, MappedTypePtr>(id, map);
}
};

class VulkanObjectInfoTableBase
{
protected:
Expand Down Expand Up @@ -132,41 +199,13 @@ class VulkanObjectInfoTableBase
template <typename T>
const T* GetVkObjectInfo(format::HandleId id, const std::unordered_map<format::HandleId, T>* map) const
{
assert(map != nullptr);

const T* object_info = nullptr;

if (id != 0)
{
const auto entry = map->find(id);

if (entry != map->end())
{
object_info = &entry->second;
}
}

return object_info;
return ObjectInfoGetter<T>()(id, map);
}

template <typename T>
T* GetVkObjectInfo(format::HandleId id, std::unordered_map<format::HandleId, T>* map)
{
assert(map != nullptr);

T* object_info = nullptr;

if (id != 0)
{
auto entry = map->find(id);

if (entry != map->end())
{
object_info = &entry->second;
}
}

return object_info;
return ObjectInfoGetter<T>()(id, map);
}
};

Expand Down
42 changes: 42 additions & 0 deletions framework/decode/vulkan_replay_consumer_base.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1270,6 +1270,41 @@ void VulkanReplayConsumerBase::CheckReplayDeviceInfo(VulkanPhysicalDeviceInfo* p
}
}

// Needed to support physical device aliasing. See comments for VulkanPhysicalDeviceInfo::vulkan_alias
void VulkanReplayConsumerBase::SetPhysicalDeviceAlias(format::HandleId instance,
VulkanPhysicalDeviceInfo& replay_physical_device)
{
if ((replay_physical_device.capture_id == format::kNullHandleId) ||
(replay_physical_device.handle == VK_NULL_HANDLE))
{
return;
}

const format::HandleId match_id = replay_physical_device.capture_id;
const VkPhysicalDevice match_handle = replay_physical_device.handle;

auto instance_info = object_info_table_->GetVkInstanceInfo(instance);
assert(instance_info);

for (const format::HandleId capture_device : instance_info->capture_devices)
{
const VulkanPhysicalDeviceInfo* physical_device_info =
GetObjectInfoTable().GetVkPhysicalDeviceInfo(capture_device);
if (!physical_device_info || (physical_device_info->vulkan_alias != format::kNullHandleId))
{
continue; // only single depth aliasing
}

const format::HandleId& capture_id = physical_device_info->capture_id;
const VkPhysicalDevice& handle = physical_device_info->handle;
if ((handle == match_handle) && (capture_id != match_id))
{
replay_physical_device.vulkan_alias = capture_id;
break;
}
}
}

void VulkanReplayConsumerBase::SetPhysicalDeviceInstanceInfo(VulkanInstanceInfo* instance_info,
VulkanPhysicalDeviceInfo* physical_device_info,
VkPhysicalDevice replay_device)
Expand Down Expand Up @@ -1572,6 +1607,13 @@ bool VulkanReplayConsumerBase::GetOverrideDeviceGroup(VulkanInstanceInfo*
return true;
}

void VulkanReplayConsumerBase::GetMatchingDevice(VulkanPhysicalDeviceInfo* physical_device_info)
{
VulkanInstanceInfo* instance_info = object_info_table_->GetVkInstanceInfo(physical_device_info->parent_id);
assert(instance_info);
GetMatchingDevice(instance_info, physical_device_info);
}

void VulkanReplayConsumerBase::GetMatchingDevice(VulkanInstanceInfo* instance_info,
VulkanPhysicalDeviceInfo* physical_device_info)
{
Expand Down
5 changes: 5 additions & 0 deletions framework/decode/vulkan_replay_consumer_base.h
Original file line number Diff line number Diff line change
Expand Up @@ -297,6 +297,11 @@ class VulkanReplayConsumerBase : public VulkanConsumer
return get_instance_proc_addr_;
}

void SetPhysicalDeviceAlias(format::HandleId instance, VulkanPhysicalDeviceInfo& replay_physical_device);

// Need the side effects from this when creating vulkan devices from OpenXr
void GetMatchingDevice(VulkanPhysicalDeviceInfo* physical_device_info);

protected:
const CommonObjectInfoTable& GetObjectInfoTable() const { return *object_info_table_; }

Expand Down

0 comments on commit fe0b46d

Please sign in to comment.