diff --git a/qrenderdoc/Code/CaptureContext.cpp b/qrenderdoc/Code/CaptureContext.cpp index a3dcff75e..c0c66e850 100644 --- a/qrenderdoc/Code/CaptureContext.cpp +++ b/qrenderdoc/Code/CaptureContext.cpp @@ -168,6 +168,11 @@ void CaptureContext::LoadCapture(const rdcstr &captureFile, const rdcstr &origFi ANALYTIC_SET(CaptureFeatures.MultiGPU, m_APIProps.MultiGPU); ANALYTIC_SET(CaptureFeatures.D3D12Bundle, m_APIProps.D3D12Bundle); + if(m_APIProps.vendor != GPUVendor::Unknown) + { + ANALYTIC_ADDUNIQ(GPUVendors, ToQStr(m_APIProps.vendor)); + } + m_MainWindow->setProgress(-1.0f); if(m_CaptureLoaded) diff --git a/renderdoc/api/replay/data_types.h b/renderdoc/api/replay/data_types.h index aeb7bde09..5b00b0822 100644 --- a/renderdoc/api/replay/data_types.h +++ b/renderdoc/api/replay/data_types.h @@ -1074,6 +1074,9 @@ different to the above, and lets the UI make decisions e.g. to flip rendering of )"); GraphicsAPI localRenderer = GraphicsAPI::D3D11; + DOCUMENT("The :class:`GPUVendor` of the active GPU being used."); + GPUVendor vendor = GPUVendor::Unknown; + DOCUMENT(R"(``True`` if the capture was loaded successfully but running in a degraded mode - e.g. with software rendering, or with some functionality disabled due to lack of support. )"); diff --git a/renderdoc/api/replay/renderdoc_tostr.inl b/renderdoc/api/replay/renderdoc_tostr.inl index 0e02a287f..0333b93ee 100644 --- a/renderdoc/api/replay/renderdoc_tostr.inl +++ b/renderdoc/api/replay/renderdoc_tostr.inl @@ -769,6 +769,25 @@ std::string DoStringise(const DebugOverlay &el) END_ENUM_STRINGISE(); } +template <> +std::string DoStringise(const GPUVendor &el) +{ + BEGIN_ENUM_STRINGISE(GPUVendor) + { + STRINGISE_ENUM_CLASS(Unknown); + STRINGISE_ENUM_CLASS(ARM); + STRINGISE_ENUM_CLASS(AMD); + STRINGISE_ENUM_CLASS(Broadcom); + STRINGISE_ENUM_CLASS(Imagination); + STRINGISE_ENUM_CLASS(Intel); + STRINGISE_ENUM_CLASS(nVidia); + STRINGISE_ENUM_CLASS(Qualcomm); + STRINGISE_ENUM_CLASS(Verisilicon); + STRINGISE_ENUM_CLASS(Software); + } + END_ENUM_STRINGISE(); +} + template <> std::string DoStringise(const GraphicsAPI &el) { diff --git a/renderdoc/api/replay/replay_enums.h b/renderdoc/api/replay/replay_enums.h index 78a32f954..172afd6d5 100644 --- a/renderdoc/api/replay/replay_enums.h +++ b/renderdoc/api/replay/replay_enums.h @@ -1207,6 +1207,79 @@ enum class QualityHint : uint32_t DECLARE_REFLECTION_ENUM(QualityHint); +DOCUMENT(R"(Identifies a GPU vendor. + +.. data:: Unknown + + A GPU from an unknown vendor + +.. data:: ARM + + An ARM GPU + +.. data:: AMD + + An AMD GPU + +.. data:: Broadcom + + A Broadcom GPU + +.. data:: Imagination + + An Imagination GPU + +.. data:: Intel + + An Intel GPU + +.. data:: nVidia + + An nVidia GPU + +.. data:: Qualcomm + + A Qualcomm GPU + +.. data:: Verisilicon + + A Verisilicon or Vivante GPU + +.. data:: Software + + A software-rendering emulated GPU +)"); +enum class GPUVendor : uint32_t +{ + Unknown, + ARM, + AMD, + Broadcom, + Imagination, + Intel, + nVidia, + Qualcomm, + Verisilicon, + Software, +}; + +DECLARE_REFLECTION_ENUM(GPUVendor); + +constexpr GPUVendor GPUVendorFromPCIVendor(uint32_t vendorID) +{ + // temporarily disable clang-format to make this more readable. + // Ideally we'd use a simple switch() but VS2015 doesn't support that :(. + // clang-format off + return vendorID == 0x13B5 ? GPUVendor::ARM + : vendorID == 0x1002 ? GPUVendor::AMD + : vendorID == 0x1010 ? GPUVendor::Imagination + : vendorID == 0x8086 ? GPUVendor::Intel + : vendorID == 0x10DE ? GPUVendor::nVidia + : vendorID == 0x5143 ? GPUVendor::Qualcomm + : GPUVendor::Unknown; + // clang-format on +} + DOCUMENT(R"(Identifies a Graphics API. .. data:: D3D11 diff --git a/renderdoc/driver/d3d11/d3d11_replay.cpp b/renderdoc/driver/d3d11/d3d11_replay.cpp index b18556f9d..9254663de 100644 --- a/renderdoc/driver/d3d11/d3d11_replay.cpp +++ b/renderdoc/driver/d3d11/d3d11_replay.cpp @@ -93,6 +93,14 @@ void D3D11Replay::CreateResources() IDXGIAdapter *pDXGIAdapter; hr = pDXGIDevice->GetParent(__uuidof(IDXGIAdapter), (void **)&pDXGIAdapter); + DXGI_ADAPTER_DESC desc = {}; + pDXGIAdapter->GetDesc(&desc); + + m_Vendor = GPUVendorFromPCIVendor(desc.VendorId); + + if(m_WARP) + m_Vendor = GPUVendor::Software; + if(FAILED(hr)) { RDCERR("Couldn't get DXGI adapter from DXGI device"); @@ -450,6 +458,7 @@ APIProperties D3D11Replay::GetAPIProperties() ret.pipelineType = GraphicsAPI::D3D11; ret.localRenderer = GraphicsAPI::D3D11; + ret.vendor = m_Vendor; ret.degraded = m_WARP; ret.shadersMutable = false; diff --git a/renderdoc/driver/d3d11/d3d11_replay.h b/renderdoc/driver/d3d11/d3d11_replay.h index 9aff49a83..ee9c336c0 100644 --- a/renderdoc/driver/d3d11/d3d11_replay.h +++ b/renderdoc/driver/d3d11/d3d11_replay.h @@ -231,6 +231,8 @@ private: bool m_WARP; bool m_Proxy; + GPUVendor m_Vendor = GPUVendor::Unknown; + D3D11DebugManager *GetDebugManager(); // shared by BuildCustomShader and BuildTargetShader void BuildShader(std::string source, std::string entry, const ShaderCompileFlags &compileFlags, diff --git a/renderdoc/driver/d3d12/d3d12_replay.cpp b/renderdoc/driver/d3d12/d3d12_replay.cpp index b45015b02..60a5a5d75 100644 --- a/renderdoc/driver/d3d12/d3d12_replay.cpp +++ b/renderdoc/driver/d3d12/d3d12_replay.cpp @@ -83,6 +83,26 @@ void D3D12Replay::CreateResources() RDCERR("Couldn't create DXGI factory! HRESULT: %s", ToStr(hr).c_str()); } + if(m_pFactory) + { + LUID luid = m_pDevice->GetAdapterLuid(); + + IDXGIAdapter *pDXGIAdapter; + hr = m_pFactory->EnumAdapterByLuid(luid, __uuidof(IDXGIAdapter), (void **)&pDXGIAdapter); + + if(FAILED(hr)) + { + RDCERR("Couldn't get DXGI adapter by LUID from D3D device"); + } + else + { + DXGI_ADAPTER_DESC desc = {}; + pDXGIAdapter->GetDesc(&desc); + + m_Vendor = GPUVendorFromPCIVendor(desc.VendorId); + } + } + m_DebugManager = new D3D12DebugManager(m_pDevice); CreateSOBuffers(); @@ -128,6 +148,7 @@ APIProperties D3D12Replay::GetAPIProperties() ret.pipelineType = GraphicsAPI::D3D12; ret.localRenderer = GraphicsAPI::D3D12; + ret.vendor = m_Vendor; ret.degraded = false; ret.shadersMutable = false; diff --git a/renderdoc/driver/d3d12/d3d12_replay.h b/renderdoc/driver/d3d12/d3d12_replay.h index df978843a..443cb79c3 100644 --- a/renderdoc/driver/d3d12/d3d12_replay.h +++ b/renderdoc/driver/d3d12/d3d12_replay.h @@ -262,6 +262,8 @@ private: bool m_Proxy; + GPUVendor m_Vendor = GPUVendor::Unknown; + vector m_ProxyResources; struct OutputWindow diff --git a/renderdoc/driver/gl/gl_debug.cpp b/renderdoc/driver/gl/gl_debug.cpp index 6b1f27463..86ad7df54 100644 --- a/renderdoc/driver/gl/gl_debug.cpp +++ b/renderdoc/driver/gl/gl_debug.cpp @@ -622,6 +622,74 @@ void GLReplay::InitDebugData() MakeCurrentReplayContext(&m_ReplayCtx); + // try to identify the GPU we're running on. + { + const char *vendor = (const char *)gl.glGetString(eGL_VENDOR); + const char *renderer = (const char *)gl.glGetString(eGL_RENDERER); + + // we're just doing substring searches, so combine both for ease. + std::string combined = (vendor ? vendor : ""); + combined += " "; + combined += (renderer ? renderer : ""); + + // make lowercase, for case-insensitive matching, and add preceding/trailing space for easier + // 'word' matching + combined = " " + strlower(combined) + " "; + + RDCDEBUG("Identifying vendor from '%s'", combined.c_str()); + + struct pattern + { + const char *search; + GPUVendor vendor; + } patterns[] = { + {" arm ", GPUVendor::ARM}, + {" mali ", GPUVendor::ARM}, + {" mali-", GPUVendor::ARM}, + {" amd ", GPUVendor::AMD}, + {"advanced micro devices", GPUVendor::AMD}, + {"ati technologies", GPUVendor::AMD}, + {"radeon", GPUVendor::AMD}, + {"broadcom", GPUVendor::Broadcom}, + {"imagination", GPUVendor::Imagination}, + {"powervr", GPUVendor::Imagination}, + {"intel", GPUVendor::Intel}, + {"geforce", GPUVendor::nVidia}, + {"quadro", GPUVendor::nVidia}, + {"nouveau", GPUVendor::nVidia}, + {"nvidia", GPUVendor::nVidia}, + {"adreno", GPUVendor::Qualcomm}, + {"qualcomm", GPUVendor::Qualcomm}, + {"vivante", GPUVendor::Verisilicon}, + {"llvmpipe", GPUVendor::Software}, + {"softpipe", GPUVendor::Software}, + {"bluestacks", GPUVendor::Software}, + }; + + for(const pattern &p : patterns) + { + if(combined.find(p.search) != std::string::npos) + { + if(m_Vendor == GPUVendor::Unknown) + { + m_Vendor = p.vendor; + } + else + { + // either we already found this with another pattern, or we've identified two patterns and + // it's ambiguous. Keep the first one we found, arbitrarily, but print a warning. + if(m_Vendor != p.vendor) + { + RDCWARN("Already identified '%s' as %s, but now identified as %s", combined.c_str(), + ToStr(m_Vendor).c_str(), ToStr(p.vendor).c_str()); + } + } + } + } + + RDCDEBUG("Identified GPU vendor '%s'", ToStr(m_Vendor).c_str()); + } + // these below need to be made on the replay context, as they are context-specific (not shared) // and will be used on the replay context. diff --git a/renderdoc/driver/gl/gl_replay.cpp b/renderdoc/driver/gl/gl_replay.cpp index ef4334b68..3bf974d29 100644 --- a/renderdoc/driver/gl/gl_replay.cpp +++ b/renderdoc/driver/gl/gl_replay.cpp @@ -143,6 +143,7 @@ APIProperties GLReplay::GetAPIProperties() ret.pipelineType = GraphicsAPI::OpenGL; ret.localRenderer = GraphicsAPI::OpenGL; ret.degraded = m_Degraded; + ret.vendor = m_Vendor; ret.shadersMutable = true; return ret; diff --git a/renderdoc/driver/gl/gl_replay.h b/renderdoc/driver/gl/gl_replay.h index 91f7b63d8..406b82610 100644 --- a/renderdoc/driver/gl/gl_replay.h +++ b/renderdoc/driver/gl/gl_replay.h @@ -365,6 +365,8 @@ private: bool m_Degraded; + GPUVendor m_Vendor = GPUVendor::Unknown; + HighlightCache m_HighlightCache; // eventId -> data diff --git a/renderdoc/driver/vulkan/vk_common.cpp b/renderdoc/driver/vulkan/vk_common.cpp index f3199d74a..52e49b466 100644 --- a/renderdoc/driver/vulkan/vk_common.cpp +++ b/renderdoc/driver/vulkan/vk_common.cpp @@ -27,10 +27,6 @@ #include "vk_manager.h" #include "vk_resources.h" -const uint32_t AMD_PCI_ID = 0x1002; -const uint32_t NV_PCI_ID = 0x10DE; -const uint32_t QUALCOMM_PCI_ID = 0x5143; - // utility struct for firing one-shot command buffers to begin/end markers struct ScopedCommandBuffer { @@ -1578,14 +1574,11 @@ INSTANTIATE_SERIALISE_TYPE(VkInitParams); VkDriverInfo::VkDriverInfo(const VkPhysicalDeviceProperties &physProps) { - if(physProps.vendorID == AMD_PCI_ID) - m_Vendor = AMD; - else if(physProps.vendorID == NV_PCI_ID) - m_Vendor = NV; - else if(physProps.vendorID == QUALCOMM_PCI_ID) - m_Vendor = QUALCOMM; - else - m_Vendor = UNKNOWN; + m_Vendor = GPUVendorFromPCIVendor(physProps.vendorID); + + // add non-PCI vendor IDs + if(physProps.vendorID == 0x10002) + m_Vendor = GPUVendor::Verisilicon; m_Major = VK_VERSION_MAJOR(physProps.driverVersion); m_Minor = VK_VERSION_MINOR(physProps.driverVersion); @@ -1594,7 +1587,7 @@ VkDriverInfo::VkDriverInfo(const VkPhysicalDeviceProperties &physProps) // nvidia uses its own version packing: // 10 | 8 | 8 | 6 // major|minor|secondary_branch|tertiary_branch - if(IsNV()) + if(m_Vendor == GPUVendor::nVidia) { m_Major = ((uint32_t)(physProps.driverVersion) >> (8 + 8 + 6)) & 0x3ff; m_Minor = ((uint32_t)(physProps.driverVersion) >> (8 + 6)) & 0x0ff; @@ -1605,7 +1598,7 @@ VkDriverInfo::VkDriverInfo(const VkPhysicalDeviceProperties &physProps) m_Patch = (secondary << 8) | tertiary; } - if(IsNV()) + if(m_Vendor == GPUVendor::nVidia) { // drivers before 372.54 did not handle a glslang bugfix about separated samplers, // and disabling texelFetch works as a workaround. @@ -1618,7 +1611,7 @@ VkDriverInfo::VkDriverInfo(const VkPhysicalDeviceProperties &physProps) // using the AMD official driver, but there's not a great other way to distinguish it from // the RADV open source driver. #if ENABLED(RDOC_WIN32) - if(IsAMD()) + if(m_Vendor == GPUVendor::AMD) { // for AMD the bugfix version isn't clear as version numbering wasn't strong for a while, but // any driver that reports a version of >= 1.0.0 is fine, as previous versions all reported @@ -1636,7 +1629,7 @@ VkDriverInfo::VkDriverInfo(const VkPhysicalDeviceProperties &physProps) // same as above, only affects the AMD official driver #if ENABLED(RDOC_WIN32) - if(IsAMD()) + if(m_Vendor == GPUVendor::AMD) { // not fixed yet amdStorageMSAABrokenDriver = true; @@ -1644,5 +1637,5 @@ VkDriverInfo::VkDriverInfo(const VkPhysicalDeviceProperties &physProps) #endif // not fixed yet - qualcommLeakingUBOOffsets = IsQualcomm(); + qualcommLeakingUBOOffsets = m_Vendor == GPUVendor::Qualcomm; } diff --git a/renderdoc/driver/vulkan/vk_common.h b/renderdoc/driver/vulkan/vk_common.h index 5e4f73a0d..3c607b0c7 100644 --- a/renderdoc/driver/vulkan/vk_common.h +++ b/renderdoc/driver/vulkan/vk_common.h @@ -178,16 +178,10 @@ struct GPUBuffer // in vk_.cpp extern const char *VulkanLibraryName; -extern const uint32_t AMD_PCI_ID; -extern const uint32_t NV_PCI_ID; -extern const uint32_t QUALCOMM_PCI_ID; - class VkDriverInfo { public: - bool IsAMD() { return m_Vendor == AMD; } - bool IsNV() { return m_Vendor == NV; } - bool IsQualcomm() { return m_Vendor == QUALCOMM; } + GPUVendor Vendor() { return m_Vendor; } uint32_t Major() { return m_Major; } uint32_t Minor() { return m_Minor; } uint32_t Patch() { return m_Patch; } @@ -206,13 +200,7 @@ public: // rendering on other descriptor sets that don't use offsets at all. bool QualcommLeakingUBOOffsets() { return qualcommLeakingUBOOffsets; } private: - enum - { - AMD, - NV, - QUALCOMM, - UNKNOWN, - } m_Vendor; + GPUVendor m_Vendor; uint32_t m_Major, m_Minor, m_Patch; diff --git a/renderdoc/driver/vulkan/wrappers/vk_device_funcs.cpp b/renderdoc/driver/vulkan/wrappers/vk_device_funcs.cpp index a0735f081..58dfcd799 100644 --- a/renderdoc/driver/vulkan/wrappers/vk_device_funcs.cpp +++ b/renderdoc/driver/vulkan/wrappers/vk_device_funcs.cpp @@ -1237,6 +1237,8 @@ bool WrappedVulkan::Serialise_vkCreateDevice(SerialiserType &ser, VkPhysicalDevi } } + APIProps.vendor = GetDriverVersion().Vendor(); + m_ShaderCache = new VulkanShaderCache(this); m_DebugManager = new VulkanDebugManager(this); diff --git a/renderdoc/driver/vulkan/wrappers/vk_get_funcs.cpp b/renderdoc/driver/vulkan/wrappers/vk_get_funcs.cpp index 0edb97782..e988bada3 100644 --- a/renderdoc/driver/vulkan/wrappers/vk_get_funcs.cpp +++ b/renderdoc/driver/vulkan/wrappers/vk_get_funcs.cpp @@ -165,7 +165,7 @@ void WrappedVulkan::vkGetImageMemoryRequirements(VkDevice device, VkImage image, // allow for this. The variability isn't quite clear, but for now we assume aligning size to // alignment * 4 should be sufficient (adding on a fixed padding won't help the problem as it // won't remove the variability, nor will adding then aligning for the same reason). - if(GetDriverVersion().IsAMD() && pMemoryRequirements->size > 0) + if(GetDriverVersion().Vendor() == GPUVendor::AMD && pMemoryRequirements->size > 0) { VkMemoryRequirements &memreq = *pMemoryRequirements; @@ -247,7 +247,7 @@ void WrappedVulkan::vkGetImageMemoryRequirements2KHR(VkDevice device, // allow for this. The variability isn't quite clear, but for now we assume aligning size to // alignment * 4 should be sufficient (adding on a fixed padding won't help the problem as it // won't remove the variability, nor will adding then aligning for the same reason). - if(GetDriverVersion().IsAMD() && pMemoryRequirements->memoryRequirements.size > 0) + if(GetDriverVersion().Vendor() == GPUVendor::AMD && pMemoryRequirements->memoryRequirements.size > 0) { VkMemoryRequirements &memreq = pMemoryRequirements->memoryRequirements; diff --git a/renderdoc/replay/renderdoc_serialise.inl b/renderdoc/replay/renderdoc_serialise.inl index 7bb6a95bc..d1e62282f 100644 --- a/renderdoc/replay/renderdoc_serialise.inl +++ b/renderdoc/replay/renderdoc_serialise.inl @@ -425,6 +425,7 @@ void DoSerialise(SerialiserType &ser, APIProperties &el) { SERIALISE_MEMBER(pipelineType); SERIALISE_MEMBER(localRenderer); + SERIALISE_MEMBER(vendor); SERIALISE_MEMBER(degraded); SERIALISE_MEMBER(shadersMutable); @@ -434,7 +435,7 @@ void DoSerialise(SerialiserType &ser, APIProperties &el) SERIALISE_MEMBER(MultiGPU); SERIALISE_MEMBER(D3D12Bundle); - SIZE_CHECK(16); + SIZE_CHECK(20); } template