Move available GPU check onto thread at startup

* This hides a stall when first opening a window that needs the list of GPUs.
This commit is contained in:
baldurk
2019-08-28 15:34:28 +01:00
parent a32c48c863
commit 422cd728ad
2 changed files with 126 additions and 106 deletions
+123 -106
View File
@@ -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<GPUDevice> 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<CaptureFileFormat> RenderDoc::GetCaptureFileFormats()
rdcarray<GPUDevice> 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<GPUDevice> 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())