diff --git a/qrenderdoc/Code/pyrenderdoc/renderdoc.i b/qrenderdoc/Code/pyrenderdoc/renderdoc.i index 330be7c1b..f4ebd161c 100644 --- a/qrenderdoc/Code/pyrenderdoc/renderdoc.i +++ b/qrenderdoc/Code/pyrenderdoc/renderdoc.i @@ -314,6 +314,8 @@ TEMPLATE_ARRAY_INSTANTIATE(rdcarray, VertexInputAttribute) TEMPLATE_ARRAY_INSTANTIATE(rdcarray, BoundResource) TEMPLATE_ARRAY_INSTANTIATE(rdcarray, BoundResourceArray) TEMPLATE_ARRAY_INSTANTIATE(rdcarray, FloatVector) +TEMPLATE_ARRAY_INSTANTIATE(rdcarray, GraphicsAPI) +TEMPLATE_ARRAY_INSTANTIATE(rdcarray, GPUDevice) TEMPLATE_NAMESPACE_ARRAY_INSTANTIATE(rdcarray, VKPipe, Attachment) TEMPLATE_NAMESPACE_ARRAY_INSTANTIATE(rdcarray, VKPipe, BindingElement) TEMPLATE_NAMESPACE_ARRAY_INSTANTIATE(rdcarray, VKPipe, DescriptorBinding) diff --git a/renderdoc/api/replay/control_types.h b/renderdoc/api/replay/control_types.h index 55066e124..443b1f4a1 100644 --- a/renderdoc/api/replay/control_types.h +++ b/renderdoc/api/replay/control_types.h @@ -660,3 +660,41 @@ structured data. }; DECLARE_REFLECTION_STRUCT(CaptureFileFormat); + +DOCUMENT("Describes a single GPU at replay time."); +struct GPUDevice +{ + DOCUMENT(""); + GPUDevice() = default; + GPUDevice(const GPUDevice &) = default; + + bool operator==(const GPUDevice &o) const + { + // deliberately don't compare name or APIs - only this triple counts for equality + return vendor == o.vendor && deviceID == o.deviceID && driver == o.driver; + } + bool operator<(const GPUDevice &o) const + { + if(!(vendor == o.vendor)) + return vendor < o.vendor; + if(!(deviceID == o.deviceID)) + return deviceID < o.deviceID; + if(!(driver == o.driver)) + return driver < o.driver; + return false; + } + DOCUMENT("The :class:`GPUVendor` of this GPU."); + GPUVendor vendor = GPUVendor::Unknown; + DOCUMENT("The PCI deviceID of this GPU."); + uint32_t deviceID = 0; + DOCUMENT("The name of the driver of this GPU, if multiple drivers are available for it."); + rdcstr driver; + + DOCUMENT("The human-readable name of this GPU."); + rdcstr name; + + DOCUMENT("The list of APIs that this device supports."); + rdcarray apis; +}; + +DECLARE_REFLECTION_STRUCT(GPUDevice); diff --git a/renderdoc/api/replay/renderdoc_replay.h b/renderdoc/api/replay/renderdoc_replay.h index de11ee994..7d59b5b86 100644 --- a/renderdoc/api/replay/renderdoc_replay.h +++ b/renderdoc/api/replay/renderdoc_replay.h @@ -1451,6 +1451,14 @@ and construction of files. )"); struct ICaptureAccess { + DOCUMENT(R"(Returns the list of available GPUs, that can be used in combination with +:class:`ReplayOptions` to force replay on a particular GPU. + +:return: The list of GPUs available. +:rtype: ``list`` of :class:`GPUDevice` +)"); + virtual rdcarray GetAvailableGPUs() = 0; + DOCUMENT(R"(Retrieve the total number of available sections. :return: The number of sections in the capture diff --git a/renderdoc/core/core.cpp b/renderdoc/core/core.cpp index d0d83a6bd..c7d3f3899 100644 --- a/renderdoc/core/core.cpp +++ b/renderdoc/core/core.cpp @@ -1131,6 +1131,118 @@ std::vector RenderDoc::GetCaptureFileFormats() return ret; } +rdcarray RenderDoc::GetAvailableGPUs() +{ + if(m_AvailableGPUs.empty()) + { + for(GraphicsAPI api : {GraphicsAPI::D3D11, GraphicsAPI::D3D12, GraphicsAPI::Vulkan}) + { + RDCDriver driverType = RDCDriver::Unknown; + + switch(api) + { + case GraphicsAPI::D3D11: driverType = RDCDriver::D3D11; break; + case GraphicsAPI::D3D12: driverType = RDCDriver::D3D12; break; + case GraphicsAPI::OpenGL: break; + case GraphicsAPI::Vulkan: driverType = RDCDriver::Vulkan; break; + } + + if(driverType == RDCDriver::Unknown || !HasReplayDriver(driverType)) + continue; + + IReplayDriver *driver = NULL; + ReplayStatus status = CreateProxyReplayDriver(driverType, &driver); + + if(status == ReplayStatus::Succeeded) + { + rdcarray gpus = driver->GetAvailableGPUs(); + + for(const GPUDevice &newgpu : gpus) + { + bool addnew = true; + + for(GPUDevice &oldgpu : m_AvailableGPUs) + { + // if we have this GPU listed already, just add its API to the previous list + if(oldgpu == newgpu) + { + oldgpu.apis.push_back(api); + addnew = false; + } + } + + if(addnew) + m_AvailableGPUs.push_back(newgpu); + } + } + else + { + RDCERR("Couldn't create proxy replay driver for %s: %s", ToStr(driverType).c_str(), + ToStr(status).c_str()); + } + + if(driver) + driver->Shutdown(); + } + + // we now have a list of GPUs, however we might have some duplicates if some APIs have + // multiple drivers for a single device. To compact this list, for each GPU with no driver + // we find all matching multi-drive GPUs and merge it into all matching copies. + bool hasDriverNames = false; + for(size_t i = 0; i < m_AvailableGPUs.size(); i++) + hasDriverNames |= !m_AvailableGPUs[i].driver.empty(); + + if(hasDriverNames) + { + for(size_t i = 0; i < m_AvailableGPUs.size();) + { + bool applied = false; + + if(!m_AvailableGPUs[i].driver.empty()) + { + i++; + continue; + } + + // scan all subsequent GPUs, if we find a duplicate, merge the APIs + for(size_t j = i + 1; j < m_AvailableGPUs.size(); j++) + { + if(m_AvailableGPUs[i].vendor == m_AvailableGPUs[j].vendor && + m_AvailableGPUs[i].deviceID == m_AvailableGPUs[j].deviceID) + { + RDCASSERT(!m_AvailableGPUs[j].driver.empty()); + for(GraphicsAPI a : m_AvailableGPUs[i].apis) + { + if(m_AvailableGPUs[j].apis.indexOf(a) == -1) + m_AvailableGPUs[j].apis.push_back(a); + } + applied = true; + } + } + + // we "applied" this GPU to all its driver-based duplicates, so we can remove it now + if(applied) + { + m_AvailableGPUs.erase(i); + } + else + { + i++; + } + } + } + + // sort the APIs list in each GPU, and sort the GPUs + std::sort(m_AvailableGPUs.begin(), m_AvailableGPUs.end()); + for(GPUDevice &dev : m_AvailableGPUs) + { + std::sort(dev.apis.begin(), dev.apis.end()); + } + } + + return m_AvailableGPUs; +} + bool RenderDoc::HasReplaySupport(RDCDriver driverType) { if(driverType == RDCDriver::Image) diff --git a/renderdoc/core/core.h b/renderdoc/core/core.h index 8249a037e..833bfef20 100644 --- a/renderdoc/core/core.h +++ b/renderdoc/core/core.h @@ -496,6 +496,7 @@ public: IDeviceProtocolHandler *GetDeviceProtocol(const rdcstr &protocol); std::vector GetCaptureFileFormats(); + rdcarray GetAvailableGPUs(); void SetVulkanLayerCheck(VulkanLayerCheck callback) { m_VulkanCheck = callback; } void SetVulkanLayerInstall(VulkanLayerInstall callback) { m_VulkanInstall = callback; } @@ -635,6 +636,8 @@ private: Threading::CriticalSection m_DriverLock; std::map m_ActiveDrivers; + rdcarray m_AvailableGPUs; + std::map m_ProgressCallbacks; Threading::CriticalSection m_CaptureLock; diff --git a/renderdoc/core/image_viewer.cpp b/renderdoc/core/image_viewer.cpp index e42d603d0..033cf50ae 100644 --- a/renderdoc/core/image_viewer.cpp +++ b/renderdoc/core/image_viewer.cpp @@ -196,6 +196,7 @@ public: DriverInformation ret = {}; return ret; } + rdcarray GetAvailableGPUs() { return {}; } const D3D12Pipe::State *GetD3D12PipelineState() { return NULL; } const GLPipe::State *GetGLPipelineState() { return NULL; } const VKPipe::State *GetVulkanPipelineState() { return NULL; } diff --git a/renderdoc/core/remote_server.cpp b/renderdoc/core/remote_server.cpp index 22ddd5ba6..973c5879c 100644 --- a/renderdoc/core/remote_server.cpp +++ b/renderdoc/core/remote_server.cpp @@ -71,6 +71,7 @@ enum RemoteServerPacket eRemoteServer_GetSectionProperties, eRemoteServer_GetSectionContents, eRemoteServer_WriteSection, + eRemoteServer_GetAvailableGPUs, eRemoteServer_RemoteServerCount, }; @@ -367,6 +368,18 @@ static void ActiveRemoteClientThread(ClientThread *threadData, tempFiles.push_back(path); } + else if(type == eRemoteServer_GetAvailableGPUs) + { + reader.EndChunk(); + + rdcarray gpus = RenderDoc::Inst().GetAvailableGPUs(); + + { + WRITE_DATA_SCOPE(); + SCOPED_SERIALISE_CHUNK(eRemoteServer_GetAvailableGPUs); + SERIALISE_ELEMENT(gpus); + } + } else if(type == eRemoteServer_ShutdownServer) { reader.EndChunk(); @@ -1568,6 +1581,37 @@ rdcstr RemoteServer::DriverName() return driverName; } +rdcarray RemoteServer::GetAvailableGPUs() +{ + if(!Connected()) + return {}; + + { + WRITE_DATA_SCOPE(); + SCOPED_SERIALISE_CHUNK(eRemoteServer_GetAvailableGPUs); + } + + rdcarray gpus; + + { + READ_DATA_SCOPE(); + RemoteServerPacket type = ser.ReadChunk(); + + if(type == eRemoteServer_GetAvailableGPUs) + { + SERIALISE_ELEMENT(gpus); + } + else + { + RDCERR("Unexpected response to GetAvailableGPUs"); + } + + ser.EndChunk(); + } + + return gpus; +} + int RemoteServer::GetSectionCount() { if(!Connected()) diff --git a/renderdoc/core/remote_server.h b/renderdoc/core/remote_server.h index 3f5192f5d..42e9a679b 100644 --- a/renderdoc/core/remote_server.h +++ b/renderdoc/core/remote_server.h @@ -77,6 +77,8 @@ public: virtual rdcstr DriverName(); + virtual rdcarray GetAvailableGPUs(); + virtual int GetSectionCount(); virtual int FindSectionByName(const char *name); diff --git a/renderdoc/core/replay_proxy.cpp b/renderdoc/core/replay_proxy.cpp index 58092873e..7fbe9258f 100644 --- a/renderdoc/core/replay_proxy.cpp +++ b/renderdoc/core/replay_proxy.cpp @@ -324,6 +324,35 @@ DriverInformation ReplayProxy::GetDriverInfo() PROXY_FUNCTION(GetDriverInfo); } +template +rdcarray ReplayProxy::Proxied_GetAvailableGPUs(ParamSerialiser ¶mser, + ReturnSerialiser &retser) +{ + const ReplayProxyPacket expectedPacket = eReplayProxy_GetAvailableGPUs; + ReplayProxyPacket packet = eReplayProxy_GetAvailableGPUs; + rdcarray ret = {}; + + { + BEGIN_PARAMS(); + END_PARAMS(); + } + + { + REMOTE_EXECUTION(); + if(paramser.IsReading() && !paramser.IsErrored() && !m_IsErrored) + ret = m_Remote->GetAvailableGPUs(); + } + + SERIALISE_RETURN(ret); + + return ret; +} + +rdcarray ReplayProxy::GetAvailableGPUs() +{ + PROXY_FUNCTION(GetAvailableGPUs); +} + template std::vector ReplayProxy::Proxied_GetDebugMessages(ParamSerialiser ¶mser, ReturnSerialiser &retser) @@ -2663,6 +2692,7 @@ bool ReplayProxy::Tick(int type) case eReplayProxy_GetDisassemblyTargets: GetDisassemblyTargets(); break; case eReplayProxy_GetTargetShaderEncodings: GetTargetShaderEncodings(); break; case eReplayProxy_GetDriverInfo: GetDriverInfo(); break; + case eReplayProxy_GetAvailableGPUs: GetAvailableGPUs(); break; default: RDCERR("Unexpected command %u", type); return false; } diff --git a/renderdoc/core/replay_proxy.h b/renderdoc/core/replay_proxy.h index 1827bf711..27bcad655 100644 --- a/renderdoc/core/replay_proxy.h +++ b/renderdoc/core/replay_proxy.h @@ -99,6 +99,7 @@ enum ReplayProxyPacket eReplayProxy_GetTargetShaderEncodings, eReplayProxy_GetDriverInfo, + eReplayProxy_GetAvailableGPUs, }; DECLARE_REFLECTION_ENUM(ReplayProxyPacket); @@ -470,6 +471,7 @@ public: IMPLEMENT_FUNCTION_PROXIED(APIProperties, GetAPIProperties); IMPLEMENT_FUNCTION_PROXIED(DriverInformation, GetDriverInfo); + IMPLEMENT_FUNCTION_PROXIED(rdcarray, GetAvailableGPUs); IMPLEMENT_FUNCTION_PROXIED(std::vector, GetDebugMessages); diff --git a/renderdoc/driver/d3d11/d3d11_replay.cpp b/renderdoc/driver/d3d11/d3d11_replay.cpp index 07de091db..631fc2a06 100644 --- a/renderdoc/driver/d3d11/d3d11_replay.cpp +++ b/renderdoc/driver/d3d11/d3d11_replay.cpp @@ -515,6 +515,50 @@ std::vector D3D11Replay::GetDebugMessages() return m_pDevice->GetDebugMessages(); } +rdcarray D3D11Replay::GetAvailableGPUs() +{ + rdcarray ret; + + for(UINT i = 0; i < 10; i++) + { + IDXGIAdapter *adapter = NULL; + + HRESULT hr = m_pFactory->EnumAdapters(i, &adapter); + + if(SUCCEEDED(hr) && adapter) + { + DXGI_ADAPTER_DESC desc; + adapter->GetDesc(&desc); + + GPUDevice dev; + dev.vendor = GPUVendorFromPCIVendor(desc.VendorId); + dev.deviceID = desc.DeviceId; + dev.driver = ""; // D3D doesn't have multiple drivers per API + dev.name = StringFormat::Wide2UTF8(desc.Description); + dev.apis = {GraphicsAPI::D3D11}; + + // don't add duplicate devices even if they get enumerated. Don't add WARP, we'll do that + // manually since it's inconsistently enumerated + if(ret.indexOf(dev) == -1 && dev.vendor != GPUVendor::Software) + ret.push_back(dev); + } + + SAFE_RELEASE(adapter); + } + + { + GPUDevice dev; + dev.vendor = GPUVendor::Software; + dev.deviceID = 0; + dev.driver = ""; // D3D doesn't have multiple drivers per API + dev.name = "WARP Rasterizer"; + dev.apis = {GraphicsAPI::D3D11}; + ret.push_back(dev); + } + + return ret; +} + APIProperties D3D11Replay::GetAPIProperties() { APIProperties ret = m_pDevice->APIProps; diff --git a/renderdoc/driver/d3d11/d3d11_replay.h b/renderdoc/driver/d3d11/d3d11_replay.h index 1a26bd3bc..0b02a4475 100644 --- a/renderdoc/driver/d3d11/d3d11_replay.h +++ b/renderdoc/driver/d3d11/d3d11_replay.h @@ -105,6 +105,7 @@ public: void DestroyResources(); DriverInformation GetDriverInfo() { return m_DriverInfo; } + rdcarray GetAvailableGPUs(); APIProperties GetAPIProperties(); ResourceDescription &GetResourceDesc(ResourceId id); diff --git a/renderdoc/driver/d3d12/d3d12_replay.cpp b/renderdoc/driver/d3d12/d3d12_replay.cpp index 245420b7f..cc7f62348 100644 --- a/renderdoc/driver/d3d12/d3d12_replay.cpp +++ b/renderdoc/driver/d3d12/d3d12_replay.cpp @@ -214,6 +214,52 @@ ReplayStatus D3D12Replay::ReadLogInitialisation(RDCFile *rdc, bool storeStructur return m_pDevice->ReadLogInitialisation(rdc, storeStructuredBuffers); } +rdcarray D3D12Replay::GetAvailableGPUs() +{ + rdcarray ret; + + for(UINT i = 0; i < 10; i++) + { + IDXGIAdapter *adapter = NULL; + + HRESULT hr = m_pFactory->EnumAdapters(i, &adapter); + + if(SUCCEEDED(hr) && adapter) + { + DXGI_ADAPTER_DESC desc; + adapter->GetDesc(&desc); + + GPUDevice dev; + dev.vendor = GPUVendorFromPCIVendor(desc.VendorId); + dev.deviceID = desc.DeviceId; + dev.driver = ""; // D3D doesn't have multiple drivers per API + dev.name = StringFormat::Wide2UTF8(desc.Description); + dev.apis = {GraphicsAPI::D3D12}; + + // don't add duplicate devices even if they get enumerated. Don't add WARP, we'll do that + // manually since it's inconsistently enumerated + if(ret.indexOf(dev) == -1 && dev.vendor != GPUVendor::Software) + ret.push_back(dev); + } + + SAFE_RELEASE(adapter); + } + + // add WARP as long as we're not 12On7 (where we can't use WARP) + if(!m_D3D12On7) + { + GPUDevice dev; + dev.vendor = GPUVendor::Software; + dev.deviceID = 0; + dev.driver = ""; // D3D doesn't have multiple drivers per API + dev.name = "WARP Rasterizer"; + dev.apis = {GraphicsAPI::D3D12}; + ret.push_back(dev); + } + + return ret; +} + APIProperties D3D12Replay::GetAPIProperties() { APIProperties ret = m_pDevice->APIProps; diff --git a/renderdoc/driver/d3d12/d3d12_replay.h b/renderdoc/driver/d3d12/d3d12_replay.h index 463b55a4a..63386b935 100644 --- a/renderdoc/driver/d3d12/d3d12_replay.h +++ b/renderdoc/driver/d3d12/d3d12_replay.h @@ -65,6 +65,7 @@ public: void CreateResources(); void DestroyResources(); DriverInformation GetDriverInfo() { return m_DriverInfo; } + rdcarray GetAvailableGPUs(); APIProperties GetAPIProperties(); ResourceDescription &GetResourceDesc(ResourceId id); diff --git a/renderdoc/driver/gl/gl_replay.cpp b/renderdoc/driver/gl/gl_replay.cpp index f5a1e7fca..3235c3ee7 100644 --- a/renderdoc/driver/gl/gl_replay.cpp +++ b/renderdoc/driver/gl/gl_replay.cpp @@ -167,6 +167,12 @@ ResourceId GLReplay::GetLiveID(ResourceId id) return m_pDriver->GetResourceManager()->GetLiveID(id); } +rdcarray GLReplay::GetAvailableGPUs() +{ + // GL doesn't support multiple GPUs, return an empty list + return {}; +} + APIProperties GLReplay::GetAPIProperties() { APIProperties ret = m_pDriver->APIProps; diff --git a/renderdoc/driver/gl/gl_replay.h b/renderdoc/driver/gl/gl_replay.h index fa7ac72d8..bfbdfe651 100644 --- a/renderdoc/driver/gl/gl_replay.h +++ b/renderdoc/driver/gl/gl_replay.h @@ -91,6 +91,7 @@ public: void SetDriver(WrappedOpenGL *d) { m_pDriver = d; } DriverInformation GetDriverInfo() { return m_DriverInfo; } + rdcarray GetAvailableGPUs(); APIProperties GetAPIProperties(); ResourceDescription &GetResourceDesc(ResourceId id); diff --git a/renderdoc/driver/vulkan/vk_replay.cpp b/renderdoc/driver/vulkan/vk_replay.cpp index 6b46020de..68f413c77 100644 --- a/renderdoc/driver/vulkan/vk_replay.cpp +++ b/renderdoc/driver/vulkan/vk_replay.cpp @@ -80,6 +80,108 @@ void VulkanReplay::Shutdown() delete m_pDriver; } +rdcarray VulkanReplay::GetAvailableGPUs() +{ + rdcarray ret; + + // do a manual enumerate to avoid any possible remapping + VkInstance instance = m_pDriver->GetInstance(); + + uint32_t count = 0; + VkResult vkr = ObjDisp(instance)->EnumeratePhysicalDevices(Unwrap(instance), &count, NULL); + + if(vkr != VK_SUCCESS) + return ret; + + VkPhysicalDevice *devices = new VkPhysicalDevice[count]; + + vkr = ObjDisp(instance)->EnumeratePhysicalDevices(Unwrap(instance), &count, devices); + RDCASSERTEQUAL(vkr, VK_SUCCESS); + + for(uint32_t p = 0; p < count; p++) + { + VkPhysicalDeviceProperties props = {}; + ObjDisp(instance)->GetPhysicalDeviceProperties(devices[p], &props); + + VkPhysicalDeviceDriverPropertiesKHR driverProps = { + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DRIVER_PROPERTIES_KHR, + }; + + VkPhysicalDeviceProperties2 physProps2 = { + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2, &driverProps, + }; + + // get driver properties if available + if(m_pDriver->GetExtensions(GetRecord(instance)).ext_KHR_get_physical_device_properties2) + { + uint32_t extCount = 0; + ObjDisp(instance)->EnumerateDeviceExtensionProperties(devices[p], NULL, &extCount, NULL); + + VkExtensionProperties *extProps = new VkExtensionProperties[extCount]; + ObjDisp(instance)->EnumerateDeviceExtensionProperties(devices[p], NULL, &extCount, extProps); + + for(uint32_t e = 0; e < extCount; e++) + { + if(!strcmp(extProps[e].extensionName, VK_KHR_DRIVER_PROPERTIES_EXTENSION_NAME)) + { + ObjDisp(instance)->GetPhysicalDeviceProperties2(devices[p], &physProps2); + break; + } + } + + SAFE_DELETE_ARRAY(extProps); + } + + GPUDevice dev; + dev.vendor = GPUVendorFromPCIVendor(props.vendorID); + dev.deviceID = props.deviceID; + dev.name = props.deviceName; + dev.apis = {GraphicsAPI::Vulkan}; + + // only set the driver name when it's useful to disambiguate + switch(driverProps.driverID) + { + default: dev.driver = ""; + case VK_DRIVER_ID_AMD_PROPRIETARY_KHR: dev.driver = "AMD Propriertary"; break; + case VK_DRIVER_ID_AMD_OPEN_SOURCE_KHR: dev.driver = "AMD Open-source"; break; + case VK_DRIVER_ID_MESA_RADV_KHR: dev.driver = "AMD RADV"; break; + case VK_DRIVER_ID_INTEL_PROPRIETARY_WINDOWS_KHR: dev.driver = "Intel Propriertary"; break; + case VK_DRIVER_ID_INTEL_OPEN_SOURCE_MESA_KHR: dev.driver = "Intel Open-source"; break; + } + + // don't add duplicate devices even if they get enumerated. + if(ret.indexOf(dev) == -1) + ret.push_back(dev); + } + + // loop over devices and remove the driver string unless it's needed to disambiguate from another + // identical device. + for(size_t i = 0; i < ret.size(); i++) + { + bool needDriver = false; + + for(size_t j = 0; j < ret.size(); j++) + { + if(i == j) + continue; + + if(ret[i].vendor == ret[j].vendor && ret[i].deviceID == ret[j].deviceID) + { + RDCASSERT(ret[i].driver != ret[j].driver); + needDriver = true; + break; + } + } + + if(!needDriver) + ret[i].driver = rdcstr(); + } + + SAFE_DELETE_ARRAY(devices); + + return ret; +} + APIProperties VulkanReplay::GetAPIProperties() { APIProperties ret = m_pDriver->APIProps; diff --git a/renderdoc/driver/vulkan/vk_replay.h b/renderdoc/driver/vulkan/vk_replay.h index 32e71d6c0..282a0f4ab 100644 --- a/renderdoc/driver/vulkan/vk_replay.h +++ b/renderdoc/driver/vulkan/vk_replay.h @@ -231,6 +231,7 @@ public: void SetDriver(WrappedVulkan *d) { m_pDriver = d; } DriverInformation GetDriverInfo() { return m_DriverInfo; } + rdcarray GetAvailableGPUs(); APIProperties GetAPIProperties(); ResourceDescription &GetResourceDesc(ResourceId id); diff --git a/renderdoc/replay/capture_file.cpp b/renderdoc/replay/capture_file.cpp index eaaa067ae..7ae14639d 100644 --- a/renderdoc/replay/capture_file.cpp +++ b/renderdoc/replay/capture_file.cpp @@ -135,6 +135,7 @@ public: return RenderDoc::Inst().GetCaptureFileFormats(); } + rdcarray GetAvailableGPUs() { return RenderDoc::Inst().GetAvailableGPUs(); } const SDFile &GetStructuredData() { // decompile to structured data on demand. diff --git a/renderdoc/replay/renderdoc_serialise.inl b/renderdoc/replay/renderdoc_serialise.inl index 6d937f15e..7ac0cecf5 100644 --- a/renderdoc/replay/renderdoc_serialise.inl +++ b/renderdoc/replay/renderdoc_serialise.inl @@ -879,6 +879,18 @@ void DoSerialise(SerialiserType &ser, CounterValue &el) SIZE_CHECK(8); } +template +void DoSerialise(SerialiserType &ser, GPUDevice &el) +{ + SERIALISE_MEMBER(vendor); + SERIALISE_MEMBER(deviceID); + SERIALISE_MEMBER(driver); + SERIALISE_MEMBER(name); + SERIALISE_MEMBER(apis); + + SIZE_CHECK(80); +} + #pragma region Common pipeline state template @@ -2243,6 +2255,7 @@ INSTANTIATE_SERIALISE_TYPE(PixelModification) INSTANTIATE_SERIALISE_TYPE(EventUsage) INSTANTIATE_SERIALISE_TYPE(CounterResult) INSTANTIATE_SERIALISE_TYPE(CounterValue) +INSTANTIATE_SERIALISE_TYPE(GPUDevice) INSTANTIATE_SERIALISE_TYPE(D3D11Pipe::Layout) INSTANTIATE_SERIALISE_TYPE(D3D11Pipe::InputAssembly) INSTANTIATE_SERIALISE_TYPE(D3D11Pipe::View) diff --git a/renderdoc/replay/replay_driver.h b/renderdoc/replay/replay_driver.h index 4aad9234b..a918d4392 100644 --- a/renderdoc/replay/replay_driver.h +++ b/renderdoc/replay/replay_driver.h @@ -176,6 +176,8 @@ public: virtual bool NeedRemapForFetch(const ResourceFormat &format) = 0; virtual DriverInformation GetDriverInfo() = 0; + + virtual rdcarray GetAvailableGPUs() = 0; }; class IReplayDriver : public IRemoteDriver