Exemple #1
0
static QString GetDescription(const EnvironmentModification &env)
{
  QString ret;

  if(env.mod == EnvMod::Append)
    ret = QFormatStr("Append %1 with %2 using %3").arg(env.name).arg(env.value).arg(ToQStr(env.sep));
  else if(env.mod == EnvMod::Prepend)
    ret = QFormatStr("Prepend %1 with %2 using %3").arg(env.name).arg(env.value).arg(ToQStr(env.sep));
  else
    ret = QFormatStr("Set %1 to %2").arg(env.name).arg(env.value);

  return ret;
}
Exemple #2
0
QString D3DSemanticString(const SigParameter &sig)
{
  if(sig.systemValue == eAttr_None)
    return ToQStr(sig.semanticIdxName);

  QString ret = ToQStr(sig.systemValue);

  // need to include the index if it's a system value semantic that's numbered
  if(sig.systemValue == eAttr_ColourOutput || sig.systemValue == eAttr_CullDistance ||
     sig.systemValue == eAttr_ClipDistance)
    ret += QString::number(sig.semanticIndex);

  return ret;
}
Exemple #3
0
void CaptureContext::SaveRenames()
{
  QVariantMap resources;
  for(ResourceId id : m_CustomNames.keys())
  {
    resources[ToQStr(id)] = m_CustomNames[id];
  }

  QVariantMap root;
  root[lit("CustomResourceNames")] = resources;

  QString json = VariantToJSON(root);

  SectionProperties props;
  props.type = SectionType::ResourceRenames;
  props.version = 1;

  Replay().GetCaptureAccess()->WriteSection(props, json.toUtf8());
}
void CaptureContext::LoadLogfileThreaded(const QString &logFile, const QString &origFilename,
                                         bool temporary, bool local)
{
  QFileInfo fi(ConfigFile("UI.config"));

  m_LogFile = origFilename;

  m_LogLocal = local;

  m_LoadInProgress = true;

  if(fi.exists())
    Config.Serialize(fi.absoluteFilePath());

  float loadProgress = 0.0f;
  float postloadProgress = 0.0f;

  QSemaphore progressThread(1);

  LambdaThread progressTickerThread([this, &progressThread, &loadProgress, &postloadProgress]() {
    while(progressThread.available())
    {
      QThread::msleep(30);

      float val = 0.8f * loadProgress + 0.19f * postloadProgress + 0.01f;

      GUIInvoke::call([this, val]() {
        m_Progress->setValue(val * 1000);
        m_MainWindow->setProgress(val);
      });
    }
    GUIInvoke::call([this]() { m_Progress->setValue(1000); });
  });
  progressTickerThread.start();

  // this function call will block until the log is either loaded, or there's some failure
  m_Renderer.OpenCapture(logFile, &loadProgress);

  // if the renderer isn't running, we hit a failure case so display an error message
  if(!m_Renderer.IsRunning())
  {
    QString errmsg = "Unknown error message";
    errmsg = ToQStr(m_Renderer.GetCreateStatus());

    progressThread.acquire();
    progressTickerThread.wait();

    RDDialog::critical(NULL, "Error opening log",
                       QString("%1\nFailed to open logfile for replay: %2.\n\n"
                               "Check diagnostic log in Help menu for more details.")
                           .arg(logFile)
                           .arg(errmsg));

    GUIInvoke::call([this]() {
      m_Progress->setValue(1000);
      m_MainWindow->setProgress(-1.0f);
      m_Progress->hide();
    });

    m_LoadInProgress = false;

    return;
  }

  if(!temporary)
  {
    PersistantConfig::AddRecentFile(Config.RecentLogFiles, origFilename, 10);

    if(fi.exists())
      Config.Serialize(fi.absoluteFilePath());
  }

  m_EventID = 0;

  // fetch initial data like drawcalls, textures and buffers
  m_Renderer.BlockInvoke([this, &postloadProgress](IReplayRenderer *r) {
    r->GetFrameInfo(&m_FrameInfo);

    m_APIProps = r->GetAPIProperties();

    postloadProgress = 0.2f;

    r->GetDrawcalls(&m_Drawcalls);

    postloadProgress = 0.4f;

    r->GetSupportedWindowSystems(&m_WinSystems);

#if defined(RENDERDOC_PLATFORM_WIN32)
    m_CurWinSystem = eWindowingSystem_Win32;
#elif defined(RENDERDOC_PLATFORM_LINUX)
    m_CurWinSystem = eWindowingSystem_Xlib;

    // prefer XCB, if supported
    for(WindowingSystem sys : m_WinSystems)
    {
      if(sys == eWindowingSystem_XCB)
      {
        m_CurWinSystem = eWindowingSystem_XCB;
        break;
      }
    }

    if(m_CurWinSystem == eWindowingSystem_XCB)
      m_XCBConnection = QX11Info::connection();
    else
      m_X11Display = QX11Info::display();
#endif

    r->GetBuffers(&m_BufferList);
    for(FetchBuffer &b : m_BufferList)
      m_Buffers[b.ID] = &b;

    postloadProgress = 0.8f;

    r->GetTextures(&m_TextureList);
    for(FetchTexture &t : m_TextureList)
      m_Textures[t.ID] = &t;

    postloadProgress = 0.9f;

    r->GetD3D11PipelineState(&CurD3D11PipelineState);
    r->GetD3D12PipelineState(&CurD3D12PipelineState);
    r->GetGLPipelineState(&CurGLPipelineState);
    r->GetVulkanPipelineState(&CurVulkanPipelineState);
    CurPipelineState.SetStates(m_APIProps, &CurD3D11PipelineState, &CurD3D12PipelineState,
                               &CurGLPipelineState, &CurVulkanPipelineState);

    UnreadMessageCount = 0;
    AddMessages(m_FrameInfo.debugMessages);

    postloadProgress = 1.0f;
  });

  QThread::msleep(20);

  QDateTime today = QDateTime::currentDateTimeUtc();
  QDateTime compare = today.addDays(-21);

  if(compare > Config.DegradedLog_LastUpdate && m_APIProps.degraded)
  {
    Config.DegradedLog_LastUpdate = today;

    RDDialog::critical(
        NULL, "Degraded support of log",
        QString(
            "%1\nThis log opened with degraded support - "
            "this could mean missing hardware support caused a fallback to software rendering.\n\n"
            "This warning will not appear every time this happens, "
            "check debug errors/warnings window for more details.")
            .arg(origFilename));
  }

  m_LogLoaded = true;

  progressThread.acquire();
  progressTickerThread.wait();

  QVector<ILogViewerForm *> logviewers(m_LogViewers);

  GUIInvoke::blockcall([&logviewers]() {
    // notify all the registers log viewers that a log has been loaded
    for(ILogViewerForm *logviewer : logviewers)
    {
      if(logviewer)
        logviewer->OnLogfileLoaded();
    }
  });

  m_LoadInProgress = false;

  GUIInvoke::call([this]() {
    m_Progress->setValue(1000);
    m_MainWindow->setProgress(1.0f);
    m_Progress->hide();
  });
}
Exemple #5
0
void RemoteManager::on_connect_clicked()
{
  RDTreeWidgetItem *node = ui->hosts->selectedItem();

  if(!node)
    return;

  RemoteConnect connect = getRemoteConnect(node);
  RemoteHost *host = getRemoteHost(node);

  if(connect.ident > 0)
  {
    connectToApp(node);
  }
  else if(host)
  {
    if(host->serverRunning)
    {
      QMessageBox::StandardButton res = RDDialog::question(
          this, tr("Remote server shutdown"),
          tr("Are you sure you wish to shut down running remote server on %1?").arg(host->Name()),
          RDDialog::YesNoCancel);

      if(res == QMessageBox::Cancel || res == QMessageBox::No)
        return;

      // shut down
      if(host->connected)
      {
        m_Ctx.Replay().ShutdownServer();
        setRemoteServerLive(node, false, false);
      }
      else
      {
        IRemoteServer *server = NULL;
        ReplayStatus status =
            RENDERDOC_CreateRemoteServerConnection(host->hostname.c_str(), 0, &server);
        if(server)
          server->ShutdownServerAndConnection();
        setRemoteServerLive(node, false, false);

        if(status != ReplayStatus::Succeeded)
          RDDialog::critical(this, tr("Shutdown error"),
                             tr("Error shutting down remote server: %1").arg(ToQStr(status)));
      }

      updateConnectButton();
    }
    else
    {
      // try to run
      ui->refreshOne->setEnabled(false);
      ui->refreshAll->setEnabled(false);

      m_Lookups.release();

      LambdaThread *th = new LambdaThread([this, node]() { runRemoteServer(node); });
      th->selfDelete(true);
      th->start();

      updateLookupsStatus();
    }
  }
}
Exemple #6
0
void CaptureContext::LoadCaptureThreaded(const QString &captureFile, const QString &origFilename,
                                         bool temporary, bool local)
{
  m_CaptureFile = origFilename;

  m_CaptureLocal = local;

  Config().Save();

  m_LoadProgress = 0.0f;
  m_PostloadProgress = 0.0f;

  // this function call will block until the capture is either loaded, or there's some failure
  m_Renderer.OpenCapture(captureFile, [this](float p) { m_LoadProgress = p; });

  // if the renderer isn't running, we hit a failure case so display an error message
  if(!m_Renderer.IsRunning())
  {
    QString errmsg = ToQStr(m_Renderer.GetCreateStatus());

    QString messageText = tr("%1\nFailed to open capture for replay: %2.\n\n"
                             "Check diagnostic log in Help menu for more details.")
                              .arg(captureFile)
                              .arg(errmsg);

    RDDialog::critical(NULL, tr("Error opening capture"), messageText);

    m_LoadInProgress = false;
    return;
  }

  if(!temporary)
  {
    AddRecentFile(Config().RecentCaptureFiles, origFilename, 10);

    Config().Save();
  }

  m_EventID = 0;

  m_FirstDrawcall = m_LastDrawcall = NULL;

  // fetch initial data like drawcalls, textures and buffers
  m_Renderer.BlockInvoke([this](IReplayController *r) {
    m_FrameInfo = r->GetFrameInfo();

    m_APIProps = r->GetAPIProperties();

    m_PostloadProgress = 0.2f;

    m_Drawcalls = r->GetDrawcalls();

    AddFakeProfileMarkers();

    m_FirstDrawcall = &m_Drawcalls[0];
    while(!m_FirstDrawcall->children.empty())
      m_FirstDrawcall = &m_FirstDrawcall->children[0];

    m_LastDrawcall = &m_Drawcalls.back();
    while(!m_LastDrawcall->children.empty())
      m_LastDrawcall = &m_LastDrawcall->children.back();

    m_PostloadProgress = 0.4f;

    m_WinSystems = r->GetSupportedWindowSystems();

#if defined(RENDERDOC_PLATFORM_WIN32)
    m_CurWinSystem = WindowingSystem::Win32;
#elif defined(RENDERDOC_PLATFORM_LINUX)
    m_CurWinSystem = WindowingSystem::Xlib;

    // prefer XCB, if supported
    for(WindowingSystem sys : m_WinSystems)
    {
      if(sys == WindowingSystem::XCB)
      {
        m_CurWinSystem = WindowingSystem::XCB;
        break;
      }
    }

    if(m_CurWinSystem == WindowingSystem::XCB)
      m_XCBConnection = QX11Info::connection();
    else
      m_X11Display = QX11Info::display();
#endif

    m_StructuredFile = &r->GetStructuredFile();

    m_ResourceList = r->GetResources();
    for(ResourceDescription &res : m_ResourceList)
      m_Resources[res.resourceId] = &res;

    m_BufferList = r->GetBuffers();
    for(BufferDescription &b : m_BufferList)
      m_Buffers[b.resourceId] = &b;

    m_PostloadProgress = 0.8f;

    m_TextureList = r->GetTextures();
    for(TextureDescription &t : m_TextureList)
      m_Textures[t.resourceId] = &t;

    m_PostloadProgress = 0.9f;

    m_CurD3D11PipelineState = &r->GetD3D11PipelineState();
    m_CurD3D12PipelineState = &r->GetD3D12PipelineState();
    m_CurGLPipelineState = &r->GetGLPipelineState();
    m_CurVulkanPipelineState = &r->GetVulkanPipelineState();
    m_CurPipelineState.SetStates(m_APIProps, m_CurD3D11PipelineState, m_CurD3D12PipelineState,
                                 m_CurGLPipelineState, m_CurVulkanPipelineState);

    m_UnreadMessageCount = 0;
    AddMessages(m_FrameInfo.debugMessages);

    m_PostloadProgress = 1.0f;
  });

  QThread::msleep(20);

  QDateTime today = QDateTime::currentDateTimeUtc();
  QDateTime compare = today.addDays(-21);

  if(compare > Config().DegradedCapture_LastUpdate && m_APIProps.degraded)
  {
    Config().DegradedCapture_LastUpdate = today;

    RDDialog::critical(
        NULL, tr("Degraded support of capture"),
        tr("%1\nThis capture opened with degraded support - "
           "this could mean missing hardware support caused a fallback to software rendering.\n\n"
           "This warning will not appear every time this happens, "
           "check debug errors/warnings window for more details.")
            .arg(origFilename));
  }

  ICaptureAccess *access = Replay().GetCaptureAccess();

  if(access)
  {
    int idx = access->FindSectionByType(SectionType::ResourceRenames);
    if(idx >= 0)
    {
      bytebuf buf = access->GetSectionContents(idx);
      LoadRenames(QString::fromUtf8((const char *)buf.data(), buf.count()));
    }

    idx = access->FindSectionByType(SectionType::Bookmarks);
    if(idx >= 0)
    {
      bytebuf buf = access->GetSectionContents(idx);
      LoadBookmarks(QString::fromUtf8((const char *)buf.data(), buf.count()));
    }

    idx = access->FindSectionByType(SectionType::Notes);
    if(idx >= 0)
    {
      bytebuf buf = access->GetSectionContents(idx);
      LoadNotes(QString::fromUtf8((const char *)buf.data(), buf.count()));
    }
  }

  m_LoadInProgress = false;
  m_CaptureLoaded = true;
}
void AppendUpdateStatistics(QString &statisticsLog, const FetchFrameInfo &frameInfo)
{
  // #mivance see AppendConstantBindStatistics
  const FetchFrameUpdateStats &reference = frameInfo.stats.updates;

  FetchFrameUpdateStats totalUpdates;
  memset(&totalUpdates, 0, sizeof(totalUpdates));
  totalUpdates.types.create(reference.types.count);
  totalUpdates.sizes.create(reference.sizes.count);

  {
    FetchFrameUpdateStats updates = frameInfo.stats.updates;

    totalUpdates.calls += updates.calls;
    totalUpdates.clients += updates.clients;
    totalUpdates.servers += updates.servers;

    for(int t = 0; t < updates.types.count; t++)
      totalUpdates.types[t] += updates.types[t];

    for(int t = 0; t < updates.sizes.count; t++)
      totalUpdates.sizes[t] += updates.sizes[t];
  }

  statisticsLog.append("\n*** Resource Update Statistics ***\n\n");

  statisticsLog.append(
      QString("Total calls: %1, client-updated memory: %2, server-updated memory: %3\n")
          .arg(totalUpdates.calls)
          .arg(totalUpdates.clients)
          .arg(totalUpdates.servers));

  statisticsLog.append("\nUpdated resource types:\n");
  uint32_t maxCount = 0;
  int maxWithValue = 0;
  for(int s = 1; s < totalUpdates.types.count; s++)
  {
    uint32_t value = totalUpdates.types[s];
    if(value > 0)
      maxWithValue = s;
    maxCount = qMax(maxCount, value);
  }

  for(int s = 1; s <= maxWithValue; s++)
  {
    uint32_t count = totalUpdates.types[s];
    int slice = SliceForString(Stars, count, maxCount);
    ShaderResourceType type = (ShaderResourceType)s;
    statisticsLog.append(
        QString("%1: %2 %3\n").arg(ToQStr(type), 20).arg(Stars.left(slice)).arg(CountOrEmpty(count)));
  }

  statisticsLog.append("\nUpdated resource sizes:\n");
  maxCount = 0;
  maxWithValue = 0;
  for(int s = 0; s < totalUpdates.sizes.count; s++)
  {
    uint32_t value = totalUpdates.sizes[s];
    if(value > 0)
      maxWithValue = s;
    maxCount = qMax(maxCount, value);
  }

  for(int s = 0; s <= maxWithValue; s++)
  {
    uint32_t count = totalUpdates.sizes[s];
    int slice = SliceForString(Stars, count, maxCount);
    statisticsLog.append(QString("%1: %2 %3\n")
                             .arg(Pow2IndexAsReadable(s), 8)
                             .arg(Stars.left(slice))
                             .arg(CountOrEmpty(count)));
  }
}
void AppendResourceBindStatistics(CaptureContext *ctx, QString &statisticsLog,
                                  const FetchFrameInfo &frameInfo)
{
  // #mivance see AppendConstantBindStatistics
  const FetchFrameResourceBindStats &reference = frameInfo.stats.resources[0];

  FetchFrameResourceBindStats totalResourcesPerStage[eShaderStage_Count];
  memset(&totalResourcesPerStage, 0, sizeof(totalResourcesPerStage));
  for(int s = eShaderStage_First; s < eShaderStage_Count; s++)
  {
    totalResourcesPerStage[s].types.create(reference.types.count);
    totalResourcesPerStage[s].bindslots.create(reference.bindslots.count);
  }

  {
    const FetchFrameResourceBindStats *resources = frameInfo.stats.resources;
    for(int s = eShaderStage_First; s < eShaderStage_Count; s++)
    {
      totalResourcesPerStage[s].calls += resources[s].calls;
      totalResourcesPerStage[s].sets += resources[s].sets;
      totalResourcesPerStage[s].nulls += resources[s].nulls;

      for(int z = 0; z < resources[s].types.count; z++)
      {
        totalResourcesPerStage[s].types[z] += resources[s].types[z];
      }

      for(int l = 0; l < resources[s].bindslots.count; l++)
      {
        totalResourcesPerStage[s].bindslots[l] += resources[s].bindslots[l];
      }
    }
  }

  FetchFrameResourceBindStats totalResourcesForAllStages;
  memset(&totalResourcesForAllStages, 0, sizeof(totalResourcesForAllStages));
  totalResourcesForAllStages.types.create(totalResourcesPerStage[0].types.count);
  totalResourcesForAllStages.bindslots.create(totalResourcesPerStage[0].bindslots.count);

  for(int s = eShaderStage_First; s < eShaderStage_Count; s++)
  {
    FetchFrameResourceBindStats perStage = totalResourcesPerStage[s];
    totalResourcesForAllStages.calls += perStage.calls;
    totalResourcesForAllStages.sets += perStage.sets;
    totalResourcesForAllStages.nulls += perStage.nulls;
    for(int t = 0; t < perStage.types.count; t++)
    {
      totalResourcesForAllStages.types[t] += perStage.types[t];
    }
    for(int l = 0; l < perStage.bindslots.count; l++)
    {
      totalResourcesForAllStages.bindslots[l] += perStage.bindslots[l];
    }
  }

  statisticsLog.append("\n*** Resource Bind Statistics ***\n\n");

  for(int s = eShaderStage_First; s < eShaderStage_Count; s++)
  {
    statisticsLog.append(QString("%1 calls: %2 non-null resource sets: %3 null resource sets: %4\n")
                             .arg(ctx->CurPipelineState.Abbrev((ShaderStageType)s))
                             .arg(totalResourcesPerStage[s].calls)
                             .arg(totalResourcesPerStage[s].sets)
                             .arg(totalResourcesPerStage[s].nulls));
  }

  statisticsLog.append(
      QString("Total calls: %1 non-null resource sets: %2 null resource sets: %3\n")
          .arg(totalResourcesForAllStages.calls)
          .arg(totalResourcesForAllStages.sets)
          .arg(totalResourcesForAllStages.nulls));

  uint32_t maxCount = 0;
  int maxWithCount = 0;

  statisticsLog.append("\nResource types across all stages:\n");
  for(int s = 0; s < totalResourcesForAllStages.types.count; s++)
  {
    uint32_t count = totalResourcesForAllStages.types[s];
    if(count > 0)
      maxWithCount = s;
    maxCount = qMax(maxCount, count);
  }

  for(int s = 0; s <= maxWithCount; s++)
  {
    uint32_t count = totalResourcesForAllStages.types[s];
    int slice = SliceForString(Stars, count, maxCount);
    ShaderResourceType type = (ShaderResourceType)s;
    statisticsLog.append(
        QString("%1: %2 %3\n").arg(ToQStr(type), 20).arg(Stars.left(slice)).arg(CountOrEmpty(count)));
  }

  statisticsLog.append(CreateSimpleIntegerHistogram(
      "Aggregate slot counts per invocation across all stages", totalResourcesForAllStages.bindslots));
}
Exemple #9
0
bool PersistantConfig::Load(const rdcstr &filename)
{
  bool ret = Deserialize(filename);

  // perform some sanitisation to make sure config is always in sensible state
  for(const rdcstrpair &key : ConfigSettings)
  {
    // redundantly set each setting so it is flushed to the core dll
    SetConfigSetting(key.first, key.second);
  }

  RENDERDOC_SetConfigSetting("Disassembly_FriendlyNaming", ShaderViewer_FriendlyNaming ? "1" : "0");

  // localhost should always be available as a remote host
  bool foundLocalhost = false;

  for(RemoteHost host : RemoteHostList)
  {
    if(host.hostname.isEmpty())
      continue;

    RemoteHosts.push_back(new RemoteHost(host));

    if(host.IsLocalhost())
      foundLocalhost = true;
  }

  if(!foundLocalhost)
  {
    RemoteHost *host = new RemoteHost();
    host->hostname = "localhost";
    RemoteHosts.insert(0, host);
  }

  bool tools[arraydim<KnownSPIRVTool>()] = {};

  // see which known tools are registered
  for(const SPIRVDisassembler &dis : SPIRVDisassemblers)
  {
    // if it's declared
    if(dis.tool != KnownSPIRVTool::Unknown)
      tools[(size_t)dis.tool] = true;

    for(KnownSPIRVTool tool : values<KnownSPIRVTool>())
    {
      if(QString(dis.executable).contains(ToolExecutable(tool)))
        tools[(size_t)tool] = true;
    }
  }

  for(KnownSPIRVTool tool : values<KnownSPIRVTool>())
  {
    if(tool == KnownSPIRVTool::Unknown || tools[(size_t)tool])
      continue;

    QString exe = ToolExecutable(tool);

    if(exe.isEmpty())
      continue;

    // try to find the tool in PATH
    QString path = QStandardPaths::findExecutable(exe);

    if(!path.isEmpty())
    {
      SPIRVDisassembler dis;
      dis.name = ToQStr(tool);
      // we store just the base name, so when we launch the process it will always find it in PATH,
      // rather than baking in the current PATH result.
      dis.executable = exe;
      dis.tool = tool;

      SPIRVDisassemblers.push_back(dis);

      continue;
    }

    // try to find it in our plugins folder
    QDir appDir(QApplication::applicationDirPath());

    QStringList searchPaths = {appDir.absoluteFilePath(lit("plugins/spirv/"))};

#if defined(Q_OS_WIN64)
    searchPaths << appDir.absoluteFilePath(lit("../../plugins-win64/spirv/"));
#elif defined(Q_OS_WIN64)
    searchPaths << appDir.absoluteFilePath(lit("../../plugins-win32/spirv/"));
#elif defined(Q_OS_LINUX)
    searchPaths << appDir.absoluteFilePath(lit("../../plugins-linux64/spirv/"));
#endif

    searchPaths << appDir.absoluteFilePath(lit("../../plugins/"));

    path = QStandardPaths::findExecutable(exe, searchPaths);

    if(!path.isEmpty())
    {
      SPIRVDisassembler dis;
      dis.name = ToQStr(tool);
      dis.executable = path;
      dis.tool = tool;

      SPIRVDisassemblers.push_back(dis);

      continue;
    }
  }

  return ret;
}
Exemple #10
0
QStringList PythonContext::completionOptions(QString base)
{
  QStringList ret;

  if(!m_Completer)
    return ret;

  QByteArray bytes = base.toUtf8();
  const char *input = (const char *)bytes.data();

  PyGILState_STATE gil = PyGILState_Ensure();

  PyObject *completeFunction = PyObject_GetAttrString(m_Completer, "complete");

  int idx = 0;
  PyObject *opt = NULL;
  do
  {
    opt = PyObject_CallFunction(completeFunction, "si", input, idx);

    if(opt && opt != Py_None)
    {
      QString optstr = ToQStr(opt);

      bool add = true;

      // little hack, remove some of the ugly swig template instantiations that we can't avoid.
      if(optstr.contains(lit("renderdoc.rdcarray")) || optstr.contains(lit("renderdoc.rdcstr")) ||
         optstr.contains(lit("renderdoc.bytebuf")))
        add = false;

      if(add)
        ret << optstr;
    }

    idx++;
  } while(opt && opt != Py_None);

  // extra hack, remove the swig object functions/data but ONLY if we find a sure-fire identifier
  // (thisown) since otherwise we could remove append from a list object
  bool containsSwigInternals = false;
  for(const QString &optstr : ret)
  {
    if(optstr.contains(lit(".thisown")))
    {
      containsSwigInternals = true;
      break;
    }
  }

  if(containsSwigInternals)
  {
    for(int i = 0; i < ret.count();)
    {
      if(ret[i].endsWith(lit(".acquire(")) || ret[i].endsWith(lit(".append(")) ||
         ret[i].endsWith(lit(".disown(")) || ret[i].endsWith(lit(".next(")) ||
         ret[i].endsWith(lit(".own(")) || ret[i].endsWith(lit(".this")) ||
         ret[i].endsWith(lit(".thisown")))
        ret.removeAt(i);
      else
        i++;
    }
  }

  Py_DecRef(completeFunction);

  PyGILState_Release(gil);

  return ret;
}
Exemple #11
0
void FetchException(QString &typeStr, QString &valueStr, int &finalLine, QList<QString> &frames)
{
  PyObject *exObj = NULL, *valueObj = NULL, *tracebackObj = NULL;

  PyErr_Fetch(&exObj, &valueObj, &tracebackObj);

  PyErr_NormalizeException(&exObj, &valueObj, &tracebackObj);

  if(exObj && PyType_Check(exObj))
  {
    PyTypeObject *type = (PyTypeObject *)exObj;

    typeStr = QString::fromUtf8(type->tp_name);
  }
  else
  {
    typeStr = QString();
  }

  if(valueObj)
    valueStr = ToQStr(valueObj);

  if(tracebackObj)
  {
    PyObject *tracebackModule = PyImport_ImportModule("traceback");

    if(tracebackModule)
    {
      PyObject *func = PyObject_GetAttrString(tracebackModule, "format_tb");

      if(func && PyCallable_Check(func))
      {
        PyObject *args = Py_BuildValue("(N)", tracebackObj);
        PyObject *formattedTB = PyObject_CallObject(func, args);

        PyTracebackObject *tb = (PyTracebackObject *)tracebackObj;

        while(tb->tb_next)
          tb = tb->tb_next;

        finalLine = tb->tb_lineno;

        if(formattedTB)
        {
          Py_ssize_t size = PyList_Size(formattedTB);
          for(Py_ssize_t i = 0; i < size; i++)
          {
            PyObject *el = PyList_GetItem(formattedTB, i);

            frames << ToQStr(el).trimmed();
          }

          Py_DecRef(formattedTB);
        }

        Py_DecRef(args);
      }
    }
  }

  Py_DecRef(exObj);
  Py_DecRef(valueObj);
  Py_DecRef(tracebackObj);
}