Files
panopainter/tests/renderer_gl/command_plan_tests.cpp

323 lines
15 KiB
C++

#include "renderer_gl/command_plan.h"
#include "test_harness.h"
#include <string_view>
#include <vector>
namespace {
pp::renderer::RecordedRenderCommand begin_render_pass_command() noexcept
{
pp::renderer::RecordedRenderCommand command;
command.kind = pp::renderer::RecordedRenderCommandKind::begin_render_pass;
command.target_desc.extent = pp::renderer::Extent2D { .width = 64U, .height = 64U };
command.target_desc.format = pp::renderer::TextureFormat::rgba8;
command.clear_color_enabled = true;
command.clear_depth_enabled = true;
return command;
}
pp::renderer::RecordedRenderCommand command_with_kind(
pp::renderer::RecordedRenderCommandKind kind) noexcept
{
pp::renderer::RecordedRenderCommand command;
command.kind = kind;
return command;
}
pp::renderer::RecordedRenderCommand viewport_command() noexcept
{
pp::renderer::RecordedRenderCommand command;
command.kind = pp::renderer::RecordedRenderCommandKind::set_viewport;
command.viewport = pp::renderer::Viewport { .width = 64U, .height = 64U };
return command;
}
pp::renderer::RecordedRenderCommand draw_command() noexcept
{
pp::renderer::RecordedRenderCommand command;
command.kind = pp::renderer::RecordedRenderCommandKind::draw;
command.mesh_desc.topology = pp::renderer::PrimitiveTopology::triangles;
command.draw_desc.vertex_count = 3U;
return command;
}
pp::renderer::RecordedRenderCommand blit_command(pp::renderer::BlitFilter filter) noexcept
{
pp::renderer::RecordedRenderCommand command;
command.kind = pp::renderer::RecordedRenderCommandKind::blit_render_target;
command.blit_filter = filter;
return command;
}
void maps_render_pass_and_state_commands(pp::tests::Harness& h)
{
const auto begin = pp::renderer::gl::plan_recorded_render_command(pp::renderer::RecordedRenderCommand {
.kind = pp::renderer::RecordedRenderCommandKind::begin_render_pass,
.target_desc = pp::renderer::TextureDesc {
.extent = pp::renderer::Extent2D { .width = 64U, .height = 32U },
.format = pp::renderer::TextureFormat::rgba8,
},
.clear_color_enabled = true,
.clear_color = pp::renderer::ClearColor { .r = 0.25F, .g = 0.5F, .b = 0.75F, .a = 1.0F },
.clear_depth_enabled = true,
.clear_depth = 0.875F,
.clear_stencil_enabled = true,
.clear_stencil = 3U,
});
const auto viewport = pp::renderer::gl::plan_recorded_render_command(pp::renderer::RecordedRenderCommand {
.kind = pp::renderer::RecordedRenderCommandKind::set_viewport,
.viewport = pp::renderer::Viewport { .x = 2, .y = 4, .width = 32U, .height = 16U },
});
const auto scissor = pp::renderer::gl::plan_recorded_render_command(pp::renderer::RecordedRenderCommand {
.kind = pp::renderer::RecordedRenderCommandKind::set_scissor,
.scissor = pp::renderer::ScissorRect { .enabled = true, .x = 3, .y = 5, .width = 8U, .height = 6U },
});
const auto blend = pp::renderer::gl::plan_recorded_render_command(pp::renderer::RecordedRenderCommand {
.kind = pp::renderer::RecordedRenderCommandKind::set_blend_state,
.blend_state = pp::renderer::BlendState {
.enabled = true,
.source_color = pp::renderer::BlendFactor::source_alpha,
.destination_color = pp::renderer::BlendFactor::one_minus_source_alpha,
},
});
const auto depth = pp::renderer::gl::plan_recorded_render_command(pp::renderer::RecordedRenderCommand {
.kind = pp::renderer::RecordedRenderCommandKind::set_depth_state,
.depth_state = pp::renderer::DepthState {
.test_enabled = true,
.write_enabled = true,
.compare = pp::renderer::CompareOp::greater,
},
});
PP_EXPECT(h, begin.supported);
PP_EXPECT(h, begin.kind == pp::renderer::gl::OpenGlPlannedCommandKind::begin_render_pass);
PP_EXPECT(h, begin.clear_mask == 0x00004500U);
PP_EXPECT(h, begin.clear_values.color[2] == 0.75F);
PP_EXPECT(h, begin.clear_values.depth == 0.875F);
PP_EXPECT(h, begin.clear_values.stencil == 3U);
PP_EXPECT(h, begin.texture_format.internal_format == 0x8058U);
PP_EXPECT(h, !begin.requires_render_pass);
PP_EXPECT(h, viewport.supported);
PP_EXPECT(h, viewport.requires_render_pass);
PP_EXPECT(h, viewport.viewport.x == 2);
PP_EXPECT(h, viewport.viewport.width == 32);
PP_EXPECT(h, scissor.supported);
PP_EXPECT(h, scissor.scissor.enabled == 1U);
PP_EXPECT(h, scissor.scissor.height == 6);
PP_EXPECT(h, blend.supported);
PP_EXPECT(h, blend.blend.enabled == 1U);
PP_EXPECT(h, blend.blend.source_color_factor == 0x0302U);
PP_EXPECT(h, depth.supported);
PP_EXPECT(h, depth.depth.test_enabled == 1U);
PP_EXPECT(h, depth.depth.compare_function == 0x0204U);
}
void maps_binding_draw_and_blit_commands(pp::tests::Harness& h)
{
const auto texture = pp::renderer::gl::plan_recorded_render_command(pp::renderer::RecordedRenderCommand {
.kind = pp::renderer::RecordedRenderCommandKind::bind_texture,
.texture_desc = pp::renderer::TextureDesc {
.extent = pp::renderer::Extent2D { .width = 16U, .height = 16U },
.format = pp::renderer::TextureFormat::depth24_stencil8,
},
});
const auto sampler = pp::renderer::gl::plan_recorded_render_command(pp::renderer::RecordedRenderCommand {
.kind = pp::renderer::RecordedRenderCommandKind::bind_sampler,
.sampler_desc = pp::renderer::SamplerDesc {
.min_filter = pp::renderer::SamplerFilter::nearest,
.mag_filter = pp::renderer::SamplerFilter::linear,
.mip_filter = pp::renderer::SamplerFilter::linear,
.address_u = pp::renderer::SamplerAddressMode::repeat,
.address_v = pp::renderer::SamplerAddressMode::mirrored_repeat,
.address_w = pp::renderer::SamplerAddressMode::clamp_to_border,
},
});
const auto mesh = pp::renderer::gl::plan_recorded_render_command(pp::renderer::RecordedRenderCommand {
.kind = pp::renderer::RecordedRenderCommandKind::bind_mesh,
.mesh_desc = pp::renderer::MeshDesc { .topology = pp::renderer::PrimitiveTopology::triangle_strip },
});
const auto draw = pp::renderer::gl::plan_recorded_render_command(pp::renderer::RecordedRenderCommand {
.kind = pp::renderer::RecordedRenderCommandKind::draw,
.mesh_desc = pp::renderer::MeshDesc { .topology = pp::renderer::PrimitiveTopology::lines },
.draw_desc = pp::renderer::DrawDesc { .vertex_count = 4U, .index_count = 2U },
});
const auto blit = pp::renderer::gl::plan_recorded_render_command(pp::renderer::RecordedRenderCommand {
.kind = pp::renderer::RecordedRenderCommandKind::blit_render_target,
.blit_filter = pp::renderer::BlitFilter::linear,
});
PP_EXPECT(h, texture.supported);
PP_EXPECT(h, texture.requires_render_pass);
PP_EXPECT(h, texture.texture_format.internal_format == 0x88F0U);
PP_EXPECT(h, sampler.supported);
PP_EXPECT(h, sampler.sampler.min_filter == 0x2702U);
PP_EXPECT(h, sampler.sampler.wrap_t == 0x8370U);
PP_EXPECT(h, mesh.supported);
PP_EXPECT(h, mesh.primitive_mode == 0x0005U);
PP_EXPECT(h, draw.supported);
PP_EXPECT(h, draw.primitive_mode == 0x0001U);
PP_EXPECT(h, draw.draw_vertex_count == 4U);
PP_EXPECT(h, draw.draw_index_count == 2U);
PP_EXPECT(h, blit.supported);
PP_EXPECT(h, !blit.requires_render_pass);
PP_EXPECT(h, blit.blit_filter.value == 0x2601U);
}
void rejects_unsupported_command_tokens(pp::tests::Harness& h)
{
const auto bad_blend = pp::renderer::gl::plan_recorded_render_command(pp::renderer::RecordedRenderCommand {
.kind = pp::renderer::RecordedRenderCommandKind::set_blend_state,
.blend_state = pp::renderer::BlendState {
.source_color = static_cast<pp::renderer::BlendFactor>(255U),
},
});
const auto bad_depth = pp::renderer::gl::plan_recorded_render_command(pp::renderer::RecordedRenderCommand {
.kind = pp::renderer::RecordedRenderCommandKind::set_depth_state,
.depth_state = pp::renderer::DepthState {
.compare = static_cast<pp::renderer::CompareOp>(255U),
},
});
const auto bad_sampler = pp::renderer::gl::plan_recorded_render_command(pp::renderer::RecordedRenderCommand {
.kind = pp::renderer::RecordedRenderCommandKind::bind_sampler,
.sampler_desc = pp::renderer::SamplerDesc {
.address_u = static_cast<pp::renderer::SamplerAddressMode>(255U),
},
});
const auto bad_mesh = pp::renderer::gl::plan_recorded_render_command(pp::renderer::RecordedRenderCommand {
.kind = pp::renderer::RecordedRenderCommandKind::draw,
.mesh_desc = pp::renderer::MeshDesc {
.topology = static_cast<pp::renderer::PrimitiveTopology>(255U),
},
});
const auto bad_blit = pp::renderer::gl::plan_recorded_render_command(pp::renderer::RecordedRenderCommand {
.kind = pp::renderer::RecordedRenderCommandKind::blit_render_target,
.blit_filter = static_cast<pp::renderer::BlitFilter>(255U),
});
const auto unknown = pp::renderer::gl::plan_recorded_render_command(pp::renderer::RecordedRenderCommand {
.kind = static_cast<pp::renderer::RecordedRenderCommandKind>(255U),
});
PP_EXPECT(h, !bad_blend.supported);
PP_EXPECT(h, bad_blend.blend.source_color_factor == 0U);
PP_EXPECT(h, !bad_depth.supported);
PP_EXPECT(h, bad_depth.depth.compare_function == 0U);
PP_EXPECT(h, !bad_sampler.supported);
PP_EXPECT(h, bad_sampler.sampler.wrap_s == 0U);
PP_EXPECT(h, !bad_mesh.supported);
PP_EXPECT(h, bad_mesh.primitive_mode == 0U);
PP_EXPECT(h, !bad_blit.supported);
PP_EXPECT(h, bad_blit.blit_filter.value == 0U);
PP_EXPECT(h, !unknown.supported);
PP_EXPECT(h, unknown.kind == pp::renderer::gl::OpenGlPlannedCommandKind::unknown);
}
void names_planned_command_kinds(pp::tests::Harness& h)
{
PP_EXPECT(h, pp::renderer::gl::planned_command_kind_name(
pp::renderer::gl::OpenGlPlannedCommandKind::begin_render_pass)
== std::string_view("begin_render_pass"));
PP_EXPECT(h, pp::renderer::gl::planned_command_kind_name(
pp::renderer::gl::OpenGlPlannedCommandKind::passthrough)
== std::string_view("passthrough"));
PP_EXPECT(h, pp::renderer::gl::planned_command_kind_name(
static_cast<pp::renderer::gl::OpenGlPlannedCommandKind>(255U))
== std::string_view("unknown"));
}
void plans_valid_recorded_command_streams(pp::tests::Harness& h)
{
const std::vector<pp::renderer::RecordedRenderCommand> commands {
command_with_kind(pp::renderer::RecordedRenderCommandKind::trace_begin_scope),
begin_render_pass_command(),
viewport_command(),
command_with_kind(pp::renderer::RecordedRenderCommandKind::bind_shader),
draw_command(),
command_with_kind(pp::renderer::RecordedRenderCommandKind::end_render_pass),
blit_command(pp::renderer::BlitFilter::nearest),
};
const auto plan = pp::renderer::gl::plan_recorded_render_commands(commands);
PP_EXPECT(h, plan.supported);
PP_EXPECT(h, plan.commands.size() == commands.size());
PP_EXPECT(h, plan.render_pass_count == 1U);
PP_EXPECT(h, plan.draw_command_count == 1U);
PP_EXPECT(h, plan.passthrough_command_count == 1U);
PP_EXPECT(h, plan.trace_command_count == 1U);
PP_EXPECT(h, plan.unsupported_command_count == 0U);
PP_EXPECT(h, plan.render_pass_order_error_count == 0U);
PP_EXPECT(h, plan.first_unsupported_command == pp::renderer::gl::OpenGlCommandPlan::npos);
PP_EXPECT(h, plan.first_render_pass_order_error == pp::renderer::gl::OpenGlCommandPlan::npos);
PP_EXPECT(h, !plan.ended_in_render_pass);
PP_EXPECT(h, plan.commands[1].kind == pp::renderer::gl::OpenGlPlannedCommandKind::begin_render_pass);
PP_EXPECT(h, plan.commands[3].kind == pp::renderer::gl::OpenGlPlannedCommandKind::passthrough);
PP_EXPECT(h, plan.commands[4].kind == pp::renderer::gl::OpenGlPlannedCommandKind::draw);
PP_EXPECT(h, plan.commands[6].kind == pp::renderer::gl::OpenGlPlannedCommandKind::blit_render_target);
}
void flags_broken_render_pass_command_order(pp::tests::Harness& h)
{
const std::vector<pp::renderer::RecordedRenderCommand> outside_pass {
viewport_command(),
};
const std::vector<pp::renderer::RecordedRenderCommand> nested_pass {
begin_render_pass_command(),
begin_render_pass_command(),
command_with_kind(pp::renderer::RecordedRenderCommandKind::end_render_pass),
};
const std::vector<pp::renderer::RecordedRenderCommand> unclosed_pass {
begin_render_pass_command(),
draw_command(),
};
const auto outside = pp::renderer::gl::plan_recorded_render_commands(outside_pass);
const auto nested = pp::renderer::gl::plan_recorded_render_commands(nested_pass);
const auto unclosed = pp::renderer::gl::plan_recorded_render_commands(unclosed_pass);
PP_EXPECT(h, !outside.supported);
PP_EXPECT(h, outside.render_pass_order_error_count == 1U);
PP_EXPECT(h, outside.first_render_pass_order_error == 0U);
PP_EXPECT(h, !nested.supported);
PP_EXPECT(h, nested.render_pass_order_error_count == 1U);
PP_EXPECT(h, nested.first_render_pass_order_error == 1U);
PP_EXPECT(h, nested.render_pass_count == 2U);
PP_EXPECT(h, !unclosed.supported);
PP_EXPECT(h, unclosed.render_pass_order_error_count == 1U);
PP_EXPECT(h, unclosed.first_render_pass_order_error == unclosed_pass.size());
PP_EXPECT(h, unclosed.ended_in_render_pass);
}
void tracks_unsupported_commands_in_streams(pp::tests::Harness& h)
{
std::vector<pp::renderer::RecordedRenderCommand> commands {
begin_render_pass_command(),
draw_command(),
command_with_kind(pp::renderer::RecordedRenderCommandKind::end_render_pass),
command_with_kind(static_cast<pp::renderer::RecordedRenderCommandKind>(255U)),
};
const auto plan = pp::renderer::gl::plan_recorded_render_commands(commands);
PP_EXPECT(h, !plan.supported);
PP_EXPECT(h, plan.unsupported_command_count == 1U);
PP_EXPECT(h, plan.first_unsupported_command == 3U);
PP_EXPECT(h, plan.render_pass_order_error_count == 0U);
PP_EXPECT(h, plan.commands[3].kind == pp::renderer::gl::OpenGlPlannedCommandKind::unknown);
}
}
int main()
{
pp::tests::Harness harness;
harness.run("maps_render_pass_and_state_commands", maps_render_pass_and_state_commands);
harness.run("maps_binding_draw_and_blit_commands", maps_binding_draw_and_blit_commands);
harness.run("rejects_unsupported_command_tokens", rejects_unsupported_command_tokens);
harness.run("names_planned_command_kinds", names_planned_command_kinds);
harness.run("plans_valid_recorded_command_streams", plans_valid_recorded_command_streams);
harness.run("flags_broken_render_pass_command_order", flags_broken_render_pass_command_order);
harness.run("tracks_unsupported_commands_in_streams", tracks_unsupported_commands_in_streams);
return harness.finish();
}