Ejemplo n.º 1
0
void CaptureContext::LoadLogfile(const QString &logFile, const QString &origFilename,
                                 bool temporary, bool local)
{
  m_Progress = new QProgressDialog(QString("Loading Log"), QString(), 0, 1000, m_MainWindow);
  m_Progress->setWindowTitle("Please Wait");
  m_Progress->setWindowFlags(Qt::CustomizeWindowHint | Qt::Dialog | Qt::WindowTitleHint);
  m_Progress->setWindowIcon(QIcon());
  m_Progress->setMinimumSize(QSize(250, 0));
  m_Progress->setMaximumSize(QSize(250, 10000));
  m_Progress->setCancelButton(NULL);
  m_Progress->setMinimumDuration(0);
  m_Progress->setWindowModality(Qt::ApplicationModal);
  m_Progress->setValue(0);

  QLabel *label = new QLabel(m_Progress);

  label->setText(QString("Loading Log: %1").arg(origFilename));
  label->setAlignment(Qt::AlignCenter);
  label->setWordWrap(true);

  m_Progress->setLabel(label);

  LambdaThread *thread = new LambdaThread([this, logFile, origFilename, temporary, local]() {
    LoadLogfileThreaded(logFile, origFilename, temporary, local);

    GUIInvoke::call([this, origFilename]() {
      delete m_Progress;
      m_Progress = NULL;
    });
  });
  thread->selfDelete(true);
  thread->start();
}
Ejemplo n.º 2
0
void CaptureDialog::CheckAndroidSetup(QString &filename)
{
  ui->androidScan->setVisible(true);
  ui->androidWarn->setVisible(false);

  LambdaThread *scan = new LambdaThread([this, filename]() {

    rdcstr host = m_Ctx.Replay().CurrentRemote()->hostname;
    RENDERDOC_CheckAndroidPackage(host.c_str(), filename.toUtf8().data(), &m_AndroidFlags);

    const bool debuggable = bool(m_AndroidFlags & AndroidFlags::Debuggable);
    const bool hasroot = bool(m_AndroidFlags & AndroidFlags::RootAccess);

    if(!debuggable && !hasroot)
    {
      // Check failed - set the warning visible
      GUIInvoke::call([this]() {
        ui->androidScan->setVisible(false);
        ui->androidWarn->setVisible(true);
      });
    }
    else
    {
      // Check passed, either app is debuggable or we have root - no warnings needed
      GUIInvoke::call([this]() {
        ui->androidScan->setVisible(false);
        ui->androidWarn->setVisible(false);
      });
    }
  });

  scan->start();
  scan->deleteLater();
}
Ejemplo n.º 3
0
void MainWindow::on_action_Open_Log_triggered()
{
	QString filename = QFileDialog::getOpenFileName(this,
		"Select Logfile to open",
		"",
		"Log Files (*.rdc);;Image Files (*.dds *.hdr *.exr *.bmp *.jpg *.jpeg *.png *.tga *.gif *.psd;;All Files (*.*)");

	QFileInfo checkFile(filename);
	if(filename != "" && checkFile.exists() && checkFile.isFile())
	{
		LambdaThread *thread = new LambdaThread([filename, this]() {
			m_Core->LoadLogfile(filename, false);
		});
		thread->start();
	}
}
Ejemplo n.º 4
0
void MainWindow::on_action_Resolve_Symbols_triggered()
{
  m_Ctx->Renderer()->AsyncInvoke([this](IReplayRenderer *r) { r->InitResolver(); });

  QProgressDialog *m_Progress =
      new QProgressDialog(tr("Please Wait - Resolving Symbols"), QString(), 0, 0, this);
  m_Progress->setWindowTitle("Please Wait");
  m_Progress->setWindowFlags(Qt::CustomizeWindowHint | Qt::Dialog | Qt::WindowTitleHint);
  m_Progress->setWindowIcon(QIcon());
  m_Progress->setMinimumSize(QSize(250, 0));
  m_Progress->setMaximumSize(QSize(250, 10000));
  m_Progress->setCancelButton(NULL);
  m_Progress->setMinimumDuration(0);
  m_Progress->setWindowModality(Qt::ApplicationModal);
  m_Progress->setValue(0);

  QLabel *label = new QLabel(m_Progress);

  label->setText(tr("Please Wait - Resolving Symbols"));
  label->setAlignment(Qt::AlignCenter);
  label->setWordWrap(true);

  m_Progress->setLabel(label);

  LambdaThread *thread = new LambdaThread([this, m_Progress]() {
    bool running = true;

    while(running)
    {
      // just bail if we managed to get here without a resolver.
      m_Ctx->Renderer()->BlockInvoke(
          [&running](IReplayRenderer *r) { running = r->HasCallstacks() && !r->InitResolver(); });
    }

    GUIInvoke::call([this, m_Progress]() {
      m_Progress->hide();
      delete m_Progress;
      if(m_Ctx->hasAPIInspector())
        m_Ctx->apiInspector()->on_apiEvents_itemSelectionChanged();
    });
  });
  thread->selfDelete(true);
  thread->start();
}
Ejemplo n.º 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();
    }
  }
}
Ejemplo n.º 6
0
void RemoteManager::refreshHost(RDTreeWidgetItem *node)
{
  RemoteHost *host = getRemoteHost(node);

  if(!host)
    return;

  // this function looks up the remote connections and for each one open
  // queries it for the API, target (usually executable name) and if any user is already connected
  LambdaThread *th = new LambdaThread([this, node, host]() {
    QByteArray username = GetSystemUsername().toUtf8();

    host->CheckStatus();

    GUIInvoke::call(
        [this, node, host]() { setRemoteServerLive(node, host->serverRunning, host->busy); });

    uint32_t nextIdent = 0;

    for(;;)
    {
      // just a sanity check to make sure we don't hit some unexpected case and infinite loop
      uint32_t prevIdent = nextIdent;

      nextIdent = RENDERDOC_EnumerateRemoteTargets(host->hostname.c_str(), nextIdent);

      if(nextIdent == 0 || prevIdent >= nextIdent)
        break;

      ITargetControl *conn =
          RENDERDOC_CreateTargetControl(host->hostname.c_str(), nextIdent, username.data(), false);

      if(conn)
      {
        QString target = QString::fromUtf8(conn->GetTarget());
        QString api = QString::fromUtf8(conn->GetAPI());
        QString busy = QString::fromUtf8(conn->GetBusyClient());

        QString running;

        if(!busy.isEmpty())
          running = tr("Running %1, %2 is connected").arg(api).arg(busy);
        else
          running = tr("Running %1").arg(api);

        RemoteConnect tag(host->hostname, host->Name(), nextIdent);

        GUIInvoke::call([this, node, target, running, tag]() {
          RDTreeWidgetItem *child = new RDTreeWidgetItem({target, running});
          setRemoteConnect(child, tag);
          node->addChild(child);
          ui->hosts->expandItem(node);
        });

        conn->Shutdown();
      }
    }

    GUIInvoke::call([node]() { node->setItalic(false); });

    m_Lookups.acquire();

    GUIInvoke::call([this]() { updateStatus(); });
  });
  th->selfDelete(true);
  th->start();
}
Ejemplo n.º 7
0
void CaptureContext::RecompressCapture()
{
  QString destFilename = GetCaptureFilename();
  QString tempFilename;

  ICaptureFile *cap = NULL;
  ICaptureFile *tempCap = NULL;

  bool inplace = false;

  if(IsCaptureTemporary() || !IsCaptureLocal())
  {
    QMessageBox::StandardButton res =
        RDDialog::question(m_MainWindow, tr("Unsaved capture"),
                           tr("To recompress a capture you must save it first. Save this capture?"),
                           QMessageBox::Yes | QMessageBox::No | QMessageBox::Cancel);

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

    destFilename = m_MainWindow->GetSavePath();

    // if it's already local, we'll do the save as part of the recompression convert. If it's
    // remote, we need to copy it first, but we copy it to a temporary so we can do the conversion
    // to the target location

    if(IsCaptureLocal())
    {
      tempFilename = GetCaptureFilename();
    }
    else
    {
      tempFilename = TempCaptureFilename(lit("recompress"));
      Replay().CopyCaptureFromRemote(GetCaptureFilename(), tempFilename, m_MainWindow);

      if(!QFile::exists(tempFilename))
      {
        RDDialog::critical(m_MainWindow, tr("Failed to save capture"),
                           tr("Capture couldn't be saved from remote."));
        return;
      }
    }
  }
  else
  {
    // if we're doing this inplace on an already saved capture, then we need to recompress to a
    // temporary and close/move it afterwards.
    inplace = true;
    destFilename = TempCaptureFilename(lit("recompress"));
  }

  if(IsCaptureLocal())
  {
    // for local files we already have a handle. We'll reuse it, then re-open
    cap = Replay().GetCaptureFile();
  }
  else
  {
    // for remote files we open a new short-lived handle on the temporary file
    tempCap = cap = RENDERDOC_OpenCaptureFile();
    cap->OpenFile(tempFilename.toUtf8().data(), "rdc");
  }

  if(!cap)
  {
    RDDialog::critical(m_MainWindow, tr("Unexpected missing handle"),
                       tr("Couldn't get open handle to file for recompression."));
    return;
  }

  int index = cap->FindSectionByType(SectionType::FrameCapture);
  SectionProperties props = cap->GetSectionProperties(index);

  if(props.flags & SectionFlags::ZstdCompressed)
  {
    RDDialog::information(m_MainWindow, tr("Capture already compressed"),
                          tr("This capture is already compressed as much as is possible."));

    if(tempCap)
      tempCap->Shutdown();
    if(!tempFilename.isEmpty())
      QFile::remove(tempFilename);
    return;
  }

  // convert from the currently open cap to the destination
  float progress = 0.0f;

  LambdaThread *th = new LambdaThread([this, cap, destFilename, &progress]() {
    cap->Convert(destFilename.toUtf8().data(), "rdc", [&progress](float p) { progress = p; });
  });
  th->start();
  // wait a few ms before popping up a progress bar
  th->wait(500);
  if(th->isRunning())
  {
    ShowProgressDialog(m_MainWindow, tr("Recompressing file."), [th]() { return !th->isRunning(); },
                       [&progress]() { return progress; });
  }
  th->deleteLater();

  if(inplace)
  {
    // if we're recompressing "in place", we need to close our capture, move the temporary over
    // the original, then re-open.

    // this releases the hold over the real desired location.
    cap->OpenFile("", "");

    // now remove the old capture
    QFile::remove(GetCaptureFilename());

    // move the recompressed one over
    QFile::rename(destFilename, GetCaptureFilename());

    // and re-open
    cap->OpenFile(GetCaptureFilename().c_str(), "rdc");
  }
  else
  {
    // we've converted into the desired location. We don't have to do anything else but mark our
    // new locally saved non-temporary status.

    m_CaptureFile = destFilename;
    m_CaptureLocal = true;
    m_CaptureTemporary = false;

    // open the saved capture file. This will let us remove the old file too
    Replay().ReopenCaptureFile(m_CaptureFile);

    m_CaptureMods = CaptureModifications::All;

    SaveChanges();
  }

  // close any temporary resources
  if(tempCap)
    tempCap->Shutdown();
  if(!tempFilename.isEmpty())
    QFile::remove(tempFilename);
}
Ejemplo n.º 8
0
void CaptureContext::LoadCapture(const rdcstr &captureFile, const rdcstr &origFilename,
                                 bool temporary, bool local)
{
  m_LoadInProgress = true;

  if(local)
    m_Config.CrashReport_LastOpenedCapture = origFilename;

  bool newCapture = (!temporary && !Config().RecentCaptureFiles.contains(origFilename));

  LambdaThread *thread = new LambdaThread([this, captureFile, origFilename, temporary, local]() {
    LoadCaptureThreaded(captureFile, origFilename, temporary, local);
  });
  thread->selfDelete(true);
  thread->start();

  QElapsedTimer loadTimer;
  loadTimer.start();

  ShowProgressDialog(m_MainWindow, tr("Loading Capture: %1").arg(origFilename),
                     [this]() { return !m_LoadInProgress; },
                     [this]() { return UpdateLoadProgress(); });

  ANALYTIC_ADDAVG(Performance.LoadTime, double(loadTimer.nsecsElapsed() * 1.0e-9));

  ANALYTIC_SET(CaptureFeatures.ShaderLinkage, m_APIProps.ShaderLinkage);
  ANALYTIC_SET(CaptureFeatures.YUVTextures, m_APIProps.YUVTextures);
  ANALYTIC_SET(CaptureFeatures.SparseResources, m_APIProps.SparseResources);
  ANALYTIC_SET(CaptureFeatures.MultiGPU, m_APIProps.MultiGPU);
  ANALYTIC_SET(CaptureFeatures.D3D12Bundle, m_APIProps.D3D12Bundle);

  m_MainWindow->setProgress(-1.0f);

  if(m_CaptureLoaded)
  {
    m_CaptureTemporary = temporary;

    m_CaptureMods = CaptureModifications::NoModifications;

    rdcarray<ICaptureViewer *> viewers(m_CaptureViewers);

    // make sure we're on a consistent event before invoking viewer forms
    if(m_LastDrawcall)
      SetEventID(viewers, m_LastDrawcall->eventId, true);
    else if(!m_Drawcalls.empty())
      SetEventID(viewers, m_Drawcalls.back().eventId, true);

    GUIInvoke::blockcall([&viewers]() {
      // notify all the registers viewers that a capture has been loaded
      for(ICaptureViewer *viewer : viewers)
      {
        if(viewer)
          viewer->OnCaptureLoaded();
      }
    });

    if(newCapture && m_Notes.contains(lit("comments")))
    {
      if(!HasCommentView())
        ShowCommentView();
      RaiseDockWindow(GetCommentView()->Widget());
    }
  }
}
Ejemplo n.º 9
0
bool RunProcessAsAdmin(const QString &fullExecutablePath, const QStringList &params,
                       std::function<void()> finishedCallback)
{
#if defined(Q_OS_WIN32)

  std::wstring wideExe = fullExecutablePath.toStdWString();
  std::wstring wideParams = params.join(QChar(' ')).toStdWString();

  SHELLEXECUTEINFOW info = {};
  info.cbSize = sizeof(info);
  info.fMask = SEE_MASK_NOCLOSEPROCESS;
  info.lpVerb = L"runas";
  info.lpFile = wideExe.c_str();
  info.lpParameters = wideParams.c_str();
  info.nShow = SW_SHOWNORMAL;

  ShellExecuteExW(&info);

  if((uintptr_t)info.hInstApp > 32 && info.hProcess != NULL)
  {
    if(finishedCallback)
    {
      HANDLE h = info.hProcess;

      // do the wait on another thread
      LambdaThread *thread = new LambdaThread([h, finishedCallback]() {
        WaitForSingleObject(h, 30000);
        CloseHandle(h);
        GUIInvoke::call(finishedCallback);
      });
      thread->selfDelete(true);
      thread->start();
    }
    else
    {
      CloseHandle(info.hProcess);
    }

    return true;
  }

  return false;

#else
  // try to find a way to run the application elevated.
  const QString graphicalSudo[] = {
      "pkexec", "kdesudo", "gksudo", "beesu",
  };

  // if none of the graphical options, then look for sudo and either
  const QString termEmulator[] = {
      "x-terminal-emulator", "gnome-terminal", "knosole", "xterm",
  };

  for(const QString &sudo : graphicalSudo)
  {
    QString inPath = QStandardPaths::findExecutable(sudo);

    // can't find in path
    if(inPath.isEmpty())
      continue;

    QProcess *process = new QProcess;

    QStringList sudoParams;
    sudoParams << fullExecutablePath;
    for(const QString &p : params)
      sudoParams << p;

    qInfo() << "Running" << sudo << "with params" << sudoParams;

    // run with sudo
    process->start(sudo, sudoParams);

    // when the process exits, call the callback and delete
    QObject::connect(process, OverloadedSlot<int>::of(&QProcess::finished),
                     [process, finishedCallback](int exitCode) {
                       process->deleteLater();
                       GUIInvoke::call(finishedCallback);
                     });

    return true;
  }

  QString sudo = QStandardPaths::findExecutable("sudo");

  if(sudo.isEmpty())
  {
    qCritical() << "Couldn't find graphical or terminal sudo program!\n"
                << "Please run " << fullExecutablePath << "with args" << params << "manually.";
    return false;
  }

  for(const QString &term : termEmulator)
  {
    QString inPath = QStandardPaths::findExecutable(term);

    // can't find in path
    if(inPath.isEmpty())
      continue;

    QProcess *process = new QProcess;

    // run terminal sudo with emulator
    QStringList termParams;
    termParams << "-e"
               << QString("bash -c 'sudo %1 %2'").arg(fullExecutablePath).arg(params.join(QChar(' ')));

    process->start(term, termParams);

    // when the process exits, call the callback and delete
    QObject::connect(process, OverloadedSlot<int>::of(&QProcess::finished),
                     [process, finishedCallback](int exitCode) {
                       process->deleteLater();
                       GUIInvoke::call(finishedCallback);
                     });

    return true;
  }

  qCritical() << "Couldn't find graphical or terminal emulator to launch sudo.\n"
              << "Please run " << fullExecutablePath << "with args" << params << "manually.";

  return false;
#endif
}