Validate packaged P3 shaders and describe bounded shadow atlases
This commit is contained in:
@@ -375,7 +375,10 @@ bool validate_build_generation(const fs::path& directory, const std::string& pac
|
|||||||
return false;
|
return false;
|
||||||
for (const auto* shader : {"vertexMain", "fragmentMain", "shadowMain",
|
for (const auto* shader : {"vertexMain", "fragmentMain", "shadowMain",
|
||||||
"gpuVertexMain", "gpuShadowMain", "gpuCullMain",
|
"gpuVertexMain", "gpuShadowMain", "gpuCullMain",
|
||||||
"gpuHzbMain", "gpuPostCullMain"})
|
"gpuHzbMain", "gpuPostCullMain", "lightTileMain",
|
||||||
|
"temporalResolveMain", "temporalCompositeVertexMain",
|
||||||
|
"temporalCompositeFragmentMain", "temporalVertexMain",
|
||||||
|
"temporalFragmentMain", "gpuTemporalVertexMain"})
|
||||||
for (const auto* extension : {".spv", ".reflection.json"})
|
for (const auto* extension : {".spv", ".reflection.json"})
|
||||||
if (!expected.contains("shaders/" + std::string(shader) + extension))
|
if (!expected.contains("shaders/" + std::string(shader) + extension))
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
@@ -920,7 +920,12 @@ struct BuildService::Impl {
|
|||||||
{"required_features", {"dynamicRendering", "synchronization2"}},
|
{"required_features", {"dynamicRendering", "synchronization2"}},
|
||||||
{"materials", {"base-color factor and texture", "metallic and roughness factors"}},
|
{"materials", {"base-color factor and texture", "metallic and roughness factors"}},
|
||||||
{"texture_sampling", "linear clamp, one mip level"},
|
{"texture_sampling", "linear clamp, one mip level"},
|
||||||
{"shadow_map", {{"resolution", 1024}, {"world_extent", 40}}},
|
{"shadow_atlases", {{"sun_cascade_limit", 4},
|
||||||
|
{"local_face_limit", 16},
|
||||||
|
{"caster_draw_limit", 4096},
|
||||||
|
{"preferred_resolution", 2048},
|
||||||
|
{"fallback_resolution", 1024},
|
||||||
|
{"sampled_d32_required", true}}},
|
||||||
{"unsupported_material_features",
|
{"unsupported_material_features",
|
||||||
{"normal maps", "metallic-roughness maps", "emissive and occlusion maps",
|
{"normal maps", "metallic-roughness maps", "emissive and occlusion maps",
|
||||||
"alpha mode selection", "unlit mode", "per-material face culling"}}};
|
"alpha mode selection", "unlit mode", "per-material face culling"}}};
|
||||||
|
|||||||
@@ -1,9 +1,11 @@
|
|||||||
#include <faset/authoring/service.hpp>
|
#include <faset/authoring/service.hpp>
|
||||||
#include <faset/core/hash.hpp>
|
#include <faset/core/hash.hpp>
|
||||||
#include <faset/core/io.hpp>
|
#include <faset/core/io.hpp>
|
||||||
|
#include <faset/editor/build_cache.hpp>
|
||||||
#include <faset/editor/build_service.hpp>
|
#include <faset/editor/build_service.hpp>
|
||||||
#include <faset/editor/commands.hpp>
|
#include <faset/editor/commands.hpp>
|
||||||
#include <faset/scripting/project.hpp>
|
#include <faset/scripting/project.hpp>
|
||||||
|
#include <algorithm>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <limits>
|
#include <limits>
|
||||||
|
|
||||||
@@ -202,19 +204,39 @@ int test_main(int argc, char** argv) {
|
|||||||
read_text(config.project_root / "schema-export-count.txt") == "2",
|
read_text(config.project_root / "schema-export-count.txt") == "2",
|
||||||
"Corrupt schema cannot be a cache hit");
|
"Corrupt schema cannot be a cache hit");
|
||||||
atomic_write(path_from_utf8(first.result.at("directory").get<std::string>()) /
|
atomic_write(path_from_utf8(first.result.at("directory").get<std::string>()) /
|
||||||
"shaders/vertexMain.spv",
|
"shaders/temporalResolveMain.spv",
|
||||||
"corrupt");
|
"corrupt");
|
||||||
first = builds.wait(builds.start_build());
|
first = builds.wait(builds.start_build());
|
||||||
check(first.state == "succeeded" && first.result.at("schema_cache_hit") == false &&
|
check(first.state == "succeeded" && first.result.at("schema_cache_hit") == false &&
|
||||||
read_text(config.project_root / "schema-export-count.txt") == "3",
|
read_text(config.project_root / "schema-export-count.txt") == "3",
|
||||||
"Corrupt shader cannot be a cache hit");
|
"Corrupt temporal shader cannot be a cache hit");
|
||||||
const auto directory = path_from_utf8(first.result.at("directory").get<std::string>());
|
const auto directory = path_from_utf8(first.result.at("directory").get<std::string>());
|
||||||
for (const auto* entry : {"lightTileMain", "gpuVertexMain", "gpuShadowMain", "gpuCullMain",
|
for (const auto* entry : {"lightTileMain", "gpuVertexMain", "gpuShadowMain", "gpuCullMain",
|
||||||
"gpuHzbMain", "gpuPostCullMain"})
|
"gpuHzbMain", "gpuPostCullMain", "temporalResolveMain",
|
||||||
|
"temporalCompositeVertexMain", "temporalCompositeFragmentMain",
|
||||||
|
"temporalVertexMain", "temporalFragmentMain",
|
||||||
|
"gpuTemporalVertexMain"})
|
||||||
for (const auto* extension : {".spv", ".reflection.json"})
|
for (const auto* extension : {".spv", ".reflection.json"})
|
||||||
check(fs::is_regular_file(directory / "shaders" /
|
check(fs::is_regular_file(directory / "shaders" /
|
||||||
(std::string(entry) + extension)),
|
(std::string(entry) + extension)),
|
||||||
"Published Player contains every checked P2 shader artifact");
|
"Published Player contains every checked P2/P3 shader artifact");
|
||||||
|
const auto published_manifest = read_json(directory / "manifest.json");
|
||||||
|
const auto package_key = published_manifest.at("package_key").get<std::string>();
|
||||||
|
check(editor::validate_build_generation(directory, package_key),
|
||||||
|
"Complete P3 shader bundle validates as a reusable generation");
|
||||||
|
const auto missing_temporal = root / "missing-temporal-generation";
|
||||||
|
fs::copy(directory, missing_temporal, fs::copy_options::recursive);
|
||||||
|
fs::remove(missing_temporal / "shaders/temporalResolveMain.spv");
|
||||||
|
fs::remove(missing_temporal / "shaders/temporalResolveMain.reflection.json");
|
||||||
|
auto incomplete_manifest = read_json(missing_temporal / "manifest.json");
|
||||||
|
auto& listed_files = incomplete_manifest.at("files").get_ref<Json::array_t&>();
|
||||||
|
std::erase_if(listed_files, [](const Json& item) {
|
||||||
|
return item.at("path") == "shaders/temporalResolveMain.spv" ||
|
||||||
|
item.at("path") == "shaders/temporalResolveMain.reflection.json";
|
||||||
|
});
|
||||||
|
atomic_write_json(missing_temporal / "manifest.json", incomplete_manifest);
|
||||||
|
check(!editor::validate_build_generation(missing_temporal, package_key),
|
||||||
|
"Generation missing temporal shaders cannot be reused even with matching hashes");
|
||||||
const auto player = path_from_utf8(first.result.at("player").get<std::string>());
|
const auto player = path_from_utf8(first.result.at("player").get<std::string>());
|
||||||
const auto schema = path_from_utf8(first.result.at("schema").get<std::string>());
|
const auto schema = path_from_utf8(first.result.at("schema").get<std::string>());
|
||||||
const auto last_build = builds.config().cache_root / "last_build.json";
|
const auto last_build = builds.config().cache_root / "last_build.json";
|
||||||
|
|||||||
@@ -92,7 +92,10 @@ int tool_main(int argc, char** argv) {
|
|||||||
fs::copy_options::overwrite_existing);
|
fs::copy_options::overwrite_existing);
|
||||||
for (const auto* entry : {"vertexMain", "fragmentMain", "shadowMain", "lightTileMain",
|
for (const auto* entry : {"vertexMain", "fragmentMain", "shadowMain", "lightTileMain",
|
||||||
"gpuVertexMain", "gpuShadowMain", "gpuCullMain",
|
"gpuVertexMain", "gpuShadowMain", "gpuCullMain",
|
||||||
"gpuHzbMain", "gpuPostCullMain"})
|
"gpuHzbMain", "gpuPostCullMain", "temporalResolveMain",
|
||||||
|
"temporalCompositeVertexMain", "temporalCompositeFragmentMain",
|
||||||
|
"temporalVertexMain", "temporalFragmentMain",
|
||||||
|
"gpuTemporalVertexMain"})
|
||||||
for (const auto* extension : {".spv", ".reflection.json"})
|
for (const auto* extension : {".spv", ".reflection.json"})
|
||||||
atomic_write(build / "shaders" / (std::string(entry) + extension), "fixture\n");
|
atomic_write(build / "shaders" / (std::string(entry) + extension), "fixture\n");
|
||||||
return 0;
|
return 0;
|
||||||
|
|||||||
@@ -310,8 +310,17 @@ int integration(const fs::path& root) {
|
|||||||
require(path_from_utf8(result.result.at("build_directory").get<std::string>()) ==
|
require(path_from_utf8(result.result.at("build_directory").get<std::string>()) ==
|
||||||
config.build_directory / "Release",
|
config.build_directory / "Release",
|
||||||
"Export has a separate CMake directory");
|
"Export has a separate CMake directory");
|
||||||
require(read_json(directory / "manifest.json").at("configuration") == "Release",
|
const auto export_manifest = read_json(directory / "manifest.json");
|
||||||
|
require(export_manifest.at("configuration") == "Release",
|
||||||
"Export manifest records the actual profile");
|
"Export manifest records the actual profile");
|
||||||
|
const auto& renderer_profile = export_manifest.at("renderer_profile");
|
||||||
|
require(!renderer_profile.contains("shadow_map") &&
|
||||||
|
renderer_profile.at("shadow_atlases").at("sun_cascade_limit") == 4 &&
|
||||||
|
renderer_profile.at("shadow_atlases").at("local_face_limit") == 16 &&
|
||||||
|
renderer_profile.at("shadow_atlases").at("caster_draw_limit") == 4096 &&
|
||||||
|
renderer_profile.at("shadow_atlases").at("preferred_resolution") == 2048 &&
|
||||||
|
renderer_profile.at("shadow_atlases").at("fallback_resolution") == 1024,
|
||||||
|
"Export manifest describes the actual bounded P3 shadow-atlas policy");
|
||||||
for (const auto* entry : {"temporalResolveMain", "temporalCompositeVertexMain",
|
for (const auto* entry : {"temporalResolveMain", "temporalCompositeVertexMain",
|
||||||
"temporalCompositeFragmentMain", "temporalVertexMain",
|
"temporalCompositeFragmentMain", "temporalVertexMain",
|
||||||
"temporalFragmentMain", "gpuTemporalVertexMain"}) {
|
"temporalFragmentMain", "gpuTemporalVertexMain"}) {
|
||||||
|
|||||||
Reference in New Issue
Block a user