diff --git a/renderdoc/core/core.cpp b/renderdoc/core/core.cpp index 445c857d6..f68931b33 100644 --- a/renderdoc/core/core.cpp +++ b/renderdoc/core/core.cpp @@ -480,6 +480,112 @@ void RenderDoc::ProcessGlobalEnvironment(GlobalEnvironment env, const std::vecto for(size_t i = 0; i < args.size(); i++) RDCDEBUG("[%u]: %s", (uint32_t)i, args[i].c_str()); } + + m_AvailableGPUThread = Threading::CreateThread([this]() { + 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 = m_ReplayDriverProviders[driverType](NULL, ReplayOptions(), &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()); + } + }); } bool RenderDoc::MatchClosestWindow(void *&dev, void *&wnd) @@ -1152,116 +1258,21 @@ std::vector RenderDoc::GetCaptureFileFormats() 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()); - } - } + SyncAvailableGPUThread(); return m_AvailableGPUs; } +void RenderDoc::SyncAvailableGPUThread() +{ + if(m_AvailableGPUThread) + { + Threading::JoinThread(m_AvailableGPUThread); + Threading::CloseThread(m_AvailableGPUThread); + m_AvailableGPUThread = 0; + } +} + bool RenderDoc::HasReplaySupport(RDCDriver driverType) { if(driverType == RDCDriver::Image) @@ -1275,6 +1286,8 @@ bool RenderDoc::HasReplaySupport(RDCDriver driverType) ReplayStatus RenderDoc::CreateProxyReplayDriver(RDCDriver proxyDriver, IReplayDriver **driver) { + SyncAvailableGPUThread(); + // passing RDCDriver::Unknown means 'I don't care, give me a proxy driver of any type' if(proxyDriver == RDCDriver::Unknown) { @@ -1295,6 +1308,8 @@ ReplayStatus RenderDoc::CreateReplayDriver(RDCFile *rdc, const ReplayOptions &op if(driver == NULL) return ReplayStatus::InternalError; + SyncAvailableGPUThread(); + // allows passing NULL rdcfile as 'I don't care, give me a proxy driver of any type' if(rdc == NULL) { @@ -1324,6 +1339,8 @@ ReplayStatus RenderDoc::CreateRemoteDriver(RDCFile *rdc, const ReplayOptions &op if(rdc == NULL || driver == NULL) return ReplayStatus::InternalError; + SyncAvailableGPUThread(); + RDCDriver driverType = rdc->GetDriver(); if(m_RemoteDriverProviders.find(driverType) != m_RemoteDriverProviders.end()) diff --git a/renderdoc/core/core.h b/renderdoc/core/core.h index aa06fcd87..9b0a01322 100644 --- a/renderdoc/core/core.h +++ b/renderdoc/core/core.h @@ -607,6 +607,8 @@ private: RenderDoc(); ~RenderDoc(); + void SyncAvailableGPUThread(); + static RenderDoc *m_Inst; bool m_Replay; @@ -639,6 +641,7 @@ private: Threading::CriticalSection m_DriverLock; std::map m_ActiveDrivers; + Threading::ThreadHandle m_AvailableGPUThread = 0; rdcarray m_AvailableGPUs; std::map m_ProgressCallbacks;