51 if (!usedNames.contains(fileName, Qt::CaseInsensitive))
54 const QFileInfo fileInfo(fileName);
55 const QString stem = fileInfo.completeBaseName();
56 const QString suffix = fileInfo.suffix();
57 for (
int number = 2;; ++number) {
58 const QString candidate = QString(
"%1-%2.%3").arg(stem).arg(number).arg(suffix);
59 if (!usedNames.contains(candidate, Qt::CaseInsensitive))
64 bool copy_shader(
const QString &sourcePath,
const QString &destinationPath, QString &error) {
68 QFile source(sourcePath);
69 if (!source.open(QIODevice::ReadOnly)) {
70 error = QObject::tr(
"Could not read %1: %2").arg(sourcePath, source.errorString());
74 QSaveFile destination(destinationPath);
75 if (!destination.open(QIODevice::WriteOnly)) {
76 error = QObject::tr(
"Could not write %1: %2").arg(destinationPath, destination.errorString());
80 while (!source.atEnd()) {
81 const QByteArray block = source.read(64 * 1024);
82 if (block.isEmpty() && source.error() != QFile::NoError) {
83 error = QObject::tr(
"Could not finish reading %1: %2").arg(sourcePath, source.errorString());
84 destination.cancelWriting();
87 if (destination.write(block) != block.size()) {
88 error = QObject::tr(
"Could not finish writing %1: %2").arg(destinationPath, destination.errorString());
89 destination.cancelWriting();
94 if (!destination.commit()) {
95 error = QObject::tr(
"Could not finish writing %1: %2").arg(destinationPath, destination.errorString());
103 QStringList usedFragmentNames;
104 QStringList usedComputeNames;
105 if (!replacingLibrary) {
106 auto reserveExisting = [&](
const QDir &outputDirectory, QStringList &usedNames,
bool computeDirectory) {
107 const QStringList existingFiles = outputDirectory.entryList(QDir::Files);
108 for (
const QString &existingFile : existingFiles) {
109 const QFileInfo existingInfo(outputDirectory.filePath(existingFile));
113 const bool compute = existingInfo.suffix().compare(
"comp", Qt::CaseInsensitive) == 0;
114 if (compute != computeDirectory)
117 bool isSelectedSource =
false;
118 for (
const QString &sourcePath : sourcePaths) {
120 isSelectedSource =
true;
124 if (!isSelectedSource)
125 usedNames.append(existingFile);
128 reserveExisting(QDir(directory), usedFragmentNames,
false);
130 reserveExisting(QDir(QDir(directory).filePath(
"compute")), usedComputeNames,
true);
133 QTemporaryDir stagingDirectory;
135 result.
error = QObject::tr(
"Could not create a temporary ACMXVK manifest directory.");
139 for (
const QString &sourcePath : sourcePaths) {
140 const QFileInfo sourceInfo(sourcePath);
142 result.
error = QObject::tr(
"A source shader is now missing or unreadable:\n%1").arg(QDir::toNativeSeparators(sourcePath));
146 const bool compute = sourceInfo.suffix().compare(
"comp", Qt::CaseInsensitive) == 0;
147 QStringList &usedNames = backend ==
acmx2::Backend::Acmxvk && compute ? usedComputeNames : usedFragmentNames;
148 const QString preferredName = backend ==
acmx2::Backend::Acmxvk ? sourceInfo.completeBaseName() + (compute ? QStringLiteral(
".comp") : QStringLiteral(
".frag")) : sourceInfo.fileName();
150 const QString relativeName = backend ==
acmx2::Backend::Acmxvk && compute ? QStringLiteral(
"compute/") + exportName : exportName;
151 const QString destinationPath = QDir(directory).filePath(relativeName);
152 if (!QDir().mkpath(QFileInfo(destinationPath).absolutePath())) {
153 result.
error = QObject::tr(
"Could not create shader directory: %1").arg(QFileInfo(destinationPath).absolutePath());
159 usedNames.append(exportName);
162 const QString stagingPath = QDir(stagingDirectory.path()).filePath(relativeName);
163 if (!QDir().mkpath(QFileInfo(stagingPath).absolutePath())) {
164 result.
error = QObject::tr(
"Could not create temporary shader directory: %1").arg(QFileInfo(stagingPath).absolutePath());