Add renderer and package readiness validation gates

This commit is contained in:
2026-06-15 19:20:56 +02:00
parent 68617e8bc4
commit f78fc3076c
23 changed files with 2350 additions and 389 deletions

View File

@@ -2873,91 +2873,81 @@ void legacy_node_stroke_preview_mix_pass_adapter_preserves_retained_material_and
void legacy_node_stroke_preview_mix_executor_preserves_setup_and_draw_order(pp::tests::Harness& h)
{
std::vector<std::string> steps;
pp::panopainter::LegacyNodeStrokePreviewMixPassPlan::ShaderPlan observed_shader {};
int observed_plane_index = -1;
const bool ok = pp::panopainter::execute_legacy_node_stroke_preview_mix_pass(
pp::panopainter::LegacyNodeStrokePreviewMixExecutionRequest {
.shader = pp::panopainter::LegacyNodeStrokePreviewMixPassPlan::ShaderPlan {
.resolution = glm::vec2(128.0F, 64.0F),
.pattern_scale = glm::vec2(-0.25F, 0.25F),
.pattern_invert = 1.0F,
.pattern_brightness = 0.6F,
.pattern_contrast = 0.8F,
.pattern_depth = 0.9F,
.pattern_blend_mode = 7,
.pattern_offset = glm::vec2(0.5F, 0.5F),
.blend_mode = 5,
.use_dual = true,
.dual_blend_mode = 9,
.dual_alpha = 0.4F,
.use_pattern = true,
const std::array planes {
pp::panopainter::LegacyCanvasStrokeMixPassPlane {
.index = 4,
.visible = true,
.has_target = true,
.opacity = 1.0f,
.mvp = glm::mat4(1.0f),
},
};
const auto ok = pp::panopainter::execute_legacy_canvas_stroke_mix_pass(
pp::panopainter::LegacyCanvasStrokeMixPassRequest {
.context = "NodeStrokePreview::stroke_draw_mix",
.resolution = glm::vec2(128.0F, 64.0F),
.planes = planes,
.bind_mix_samplers = [&] {
steps.emplace_back("bind-mix");
},
.mixer_width = 128,
.mixer_height = 64,
.scissor_x = 11,
.scissor_y = 12,
.scissor_width = 13,
.scissor_height = 14,
.save_state = [&] {
steps.emplace_back("save");
.unbind_mix_samplers = [&] {
steps.emplace_back("unbind-mix");
},
.setup_mix_shader = [&](const auto& shader) {
observed_shader = shader;
steps.emplace_back("setup");
},
.bind_mixer_framebuffer = [&] {
steps.emplace_back("bind-framebuffer");
},
.configure_mix_target_state = [&](int width, int height, int x, int y, int scissor_width, int scissor_height) {
.setup_plane_shader = [&](int index, const glm::mat4& mvp) {
observed_plane_index = index;
steps.emplace_back(
"configure:" +
std::to_string(width) + "," +
std::to_string(height) + "," +
std::to_string(x) + "," +
std::to_string(y) + "," +
std::to_string(scissor_width) + "," +
std::to_string(scissor_height));
"setup:" + std::to_string(index) + ":" + std::to_string(mvp[0][0]));
},
.bind_mix_inputs = [&] {
steps.emplace_back("bind-inputs");
.bind_layer_texture = [&](int /*index*/) {
steps.emplace_back("bind-layer");
},
.draw_mix = [&] {
.bind_stroke_texture = [&](int /*index*/) {
steps.emplace_back("bind-stroke");
},
.bind_mask_texture = [&](int /*index*/) {
steps.emplace_back("bind-mask");
},
.draw_plane = [&] {
steps.emplace_back("draw");
},
.unbind_mixer_framebuffer = [&] {
steps.emplace_back("unbind-framebuffer");
.unbind_mask_texture = [&](int /*index*/) {
steps.emplace_back("unbind-mask");
},
.restore_state = [&] {
steps.emplace_back("restore");
.unbind_stroke_texture = [&](int /*index*/) {
steps.emplace_back("unbind-stroke");
},
.unbind_layer_texture = [&](int /*index*/) {
steps.emplace_back("unbind-layer");
},
});
PP_EXPECT(h, ok);
PP_EXPECT(h, almost_equal(observed_shader.resolution, glm::vec2(128.0F, 64.0F)));
PP_EXPECT(h, almost_equal(observed_shader.pattern_scale, glm::vec2(-0.25F, 0.25F)));
PP_EXPECT(h, observed_shader.use_dual);
PP_EXPECT(h, observed_shader.use_pattern);
PP_EXPECT(h, observed_shader.dual_blend_mode == 9);
PP_EXPECT(h, almost_equal(observed_shader.dual_alpha, 0.4F));
PP_EXPECT(h, ok.ok);
PP_EXPECT(h, observed_plane_index == 4);
const std::vector<std::string> expected_steps {
"save",
"setup",
"bind-framebuffer",
"configure:128,64,11,12,13,14",
"bind-inputs",
"bind-mix",
"setup:4:1.000000",
"bind-layer",
"bind-stroke",
"bind-mask",
"draw",
"unbind-framebuffer",
"restore",
"unbind-mask",
"unbind-stroke",
"unbind-layer",
"unbind-mix",
};
PP_EXPECT(h, steps == expected_steps);
const bool invalid = pp::panopainter::execute_legacy_node_stroke_preview_mix_pass(
pp::panopainter::LegacyNodeStrokePreviewMixExecutionRequest {
.mixer_width = 128,
.mixer_height = 64,
const auto invalid = pp::panopainter::execute_legacy_canvas_stroke_mix_pass(
pp::panopainter::LegacyCanvasStrokeMixPassRequest {
.context = "NodeStrokePreview::stroke_draw_mix",
.resolution = glm::vec2(128.0F, 64.0F),
.planes = planes,
});
PP_EXPECT(h, !invalid);
PP_EXPECT(h, !invalid.ok);
}
void legacy_node_stroke_preview_pass_sequence_preserves_dual_main_and_composite_order(pp::tests::Harness& h)
@@ -2965,35 +2955,49 @@ void legacy_node_stroke_preview_pass_sequence_preserves_dual_main_and_composite_
std::vector<std::string> steps;
const auto run_sequence = [&](bool dual_enabled) {
steps.clear();
const bool ok = pp::panopainter::execute_legacy_node_stroke_preview_pass_sequence(
pp::panopainter::LegacyNodeStrokePreviewPassSequenceRequest {
.dual_pass_enabled = dual_enabled,
.prepare_dual_pass = [&] {
steps.emplace_back("prepare_dual");
if (dual_enabled) {
steps.emplace_back("prepare_dual");
steps.emplace_back("execute_dual");
}
steps.emplace_back("capture_background");
steps.emplace_back("prepare_main");
const bool ok = pp::panopainter::execute_legacy_node_stroke_preview_main_live_pass(
pp::panopainter::LegacyNodeStrokePreviewMainLivePassRequestT<std::uint8_t> {
.setup_blend_uniforms = [] {},
.bind_main_pass_textures = [] {},
.clear_target = [] {},
.compute_frames = [&] {
return std::vector<std::uint8_t> { 1 };
},
.execute_dual_pass = [&] {
steps.emplace_back("execute_dual");
},
.capture_background = [&] {
steps.emplace_back("capture_background");
},
.prepare_main_pass = [&] {
steps.emplace_back("prepare_main");
},
.execute_main_pass = [&] {
.before_frame = [](std::uint8_t&) {},
.setup_sample_shader = [](std::uint8_t&) {},
.draw_sample = [&] (std::uint8_t&) {
steps.emplace_back("execute_main");
},
.finish_main_pass = [&] {
steps.emplace_back("finish_main");
},
.execute_final_composite = [&] {
steps.emplace_back("execute_composite");
},
.copy_preview_result = [&] {
steps.emplace_back("copy_preview");
},
.copy_pass_result = [] {},
.finish_main_pass = [] {},
});
PP_EXPECT(h, ok);
steps.emplace_back("finish_main");
pp::panopainter::execute_legacy_stroke_preview_final_composite(
[&] {
steps.emplace_back("execute_composite");
},
[] {},
[] {},
[] {});
const auto copy_status = pp::paint_renderer::copy_stroke_preview_result_to_texture(
[] {},
[&](int, int, int, int, int, int) {
steps.emplace_back("copy_preview");
},
pp::paint_renderer::StrokePreviewCopySize {
.width = 32,
.height = 16,
});
PP_EXPECT(h, copy_status.ok());
};
run_sequence(true);
@@ -3019,73 +3023,6 @@ void legacy_node_stroke_preview_pass_sequence_preserves_dual_main_and_composite_
"copy_preview",
};
PP_EXPECT(h, steps == single_steps);
steps.clear();
const bool missing_dual_prepare =
pp::panopainter::execute_legacy_node_stroke_preview_pass_sequence(
pp::panopainter::LegacyNodeStrokePreviewPassSequenceRequest {
.dual_pass_enabled = true,
.prepare_dual_pass = {},
.execute_dual_pass = [&] {
steps.emplace_back("execute_dual");
},
.capture_background = [&] {
steps.emplace_back("capture_background");
},
.prepare_main_pass = [&] {
steps.emplace_back("prepare_main");
},
.execute_main_pass = [&] {
steps.emplace_back("execute_main");
},
.finish_main_pass = [&] {
steps.emplace_back("finish_main");
},
.execute_final_composite = [&] {
steps.emplace_back("execute_composite");
},
.copy_preview_result = [&] {
steps.emplace_back("copy_preview");
},
});
PP_EXPECT(h, !missing_dual_prepare);
PP_EXPECT(h, steps.empty());
steps.clear();
const bool missing_main_prepare =
pp::panopainter::execute_legacy_node_stroke_preview_pass_sequence(
pp::panopainter::LegacyNodeStrokePreviewPassSequenceRequest {
.dual_pass_enabled = true,
.prepare_dual_pass = [&] {
steps.emplace_back("prepare_dual");
},
.execute_dual_pass = [&] {
steps.emplace_back("execute_dual");
},
.capture_background = [&] {
steps.emplace_back("capture_background");
},
.prepare_main_pass = {},
.execute_main_pass = [&] {
steps.emplace_back("execute_main");
},
.finish_main_pass = [&] {
steps.emplace_back("finish_main");
},
.execute_final_composite = [&] {
steps.emplace_back("execute_composite");
},
.copy_preview_result = [&] {
steps.emplace_back("copy_preview");
},
});
PP_EXPECT(h, !missing_main_prepare);
PP_EXPECT(h, steps.empty());
const bool missing_required =
pp::panopainter::execute_legacy_node_stroke_preview_pass_sequence(
pp::panopainter::LegacyNodeStrokePreviewPassSequenceRequest {});
PP_EXPECT(h, !missing_required);
}
void legacy_node_stroke_preview_main_live_pass_preserves_order(pp::tests::Harness& h)
@@ -3210,26 +3147,19 @@ void legacy_node_stroke_preview_main_pass_texture_dispatch_preserves_order(pp::t
void legacy_node_stroke_preview_final_composite_and_copy_helpers_preserve_order(pp::tests::Harness& h)
{
std::vector<std::string> steps;
const bool composite_ok = pp::panopainter::execute_legacy_node_stroke_preview_final_composite(
pp::panopainter::LegacyNodeStrokePreviewFinalCompositeRequest {
.resolution = glm::vec2(64.0F, 32.0F),
.pattern_scale = glm::vec2(0.25F, -0.5F),
.brush = reinterpret_cast<const Brush*>(1),
.composite_pass = reinterpret_cast<const pp::paint_renderer::CanvasStrokeCompositePassPlan*>(1),
.setup_composite_shader = [&] {
steps.emplace_back("setup");
},
.bind_composite_samplers = [&] {
steps.emplace_back("bind_samplers");
},
.bind_composite_inputs = [&] {
steps.emplace_back("bind_inputs");
},
.draw_composite = [&] {
steps.emplace_back("draw");
},
pp::panopainter::execute_legacy_stroke_preview_final_composite(
[&] {
steps.emplace_back("setup");
},
[&] {
steps.emplace_back("bind_samplers");
},
[&] {
steps.emplace_back("bind_inputs");
},
[&] {
steps.emplace_back("draw");
});
PP_EXPECT(h, composite_ok);
PP_EXPECT(h, (steps == std::vector<std::string> {
"setup",
"bind_samplers",
@@ -3238,23 +3168,27 @@ void legacy_node_stroke_preview_final_composite_and_copy_helpers_preserve_order(
}));
steps.clear();
const bool copy_ok = pp::panopainter::copy_legacy_node_stroke_preview_result(
pp::panopainter::LegacyNodeStrokePreviewCopyResultRequest {
.preview_texture = reinterpret_cast<Texture2D*>(1),
.size = glm::vec2(32.0F, 16.0F),
.copy_framebuffer_to_texture = [&](int src_x, int src_y, int dst_x, int dst_y, int width, int height) {
steps.emplace_back(
"copy:" +
std::to_string(src_x) + "," +
std::to_string(src_y) + "," +
std::to_string(dst_x) + "," +
std::to_string(dst_y) + "," +
std::to_string(width) + "," +
std::to_string(height));
},
const auto copy_status = pp::paint_renderer::copy_stroke_preview_result_to_texture(
[&] {
steps.emplace_back("bind");
},
[&](int src_x, int src_y, int dst_x, int dst_y, int width, int height) {
steps.emplace_back(
"copy:" +
std::to_string(src_x) + "," +
std::to_string(src_y) + "," +
std::to_string(dst_x) + "," +
std::to_string(dst_y) + "," +
std::to_string(width) + "," +
std::to_string(height));
},
pp::paint_renderer::StrokePreviewCopySize {
.width = 32,
.height = 16,
});
PP_EXPECT(h, copy_ok);
PP_EXPECT(h, copy_status.ok());
PP_EXPECT(h, (steps == std::vector<std::string> {
"bind",
"copy:0,0,0,0,32,16",
}));
}