Пример #1
0
QStringList Retracer::retraceArguments() const
{
    QStringList arguments;

    if (m_singlethread) {
        arguments << QLatin1String("--singlethread");
    }

    if (m_useCoreProfile) {
        arguments << QLatin1String("--core");
    }

    if (m_captureState) {
        arguments << QLatin1String("-D");
        arguments << QString::number(m_captureCall);
        arguments << QLatin1String("--dump-format");
        arguments << QLatin1String("ubjson");
    } else if (m_captureThumbnails) {
        if (!m_thumbnailsToCapture.isEmpty()) {
            arguments << QLatin1String("-S");
            arguments << thumbnailCallSet();
        }
        arguments << QLatin1String("-s"); // emit snapshots
        arguments << QLatin1String("-"); // emit to stdout
    } else if (isProfiling()) {
        if (m_profileGpu) {
            arguments << QLatin1String("--pgpu");
        }

        if (m_profileCpu) {
            arguments << QLatin1String("--pcpu");
        }

        if (m_profilePixels) {
            arguments << QLatin1String("--ppd");
        }

        if (m_profileMemory) {
            arguments << QLatin1String("--pmem");
        }
    } else {
        if (!m_doubleBuffered) {
            arguments << QLatin1String("--sb");
        }

        if (m_benchmarking) {
            arguments << QLatin1String("-b");
        } else {
            arguments << QLatin1String("-d");
        }
    }
    return arguments;
}
Пример #2
0
/**
 * Starting point for the retracing thread.
 *
 * Overrides QThread::run().
 */
void Retracer::run()
{
    QString msg = QLatin1String("Replay finished!");

    /*
     * Construct command line
     */

    QString prog;
    QStringList arguments;

    switch (m_api) {
    case trace::API_GL:
        prog = QLatin1String("glretrace");
        break;
    case trace::API_EGL:
        prog = QLatin1String("eglretrace");
        break;
    case trace::API_DX:
    case trace::API_D3D7:
    case trace::API_D3D8:
    case trace::API_D3D9:
    case trace::API_DXGI:
#ifdef Q_OS_WIN
        prog = QLatin1String("d3dretrace");
#else
        prog = QLatin1String("wine");
        arguments << QLatin1String("d3dretrace.exe");
#endif
        break;
    default:
        emit finished(QLatin1String("Unsupported API"));
        return;
    }

    if (m_singlethread) {
        arguments << QLatin1String("--singlethread");
    }

    if (m_useCoreProfile) {
        arguments << QLatin1String("--core");
    }

    if (!m_msaaResolve) {
        arguments << QLatin1String("--msaa-no-resolve");
    }

    if (m_captureState) {
        arguments << QLatin1String("-D");
        arguments << QString::number(m_captureCall);
        arguments << QLatin1String("--dump-format");
        arguments << QLatin1String("ubjson");
    } else if (m_captureThumbnails) {
        if (!m_thumbnailsToCapture.isEmpty()) {
            arguments << QLatin1String("-S");
            arguments << thumbnailCallSet();
        }
        arguments << QLatin1String("-s"); // emit snapshots
        arguments << QLatin1String("-"); // emit to stdout
    } else if (isProfiling()) {
        if (m_profileGpu) {
            arguments << QLatin1String("--pgpu");
        }

        if (m_profileCpu) {
            arguments << QLatin1String("--pcpu");
        }

        if (m_profilePixels) {
            arguments << QLatin1String("--ppd");
        }
    } else {
        if (!m_doubleBuffered) {
            arguments << QLatin1String("--sb");
        }

        if (m_benchmarking) {
            arguments << QLatin1String("-b");
        }
    }

    arguments << m_fileName;

    /*
     * Support remote execution on a separate target.
     */

    if (m_remoteTarget.length() != 0) {
        arguments.prepend(prog);
        arguments.prepend(m_remoteTarget);
        prog = QLatin1String("ssh");
    }

    /*
     * Start the process.
     */

    {
        QDebug debug(QtDebugMsg);
        debug << "Running:";
        debug << prog;
        foreach (const QString &argument, arguments) {
            debug << argument;
        }
    }

    QProcess process;

    process.start(prog, arguments, QIODevice::ReadOnly);
    if (!process.waitForStarted(-1)) {
        emit finished(QLatin1String("Could not start process"));
        return;
    }

    /*
     * Process standard output
     */

    ImageHash thumbnails;
    QVariantMap parsedJson;
    trace::Profile* profile = NULL;

    process.setReadChannel(QProcess::StandardOutput);
    if (process.waitForReadyRead(-1)) {
        BlockingIODevice io(&process);

        if (m_captureState) {
            parsedJson = decodeUBJSONObject(&io).toMap();
            process.waitForFinished(-1);
        } else if (m_captureThumbnails) {
            /*
             * Parse concatenated PNM images from output.
             */

            while (!io.atEnd()) {
                image::PNMInfo info;

                char header[512];
                qint64 headerSize = 0;
                int headerLines = 3; // assume no optional comment line

                for (int headerLine = 0; headerLine < headerLines; ++headerLine) {
                    qint64 headerRead = io.readLine(&header[headerSize], sizeof(header) - headerSize);

                    // if header actually contains optional comment line, ...
                    if (headerLine == 1 && header[headerSize] == '#') {
                        ++headerLines;
                    }

                    headerSize += headerRead;
                }

                const char *headerEnd = image::readPNMHeader(header, headerSize, info);

                // if invalid PNM header was encountered, ...
                if (headerEnd == NULL ||
                    info.channelType != image::TYPE_UNORM8) {
                    qDebug() << "error: invalid snapshot stream encountered";
                    break;
                }

                unsigned channels = info.channels;
                unsigned width = info.width;
                unsigned height = info.height;

                // qDebug() << "channels: " << channels << ", width: " << width << ", height: " << height";

                QImage snapshot = QImage(width, height, channels == 1 ? QImage::Format_Mono : QImage::Format_RGB888);

                int rowBytes = channels * width;
                for (int y = 0; y < height; ++y) {
                    unsigned char *scanLine = snapshot.scanLine(y);
                    qint64 readBytes = io.read((char *) scanLine, rowBytes);
                    Q_ASSERT(readBytes == rowBytes);
                    (void)readBytes;
                }

                QImage thumb = thumbnail(snapshot);
                thumbnails.insert(info.commentNumber, thumb);
            }

            Q_ASSERT(process.state() != QProcess::Running);
        } else if (isProfiling()) {
            profile = new trace::Profile();

            while (!io.atEnd()) {
                char line[256];
                qint64 lineLength;

                lineLength = io.readLine(line, 256);

                if (lineLength == -1)
                    break;

                trace::Profiler::parseLine(line, profile);
            }
        } else {
            QByteArray output;
            output = process.readAllStandardOutput();
            if (output.length() < 80) {
                msg = QString::fromUtf8(output);
            }
        }
    }

    /*
     * Wait for process termination
     */

    process.waitForFinished(-1);

    if (process.exitStatus() != QProcess::NormalExit) {
        msg = QLatin1String("Process crashed");
    } else if (process.exitCode() != 0) {
        msg = QLatin1String("Process exited with non zero exit code");
    }

    /*
     * Parse errors.
     */

    QList<ApiTraceError> errors;
    process.setReadChannel(QProcess::StandardError);
    QRegExp regexp("(^\\d+): +(\\b\\w+\\b): ([^\\r\\n]+)[\\r\\n]*$");
    while (!process.atEnd()) {
        QString line = process.readLine();
        if (regexp.indexIn(line) != -1) {
            ApiTraceError error;
            error.callIndex = regexp.cap(1).toInt();
            error.type = regexp.cap(2);
            error.message = regexp.cap(3);
            errors.append(error);
        } else if (!errors.isEmpty()) {
            // Probably a multiligne message
            ApiTraceError &previous = errors.last();
            if (line.endsWith("\n")) {
                line.chop(1);
            }
            previous.message.append('\n');
            previous.message.append(line);
        }
    }

    /*
     * Emit signals
     */

    if (m_captureState) {
        ApiTraceState *state = new ApiTraceState(parsedJson);
        emit foundState(state);
    }

    if (m_captureThumbnails && !thumbnails.isEmpty()) {
        emit foundThumbnails(thumbnails);
    }

    if (isProfiling() && profile) {
        emit foundProfile(profile);
    }

    if (!errors.isEmpty()) {
        emit retraceErrors(errors);
    }

    emit finished(msg);
}