ACMX 2.136.0
Dual-Backend Real-Time GPU Video Synthesis
Loading...
Searching...
No Matches
acmxvk-source-manifest-test.cpp
Go to the documentation of this file.
2#include "shader-manifest.hpp"
3
4#include <QDir>
5#include <QFile>
6#include <QFileInfo>
7#include <QJsonArray>
8#include <QJsonDocument>
9#include <QJsonObject>
10#include <QTemporaryDir>
11#include <iostream>
12
13namespace {
14 bool write_file(const QString &path, const QByteArray &contents) {
15 if (!QDir().mkpath(QFileInfo(path).absolutePath()))
16 return false;
17 QFile file(path);
18 return file.open(QIODevice::WriteOnly) &&
19 file.write(contents) == contents.size();
20 }
21
22 QJsonObject read_manifest(const QString &path) {
23 QFile file(path);
24 if (!file.open(QIODevice::ReadOnly))
25 return {};
26 return QJsonDocument::fromJson(file.readAll()).object();
27 }
28} // namespace
29
30int main() {
31 QTemporaryDir temporary;
32 if (!temporary.isValid())
33 return 1;
34 const QString root = temporary.path();
35 if (!write_file(QDir(root).filePath(QStringLiteral("z.frag")),
36 QByteArrayLiteral("#version 450\n")) ||
37 !write_file(QDir(root).filePath(QStringLiteral("a.frag")),
38 QByteArrayLiteral(
39 "#define slider1 ext.custom_uniforms[5].x\n")) ||
40 !write_file(QDir(root).filePath(QStringLiteral("compute/fx.comp")),
41 QByteArrayLiteral("#version 450\n"))) {
42 return 2;
43 }
44
46 QString error;
47 if (!acmx2::create_acmxvk_source_manifest(root, QString(), result, error)) {
48 std::cerr << error.toStdString() << '\n';
49 return 3;
50 }
51 if (result.fragmentCount != 2 || result.computeCount != 1 ||
52 result.customUniformCount != 27) {
53 return 4;
54 }
55
56 const QString manifestPath = QDir(root).filePath(QStringLiteral("library.json"));
57 QJsonObject manifest = read_manifest(manifestPath);
58 const QJsonArray shaders = manifest.value(QStringLiteral("shaders")).toArray();
59 if (manifest.value(QStringLiteral("backend")).toString() !=
60 QStringLiteral("acmxvk") ||
61 manifest.value(QStringLiteral("library_type")).toString() !=
62 QStringLiteral("source") ||
63 shaders.size() != 3 || shaders.at(0).toString() != QStringLiteral("a.frag") ||
64 shaders.at(2).toString() != QStringLiteral("compute/fx.comp")) {
65 return 5;
66 }
67
68 QJsonObject uniforms =
69 manifest.value(QStringLiteral("custom_uniforms")).toObject();
70 QJsonObject slider = uniforms.value(QStringLiteral("slider1")).toObject();
71 slider.insert(QStringLiteral("value"), 0.75);
72 slider.insert(QStringLiteral("maximum"), 2.0);
73 uniforms.insert(QStringLiteral("slider1"), slider);
74 manifest.insert(QStringLiteral("custom_uniforms"), uniforms);
75 if (!write_file(manifestPath,
76 QJsonDocument(manifest).toJson(QJsonDocument::Indented))) {
77 return 6;
78 }
79 if (!acmx2::create_acmxvk_source_manifest(root, QString(), result, error)) {
80 std::cerr << error.toStdString() << '\n';
81 return 7;
82 }
83 slider = read_manifest(manifestPath)
84 .value(QStringLiteral("custom_uniforms"))
85 .toObject()
86 .value(QStringLiteral("slider1"))
87 .toObject();
88 if (slider.value(QStringLiteral("slot")).toInt() != 20 ||
89 slider.value(QStringLiteral("value")).toDouble() != 0.75 ||
90 slider.value(QStringLiteral("maximum")).toDouble() != 2.0) {
91 return 8;
92 }
93
94 if (!acmx2::remove_shader_manifest_entry(root, QStringLiteral("z.frag"),
95 error)) {
96 std::cerr << error.toStdString() << '\n';
97 return 9;
98 }
99 QStringList remainingShaders;
100 if (!acmx2::load_shader_manifest(root, remainingShaders, error) ||
101 remainingShaders.contains(QStringLiteral("z.frag"),
102 Qt::CaseInsensitive) ||
103 !QFileInfo::exists(QDir(root).filePath(QStringLiteral("z.frag")))) {
104 return 10;
105 }
106 if (!write_file(QDir(root).filePath(QStringLiteral("new.frag")),
107 QByteArrayLiteral("#version 450\n"))) {
108 return 11;
109 }
110 remainingShaders.append(QStringLiteral("new.frag"));
112 root, remainingShaders, QString(), result, error)) {
113 std::cerr << error.toStdString() << '\n';
114 return 12;
115 }
116 remainingShaders.clear();
117 if (!acmx2::load_shader_manifest(root, remainingShaders, error) ||
118 remainingShaders.contains(QStringLiteral("z.frag"),
119 Qt::CaseInsensitive) ||
120 !remainingShaders.contains(QStringLiteral("new.frag"),
121 Qt::CaseInsensitive)) {
122 return 13;
123 }
124
125 QList<acmx2::CustomUniformDefinition> customUniforms;
126 if (!acmx2::load_custom_uniforms(root, customUniforms, error) ||
127 customUniforms.size() != 27) {
128 return 14;
129 }
130 customUniforms.append({QStringLiteral("custom_knob"), 0.0, 2.0, 0.1,
131 1.0, 27});
132 if (!acmx2::write_custom_uniforms(root, customUniforms, error)) {
133 std::cerr << error.toStdString() << '\n';
134 return 15;
135 }
136 QJsonObject writtenUniforms =
137 read_manifest(manifestPath)
138 .value(QStringLiteral("custom_uniforms"))
139 .toObject();
140 if (writtenUniforms.value(QStringLiteral("custom_knob"))
141 .toObject()
142 .value(QStringLiteral("slot"))
143 .toInt(-1) != 27) {
144 return 16;
145 }
146
147 customUniforms.removeLast();
148 if (!acmx2::write_custom_uniforms(root, customUniforms, error) ||
149 read_manifest(manifestPath)
150 .value(QStringLiteral("custom_uniforms"))
151 .toObject()
152 .contains(QStringLiteral("custom_knob"))) {
153 return 17;
154 }
155
156 while (customUniforms.size() < 65) {
157 const int slot = customUniforms.size();
158 customUniforms.append(
159 {QStringLiteral("extra_%1").arg(slot), 0.0, 1.0, 0.01, 0.0,
160 slot});
161 }
162 if (acmx2::write_custom_uniforms(root, customUniforms, error) ||
163 !error.contains(QStringLiteral("at most 64"))) {
164 return 18;
165 }
166
167 QTemporaryDir runtimeDirectory;
168 if (!runtimeDirectory.isValid())
169 return 19;
170 QJsonObject runtimeManifest = read_manifest(manifestPath);
171 QJsonObject runtimeUniforms =
172 runtimeManifest.value(QStringLiteral("custom_uniforms")).toObject();
173 QJsonObject runtimeSlider =
174 runtimeUniforms.value(QStringLiteral("slider1")).toObject();
175 runtimeSlider.insert(QStringLiteral("value"), 0.75000000000001);
176 runtimeUniforms.insert(QStringLiteral("slider1"), runtimeSlider);
177 runtimeManifest.insert(QStringLiteral("custom_uniforms"), runtimeUniforms);
178 if (!write_file(QDir(runtimeDirectory.path())
179 .filePath(QStringLiteral("library.json")),
180 QJsonDocument(runtimeManifest)
181 .toJson(QJsonDocument::Indented))) {
182 return 20;
183 }
184 bool metadataMatches = false;
186 root, runtimeDirectory.path(), metadataMatches, error) ||
187 !metadataMatches) {
188 return 21;
189 }
190 runtimeSlider.insert(QStringLiteral("value"), 0.8);
191 runtimeUniforms.insert(QStringLiteral("slider1"), runtimeSlider);
192 runtimeManifest.insert(QStringLiteral("custom_uniforms"), runtimeUniforms);
193 if (!write_file(QDir(runtimeDirectory.path())
194 .filePath(QStringLiteral("library.json")),
195 QJsonDocument(runtimeManifest)
196 .toJson(QJsonDocument::Indented)) ||
198 root, runtimeDirectory.path(), metadataMatches, error) ||
199 metadataMatches) {
200 return 22;
201 }
202 return 0;
203}
int main(int argc, char **argv)
Application entry point.
bool custom_uniform_metadata_matches(const QString &leftDirectory, const QString &rightDirectory, bool &matches, QString &error)
Compare two manifests' custom-uniform ABI and numeric metadata.
bool create_acmxvk_source_manifest_for_shaders(const QString &rootDirectory, const QStringList &shaderFiles, const QString &outputPath, AcmxvkSourceManifestResult &result, QString &error)
Generate a source manifest from an explicit subset of files below root.
bool load_custom_uniforms(const QString &directory, QList< CustomUniformDefinition > &uniforms, QString &error)
Load custom float-uniform controls from library.json.
bool create_acmxvk_source_manifest(const QString &rootDirectory, const QString &outputPath, AcmxvkSourceManifestResult &result, QString &error)
Scan an ACMXVK source tree and atomically generate its library.json.
bool remove_shader_manifest_entry(const QString &directory, const QString &shader, QString &error)
Remove one shader from the preferred manifest, without deleting its file.
bool load_shader_manifest(const QString &directory, QStringList &shaders, QString &error)
Load shader filenames from the preferred manifest in a directory.
bool write_custom_uniforms(const QString &directory, const QList< CustomUniformDefinition > &uniforms, QString &error)
Rewrite custom float-uniform controls while preserving all other JSON fields.
bool write_file(const QString &path, const QByteArray &contents)
Optional JSON and legacy text shader-library manifests.