mirror of
https://github.com/baldurk/renderdoc.git
synced 2026-05-06 01:50:38 +00:00
Add remapping of physical devices on vulkan captures.
* This will solve the common case encountered when physical devices vary between capture and replay, where two devices swap over. E.g. [0]=AMD [1]=NV to [0]=NV [1]=AMD * This can also happen with discrete and embedded GPUs that swap order. * It will also provide a limited amount of portability by selecting a closer matching physical device if more than one is available.
This commit is contained in:
@@ -319,9 +319,17 @@ private:
|
||||
m_QueueFamilyIdx; // the family index that we've selected in CreateDevice for our queue
|
||||
VkQueue m_Queue; // the queue used for our own command buffer work
|
||||
|
||||
// the physical devices
|
||||
// the physical devices. At capture time this is trivial, just the enumerated devices.
|
||||
// At replay time this is re-ordered from the real list to try and match
|
||||
vector<VkPhysicalDevice> m_PhysicalDevices;
|
||||
|
||||
// replay only, information we need for remapping. The original vector keeps information about the
|
||||
// physical devices used at capture time, and the replay vector contains the real unmodified list
|
||||
// of physical devices at replay time.
|
||||
vector<PhysicalDeviceData> m_OriginalPhysicalDevices;
|
||||
vector<VkPhysicalDevice> m_ReplayPhysicalDevices;
|
||||
vector<bool> m_ReplayPhysicalDevicesUsed;
|
||||
|
||||
// the single queue family supported for each physical device
|
||||
vector<pair<uint32_t, VkQueueFamilyProperties> > m_SupportedQueueFamilies;
|
||||
|
||||
|
||||
@@ -254,6 +254,23 @@ ReplayCreateStatus WrappedVulkan::Initialise(VkInitParams ¶ms)
|
||||
->CreateDebugReportCallbackEXT(Unwrap(m_Instance), &debugInfo, NULL, &m_DbgMsgCallback);
|
||||
}
|
||||
|
||||
uint32_t count = 0;
|
||||
|
||||
VkResult vkr = ObjDisp(m_Instance)->EnumeratePhysicalDevices(Unwrap(m_Instance), &count, NULL);
|
||||
RDCASSERTEQUAL(vkr, VK_SUCCESS);
|
||||
|
||||
m_ReplayPhysicalDevices.resize(count);
|
||||
m_ReplayPhysicalDevicesUsed.resize(count);
|
||||
m_OriginalPhysicalDevices.resize(count);
|
||||
m_MemIdxMaps.resize(count);
|
||||
|
||||
vkr = ObjDisp(m_Instance)
|
||||
->EnumeratePhysicalDevices(Unwrap(m_Instance), &count, &m_ReplayPhysicalDevices[0]);
|
||||
RDCASSERTEQUAL(vkr, VK_SUCCESS);
|
||||
|
||||
for(uint32_t i = 0; i < count; i++)
|
||||
GetResourceManager()->WrapResource(m_Instance, m_ReplayPhysicalDevices[i]);
|
||||
|
||||
return eReplayCreate_Success;
|
||||
}
|
||||
|
||||
@@ -421,6 +438,11 @@ void WrappedVulkan::Shutdown()
|
||||
}
|
||||
m_CleanupMems.clear();
|
||||
|
||||
// destroy the physical devices manually because due to remapping the may have leftover
|
||||
// refcounts
|
||||
for(size_t i = 0; i < m_ReplayPhysicalDevices.size(); i++)
|
||||
GetResourceManager()->ReleaseWrappedResource(m_ReplayPhysicalDevices[i]);
|
||||
|
||||
// destroy debug manager and any objects it created
|
||||
SAFE_DELETE(m_DebugManager);
|
||||
|
||||
@@ -445,6 +467,7 @@ void WrappedVulkan::Shutdown()
|
||||
m_Device = VK_NULL_HANDLE;
|
||||
m_Instance = VK_NULL_HANDLE;
|
||||
|
||||
m_ReplayPhysicalDevices.clear();
|
||||
m_PhysicalDevices.clear();
|
||||
|
||||
for(size_t i = 0; i < m_QueueFamilies.size(); i++)
|
||||
@@ -530,74 +553,115 @@ bool WrappedVulkan::Serialise_vkEnumeratePhysicalDevices(Serialiser *localSerial
|
||||
}
|
||||
else
|
||||
{
|
||||
uint32_t count;
|
||||
VkPhysicalDevice *devices;
|
||||
|
||||
instance = GetResourceManager()->GetLiveHandle<VkInstance>(inst);
|
||||
VkResult vkr = ObjDisp(instance)->EnumeratePhysicalDevices(Unwrap(instance), &count, NULL);
|
||||
RDCASSERTEQUAL(vkr, VK_SUCCESS);
|
||||
|
||||
if(count <= physIndex)
|
||||
{
|
||||
RDCERR(
|
||||
"Capture had more physical devices than available on replay! This will lead to a crash "
|
||||
"if they are used.");
|
||||
return true;
|
||||
VkDriverInfo capturedVersion(physProps);
|
||||
|
||||
RDCLOG("Captured log describes physical device %u:", physIndex);
|
||||
RDCLOG(" - %s (ver %u.%u patch 0x%x) - %04x:%04x", physProps.deviceName,
|
||||
capturedVersion.Major(), capturedVersion.Minor(), capturedVersion.Patch(),
|
||||
physProps.vendorID, physProps.deviceID);
|
||||
|
||||
m_OriginalPhysicalDevices[physIndex].props = physProps;
|
||||
m_OriginalPhysicalDevices[physIndex].memProps = memProps;
|
||||
m_OriginalPhysicalDevices[physIndex].features = physFeatures;
|
||||
}
|
||||
|
||||
devices = new VkPhysicalDevice[count];
|
||||
// match up physical devices to those available on replay as best as possible. In general
|
||||
// hopefully the most common case is when there's a precise match, and maybe the order changed.
|
||||
//
|
||||
// If more GPUs were present on replay than during capture, we map many-to-one which might have
|
||||
// bad side-effects as e.g. we have to pick one memidxmap, but this is as good as we can do.
|
||||
|
||||
if(physIndex >= m_PhysicalDevices.size())
|
||||
uint32_t bestIdx = 0;
|
||||
VkPhysicalDeviceProperties bestPhysProps;
|
||||
VkPhysicalDeviceMemoryProperties bestMemProps;
|
||||
|
||||
pd = m_ReplayPhysicalDevices[bestIdx];
|
||||
|
||||
ObjDisp(pd)->GetPhysicalDeviceProperties(Unwrap(pd), &bestPhysProps);
|
||||
ObjDisp(pd)->GetPhysicalDeviceMemoryProperties(Unwrap(pd), &bestMemProps);
|
||||
|
||||
for(uint32_t i = 1; i < (uint32_t)m_ReplayPhysicalDevices.size(); i++)
|
||||
{
|
||||
m_PhysicalDevices.resize(physIndex + 1);
|
||||
m_MemIdxMaps.resize(physIndex + 1);
|
||||
}
|
||||
VkPhysicalDeviceProperties compPhysProps;
|
||||
VkPhysicalDeviceMemoryProperties compMemProps;
|
||||
|
||||
vkr = ObjDisp(instance)->EnumeratePhysicalDevices(Unwrap(instance), &count, devices);
|
||||
RDCASSERTEQUAL(vkr, VK_SUCCESS);
|
||||
pd = m_ReplayPhysicalDevices[i];
|
||||
|
||||
// PORTABILITY match up physical devices to those available on replay
|
||||
// find the best possible match for this physical device
|
||||
ObjDisp(pd)->GetPhysicalDeviceProperties(Unwrap(pd), &compPhysProps);
|
||||
ObjDisp(pd)->GetPhysicalDeviceMemoryProperties(Unwrap(pd), &compMemProps);
|
||||
|
||||
pd = devices[physIndex];
|
||||
|
||||
for(size_t i = 0; i < m_PhysicalDevices.size(); i++)
|
||||
{
|
||||
// physical devices might be re-created inside EnumeratePhysicalDevices every time, so
|
||||
// we need to re-wrap any previously enumerated physical devices
|
||||
if(m_PhysicalDevices[i] != VK_NULL_HANDLE)
|
||||
// an exact vendorID match is a better match than not
|
||||
if(compPhysProps.vendorID == physProps.vendorID && bestPhysProps.vendorID != physProps.vendorID)
|
||||
{
|
||||
RDCASSERTNOTEQUAL(i, physIndex);
|
||||
GetWrapped(m_PhysicalDevices[i])->RewrapObject(devices[i]);
|
||||
bestIdx = i;
|
||||
bestPhysProps = compPhysProps;
|
||||
bestMemProps = compMemProps;
|
||||
continue;
|
||||
}
|
||||
else if(compPhysProps.vendorID != physProps.vendorID)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// ditto deviceID
|
||||
if(compPhysProps.deviceID == physProps.deviceID && bestPhysProps.deviceID != physProps.deviceID)
|
||||
{
|
||||
bestIdx = i;
|
||||
bestPhysProps = compPhysProps;
|
||||
bestMemProps = compMemProps;
|
||||
continue;
|
||||
}
|
||||
else if(compPhysProps.deviceID != physProps.deviceID)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// if we have multiple identical devices, which isn't uncommon, favour the one
|
||||
// that hasn't been assigned
|
||||
if(m_ReplayPhysicalDevicesUsed[bestIdx] && !m_ReplayPhysicalDevicesUsed[i])
|
||||
{
|
||||
bestIdx = i;
|
||||
bestPhysProps = compPhysProps;
|
||||
bestMemProps = compMemProps;
|
||||
continue;
|
||||
}
|
||||
|
||||
// this device isn't any better, ignore it
|
||||
}
|
||||
|
||||
SAFE_DELETE_ARRAY(devices);
|
||||
{
|
||||
VkDriverInfo runningVersion(bestPhysProps);
|
||||
|
||||
RDCLOG("Mapping during replay to physical device %u:", bestIdx);
|
||||
RDCLOG(" - %s (ver %u.%u patch 0x%x) - %04x:%04x", bestPhysProps.deviceName,
|
||||
runningVersion.Major(), runningVersion.Minor(), runningVersion.Patch(),
|
||||
bestPhysProps.vendorID, bestPhysProps.deviceID);
|
||||
}
|
||||
|
||||
pd = m_ReplayPhysicalDevices[bestIdx];
|
||||
|
||||
GetResourceManager()->WrapResource(instance, pd);
|
||||
GetResourceManager()->AddLiveResource(physId, pd);
|
||||
|
||||
if(physIndex >= m_PhysicalDevices.size())
|
||||
m_PhysicalDevices.resize(physIndex + 1);
|
||||
m_PhysicalDevices[physIndex] = pd;
|
||||
|
||||
uint32_t *storedMap = new uint32_t[32];
|
||||
memcpy(storedMap, memIdxMap, sizeof(memIdxMap));
|
||||
m_MemIdxMaps[physIndex] = storedMap;
|
||||
|
||||
VkDriverInfo capturedVersion(physProps);
|
||||
|
||||
RDCLOG("Captured log describes physical device %u:", physIndex);
|
||||
RDCLOG(" - %s (ver %u.%u patch 0x%x) - %04x:%04x", physProps.deviceName,
|
||||
capturedVersion.Major(), capturedVersion.Minor(), capturedVersion.Patch(),
|
||||
physProps.vendorID, physProps.deviceID);
|
||||
|
||||
ObjDisp(pd)->GetPhysicalDeviceProperties(Unwrap(pd), &physProps);
|
||||
ObjDisp(pd)->GetPhysicalDeviceMemoryProperties(Unwrap(pd), &memProps);
|
||||
ObjDisp(pd)->GetPhysicalDeviceFeatures(Unwrap(pd), &physFeatures);
|
||||
|
||||
VkDriverInfo runningVersion(physProps);
|
||||
|
||||
RDCLOG("Replaying on physical device %u:", physIndex);
|
||||
RDCLOG(" - %s (ver %u.%u patch 0x%x) - %04x:%04x", physProps.deviceName, runningVersion.Major(),
|
||||
runningVersion.Minor(), runningVersion.Patch(), physProps.vendorID, physProps.deviceID);
|
||||
if(m_ReplayPhysicalDevicesUsed[bestIdx])
|
||||
{
|
||||
// error if we're remapping multiple physical devices to the same best match
|
||||
RDCERR(
|
||||
"Mappnig multiple capture-time physical devices to a single replay-time physical device."
|
||||
"This means the HW has changed between capture and replay and may cause bugs.");
|
||||
}
|
||||
else
|
||||
{
|
||||
// the first physical device 'wins' for the memory index map
|
||||
uint32_t *storedMap = new uint32_t[32];
|
||||
memcpy(storedMap, memIdxMap, sizeof(memIdxMap));
|
||||
m_MemIdxMaps[physIndex] = storedMap;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
Reference in New Issue
Block a user