Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
118 changes: 72 additions & 46 deletions vkconfig_core/layer_manager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -500,6 +500,52 @@ void LayerManager::LoadAllInstalledLayers(ConfiguratorMode configurator_mode) {
this->ApplyLayerDescriptor();
}

bool LayerManager::Validate(const Path &layer_path, QString json_text, ConfiguratorMode configurator_mode) const {
JsonValidator validator;
bool result = validator.Check(json_text);

if (!result) {
switch (configurator_mode) {
default: {
} break;
case CONFIGURATOR_MODE_GUI: {
QMessageBox alert;
alert.setWindowTitle("Failed to load a layer manifest...");
alert.setText(format("%s is not a valid layer file", layer_path.AbsolutePath().c_str()).c_str());
alert.setInformativeText("Do you want to save the JSON schema validation log?");
alert.setIcon(QMessageBox::Critical);
alert.setStandardButtons(QMessageBox::Yes | QMessageBox::No);
alert.setDefaultButton(QMessageBox::Yes);
int result = alert.exec();
if (result == QMessageBox::Yes) {
const QString &selected_path = QFileDialog::getSaveFileName(
nullptr, format("Export %s validation log", layer_path.AbsolutePath().c_str()).c_str(),
(AbsolutePath(Path::HOME) + "/" + layer_path.Basename() + "_log.txt").c_str(), "Log(*.txt)");
QFile log_file(selected_path);
const bool result = log_file.open(QIODevice::WriteOnly | QIODevice::Text);
if (result) {
QDesktopServices::openUrl(QUrl::fromLocalFile(selected_path));
log_file.write(validator.message.toStdString().c_str());
log_file.close();
} else {
QMessageBox alert;
alert.setWindowTitle("Failed to save layer manifest log...");
alert.setText(format("Couldn't not open %s file...", selected_path.toStdString().c_str()).c_str());
alert.setIcon(QMessageBox::Critical);
alert.exec();
}
}
} break;
case CONFIGURATOR_MODE_CMD: {
fprintf(stderr, "vkconfig: [ERROR] Couldn't validate layer file: %s\n", layer_path.AbsolutePath().c_str());
fprintf(stderr, "\n%s\n)", validator.message.toStdString().c_str());
} break;
}
}

return result;
}

LayerLoadStatus LayerManager::LoadLayers(const Path &layer_path, LayerType type, ConfiguratorMode configurator_mode) {
const std::string &last_modified = layer_path.LastModified();
LayerDescriptor descriptor;
Expand All @@ -513,52 +559,6 @@ LayerLoadStatus LayerManager::LoadLayers(const Path &layer_path, LayerType type,
QString json_text = file.readAll();
file.close();

if (this->validate_manifests) {
JsonValidator validator;
descriptor.validated = validator.Check(json_text);

if (descriptor.validated) {
switch (configurator_mode) {
default: {
} break;
case CONFIGURATOR_MODE_GUI: {
QMessageBox alert;
alert.setWindowTitle("Failed to load a layer manifest...");
alert.setText(format("%s is not a valid layer file", layer_path.AbsolutePath().c_str()).c_str());
alert.setInformativeText("Do you want to save the validation log?");
alert.setIcon(QMessageBox::Critical);
alert.setStandardButtons(QMessageBox::Yes | QMessageBox::No);
alert.setDefaultButton(QMessageBox::Yes);
int result = alert.exec();
if (result == QMessageBox::Yes) {
const QString &selected_path = QFileDialog::getSaveFileName(
nullptr, format("Export %s validation log", layer_path.AbsolutePath().c_str()).c_str(),
(AbsolutePath(Path::HOME) + "/" + layer_path.Basename() + "_log.txt").c_str(), "Log(*.txt)");
QFile log_file(selected_path);
const bool result = log_file.open(QIODevice::WriteOnly | QIODevice::Text);
if (result) {
QDesktopServices::openUrl(QUrl::fromLocalFile(selected_path));
log_file.write(validator.message.toStdString().c_str());
log_file.close();
} else {
QMessageBox alert;
alert.setWindowTitle("Failed to save layer manifest log...");
alert.setText(format("Couldn't not open %s file...", selected_path.toStdString().c_str()).c_str());
alert.setIcon(QMessageBox::Critical);
alert.exec();
}
}
} break;
case CONFIGURATOR_MODE_CMD: {
fprintf(stderr, "vkconfig: [ERROR] Couldn't validate layer file: %s\n", layer_path.AbsolutePath().c_str());
fprintf(stderr, "\n%s\n)", validator.message.toStdString().c_str());
} break;
}
}

return LAYER_LOAD_INVALID;
}

// Convert the text to a JSON document & validate it.
// It does need to be a valid json formatted file.
QJsonParseError json_parse_error;
Expand All @@ -582,12 +582,38 @@ LayerLoadStatus LayerManager::LoadLayers(const Path &layer_path, LayerType type,

if (json_root_object.value("layers") != QJsonValue::Undefined) {
const QJsonArray &json_layers_array = json_root_object.value("layers").toArray();

for (int i = 0, n = json_layers_array.size(); i < n; ++i) {
const QJsonObject &json_layer_object = json_layers_array[i].toObject();

std::string key = ReadStringValue(json_layer_object, "name");

if (key == "VK_LAYER_LUNARG_override" || !(key.rfind("VK_", 0) == 0)) {
return LAYER_LOAD_IGNORED;
}
}

if (this->validate_manifests) {
descriptor.validated = this->Validate(layer_path, json_text, configurator_mode);
}

for (int i = 0, n = json_layers_array.size(); i < n; ++i) {
const QJsonObject &json_layer_object = json_layers_array[i].toObject();
status = this->LoadLayer(json_layer_object, layer_path, type, last_modified, file_format_version, descriptor);
}
} else if (json_root_object.value("layer") != QJsonValue::Undefined) {
const QJsonObject &json_layer_object = json_root_object.value("layer").toObject();

std::string key = ReadStringValue(json_layer_object, "name");

if (key == "VK_LAYER_LUNARG_override" || !(key.rfind("VK_", 0) == 0)) {
return LAYER_LOAD_IGNORED;
}

if (this->validate_manifests) {
descriptor.validated = this->Validate(layer_path, json_text, configurator_mode);
}

status = this->LoadLayer(json_layer_object, layer_path, type, last_modified, file_format_version, descriptor);
} else {
assert(0);
Expand Down
2 changes: 2 additions & 0 deletions vkconfig_core/layer_manager.h
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,8 @@ class LayerManager : public Serialize {
}

private:
bool Validate(const Path& layer_path, QString json_text, ConfiguratorMode configurator_mode) const;

LayerLoadStatus LoadLayer(const QJsonObject& json_layer_object, const Path& layer_path, LayerType type,
const std::string& last_modified, Version file_format_version, LayerDescriptor descriptor);

Expand Down
105 changes: 103 additions & 2 deletions vkconfig_core/layers/layers_schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,7 @@
"description": "JSON Schema for validating the Vulkan Layer Manifest Files",
"additionalProperties": true,
"required": [
"file_format_version",
"layer"
"file_format_version"
],
"definitions": {
"version": {
Expand Down Expand Up @@ -1717,6 +1716,12 @@
"file_format_version": {
"$ref": "#/definitions/version"
},
"ICD": {
"type": "object",
"additionalProperties": true,
"properties": {
}
},
"layer": {
"type": "object",
"additionalProperties": true,
Expand Down Expand Up @@ -1812,6 +1817,102 @@
}
}
}
},
"layers": {
"type": "array",
"additionalProperties": true,
"required": [
"name",
"api_version",
"implementation_version",
"description"
],
"properties": {
"name": {
"description": "The string used to uniquely identify this layer to applications.",
"type": "string",
"pattern": "^VK_LAYER_[A-Z0-9]+_[A-Za-z0-9_]+"
},
"shortcut": {
"description": "Short name used to reference a layer variable. Eg on Android: debug.vvl.validate_core instead of debug.vulkan.khronos_validation.validate_core",
"type": "string"
},
"library_path": {
"description": "The library_path specifies either a filename, a relative pathname, or a full pathname to a layer shared library file. If library_path specifies a relative pathname, it is relative to the path of the JSON manifest file (e.g. for cases when an application provides a layer that is in the same folder hierarchy as the rest of the application files). If library_path specifies a filename, the library must live in the system's shared object search path. There are no rules about the name of the layer shared library files other than it should end with the appropriate suffix (.DLL on Windows, .so on Linux, and .dylib on macOS). This field must not be present if component_layers is defined.",
"type": "string"
},
"api_version": {
"description": "The major.minor.patch version number of the Vulkan API that the shared library file for the library was built against.",
"$ref": "#/definitions/version"
},
"implementation_version": {
"description": "The version of the layer implemented. If the layer itself has any major changes, this number should change so the loader and/or application can identify it properly.",
"type": "string"
},
"description": {
"description": "A high-level description of the layer and its intended use.",
"type": "string"
},
"introduction": {
"description": "A detailed description of the layer and its intended use. Introduced with version 1.2.0.",
"type": "string"
},
"url": {
"description": "A link to the layer home page. Introduced with version 1.2.0.",
"type": "string"
},
"platforms": {
"description": "The list of platforms supported by the layer. Introduced with version 1.2.0.",
"$ref": "#/definitions/platforms"
},
"status": {
"description": "The development status of the layer. When the node is missing, the value is gathered from a parent node or set to STABLE when no parent node has defined the node. Introduced with version 1.2.0.",
"$ref": "#/definitions/status"
},
"features": {
"type": "object",
"additionalProperties": true,
"properties": {
"settings": {
"$ref": "#/definitions/settings_meta"
},
"presets": {
"type": "array",
"items": {
"required": [
"label",
"description",
"settings"
],
"additionalProperties": true,
"properties": {
"label": {
"description": "The label used to identify the preset to the user eyes.",
"type": "string"
},
"description": {
"description": "The description of the preset to example it's purpose.",
"type": "string"
},
"url": {
"description": "A url for more documentation about the preset.",
"type": "string"
},
"platforms": {
"$ref": "#/definitions/platforms"
},
"status": {
"$ref": "#/definitions/status"
},
"settings": {
"$ref": "#/definitions/settings_data"
}
}
}
}
}
}
}
}
}
}
Expand Down
Loading