Complete two-pass GPU occlusion, diagnostics, and LOD integration
This commit is contained in:
@@ -4,12 +4,13 @@
|
||||
#include <faset/render/renderer.hpp>
|
||||
#include <iostream>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
using namespace faset::render;
|
||||
|
||||
namespace {
|
||||
void require(bool condition, const char* message) {
|
||||
void require(bool condition, const std::string& message) {
|
||||
if (!condition)
|
||||
throw std::runtime_error(message);
|
||||
}
|
||||
@@ -21,6 +22,7 @@ RendererConfig config(VisibilityMode mode) {
|
||||
result.headless = true;
|
||||
result.validation = true;
|
||||
result.visibility_mode = mode;
|
||||
result.visibility_diagnostics = true;
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -68,6 +70,10 @@ int main() {
|
||||
gpu.stats().gpu_frustum_rejected == 1,
|
||||
"GPU frustum/indirect counts are wrong");
|
||||
require(gpu.stats().validation_errors == 0, "Vulkan validation rejected GPU path");
|
||||
if (gpu.stats().gpu_ms > 0)
|
||||
require(gpu.stats().gpu_main_cull_ms > 0 &&
|
||||
gpu.stats().gpu_main_raster_ms > 0,
|
||||
"GPU visibility pass timings are missing");
|
||||
require(different_pixels(direct.pixels(), gpu.pixels(), 5) < 160,
|
||||
"GPU and direct opaque images differ");
|
||||
|
||||
@@ -76,6 +82,32 @@ int main() {
|
||||
require(gpu.stats().gpu_visible_instances == 0 && gpu.stats().gpu_bins == 0,
|
||||
"Empty frame must reset indirect counts");
|
||||
require(gpu.stats().validation_errors == 0, "Empty GPU frame failed validation");
|
||||
gpu.set_visibility_diagnostics(false);
|
||||
gpu.render(scene());
|
||||
require(!gpu.stats().visibility_counters_valid &&
|
||||
gpu.stats().gpu_visibility_active,
|
||||
"Normal GPU rendering must not read diagnostic visibility counters");
|
||||
gpu.set_visibility_diagnostics(true);
|
||||
gpu.render(scene());
|
||||
require(gpu.stats().visibility_counters_valid &&
|
||||
gpu.stats().gpu_visible_instances == 1,
|
||||
"Visibility counters can be enabled for diagnostics");
|
||||
Renderer occlusion(config(VisibilityMode::GpuOcclusion));
|
||||
occlusion.render(scene());
|
||||
auto hzb = occlusion.hzb_debug_image(0);
|
||||
if (occlusion.stats().gpu_ms > 0)
|
||||
require(occlusion.stats().gpu_hzb_ms > 0 &&
|
||||
occlusion.stats().gpu_post_cull_ms > 0 &&
|
||||
occlusion.stats().gpu_post_raster_ms > 0,
|
||||
"HZB/post pass timings are missing");
|
||||
require(hzb && hzb->width == 512 && hzb->height == 256 &&
|
||||
hzb->rgba.size() == std::size_t(hzb->width) * hzb->height * 4,
|
||||
"Current HZB debug image has wrong dimensions");
|
||||
require(std::any_of(hzb->rgba.begin(), hzb->rgba.end(),
|
||||
[](std::uint8_t value) { return value < 250; }),
|
||||
"Current HZB debug image contains no scene depth (min=" +
|
||||
std::to_string(*std::min_element(hzb->rgba.begin(), hzb->rgba.end())) +
|
||||
")");
|
||||
std::cout << "GPU frustum, fixed indirect and direct-image comparison passed\n";
|
||||
return 0;
|
||||
} catch (const std::exception& error) {
|
||||
|
||||
@@ -65,6 +65,46 @@ int main() {
|
||||
configuration.validation = true;
|
||||
configuration.shader_directory = bundle;
|
||||
render::Renderer renderer(configuration);
|
||||
const auto baseline_only = temporary / "baseline-only";
|
||||
fs::create_directories(baseline_only);
|
||||
for (const auto* entry : {"vertexMain", "fragmentMain", "shadowMain"})
|
||||
for (const auto* extension : {".spv", ".reflection.json"}) {
|
||||
const auto name = std::string(entry) + extension;
|
||||
fs::copy_file(bundle / name, baseline_only / name);
|
||||
}
|
||||
auto direct_only_configuration = configuration;
|
||||
direct_only_configuration.shader_directory = baseline_only;
|
||||
render::Renderer direct_only(direct_only_configuration);
|
||||
direct_only.render(render::Snapshot{});
|
||||
require(direct_only.stats().validation_errors == 0,
|
||||
"Direct renderer starts without optional GPU shader bundle");
|
||||
bool unavailable_gpu_bundle = false;
|
||||
try {
|
||||
direct_only.set_visibility_mode(render::VisibilityMode::GpuFrustum);
|
||||
} catch (const std::exception&) {
|
||||
unavailable_gpu_bundle = true;
|
||||
}
|
||||
require(unavailable_gpu_bundle,
|
||||
"Switching to GPU visibility reports missing optional shader bundle");
|
||||
direct_only.render(render::Snapshot{});
|
||||
require(direct_only.visibility_mode() == render::VisibilityMode::Direct &&
|
||||
direct_only.stats().validation_errors == 0,
|
||||
"Failed GPU initialization preserves the direct renderer");
|
||||
auto gpu_configuration = configuration;
|
||||
gpu_configuration.visibility_mode = render::VisibilityMode::GpuFrustum;
|
||||
render::Renderer gpu_renderer(gpu_configuration);
|
||||
render::Snapshot opaque_scene;
|
||||
opaque_scene.eye = {0, 0, 5};
|
||||
opaque_scene.view_projection = render::multiply(
|
||||
render::perspective(.8f, 1.f, .1f, 20.f),
|
||||
render::look_at(opaque_scene.eye, {0, 0, 0}));
|
||||
render::DrawItem opaque_cube;
|
||||
opaque_cube.mesh = render::cube_mesh();
|
||||
opaque_cube.instance_key = "shader-reload-cube";
|
||||
opaque_cube.cast_shadow = false;
|
||||
opaque_scene.draws.push_back(opaque_cube);
|
||||
gpu_renderer.render(opaque_scene);
|
||||
const auto gpu_expected = gpu_renderer.pixels();
|
||||
render::Snapshot scene;
|
||||
scene.ui_quads.push_back({0, 0, 32, 64, {1, .8f, .4f, 1}});
|
||||
scene.sprites.push_back({{.5f, 0, .5f}, {1, 2}, {.2f, 1, .4f, 1}});
|
||||
@@ -161,6 +201,12 @@ int main() {
|
||||
"Source-only behavior edit preserves normalized layout fingerprint");
|
||||
std::string error;
|
||||
require(renderer.reload_shaders(error), "Compatible shader edit reloads successfully");
|
||||
require(gpu_renderer.reload_shaders(error),
|
||||
"Compatible fragment edit reloads GPU scene pipeline");
|
||||
gpu_renderer.render(opaque_scene);
|
||||
const auto gpu_changed = gpu_renderer.pixels();
|
||||
require(gpu_changed != gpu_expected,
|
||||
"Compatible fragment reload must change GPU opaque pixels");
|
||||
renderer.render(scene);
|
||||
const auto changed = renderer.pixels();
|
||||
require(changed[0] + 50 < expected[0], "Compatible reload changes actual rendered pixels");
|
||||
|
||||
Reference in New Issue
Block a user