Add renderer draw descriptor contract
This commit is contained in:
@@ -23,6 +23,7 @@ using pp::renderer::ClearColor;
|
||||
using pp::renderer::CompareOp;
|
||||
using pp::renderer::compare_op_name;
|
||||
using pp::renderer::DepthState;
|
||||
using pp::renderer::DrawDesc;
|
||||
using pp::renderer::Extent2D;
|
||||
using pp::renderer::frame_capture_byte_size;
|
||||
using pp::renderer::ICommandContext;
|
||||
@@ -72,6 +73,7 @@ using pp::renderer::validate_blend_op;
|
||||
using pp::renderer::validate_blend_state;
|
||||
using pp::renderer::validate_compare_op;
|
||||
using pp::renderer::validate_depth_state;
|
||||
using pp::renderer::validate_draw_desc;
|
||||
using pp::renderer::validate_mesh_desc;
|
||||
using pp::renderer::validate_readback_region;
|
||||
using pp::renderer::validate_render_pass_desc;
|
||||
@@ -319,13 +321,31 @@ public:
|
||||
|
||||
[[nodiscard]] pp::foundation::Status bind_mesh(IMesh& mesh) noexcept override
|
||||
{
|
||||
return validate_mesh_desc(mesh.desc());
|
||||
const auto status = validate_mesh_desc(mesh.desc());
|
||||
if (!status.ok()) {
|
||||
return status;
|
||||
}
|
||||
last_mesh_desc = mesh.desc();
|
||||
mesh_bound = true;
|
||||
return pp::foundation::Status::success();
|
||||
}
|
||||
|
||||
[[nodiscard]] pp::foundation::Status draw() noexcept override
|
||||
[[nodiscard]] pp::foundation::Status draw(DrawDesc desc) noexcept override
|
||||
{
|
||||
return in_render_pass ? pp::foundation::Status::success()
|
||||
: pp::foundation::Status::invalid_argument("render pass has not begun");
|
||||
if (!in_render_pass) {
|
||||
return pp::foundation::Status::invalid_argument("render pass has not begun");
|
||||
}
|
||||
if (!mesh_bound) {
|
||||
return pp::foundation::Status::invalid_argument("mesh must be bound before draw");
|
||||
}
|
||||
|
||||
const auto status = validate_draw_desc(last_mesh_desc, desc);
|
||||
if (!status.ok()) {
|
||||
return status;
|
||||
}
|
||||
|
||||
last_draw_desc = desc;
|
||||
return pp::foundation::Status::success();
|
||||
}
|
||||
|
||||
[[nodiscard]] pp::foundation::Status read_texture(
|
||||
@@ -410,10 +430,15 @@ public:
|
||||
void end_render_pass() noexcept override
|
||||
{
|
||||
in_render_pass = false;
|
||||
mesh_bound = false;
|
||||
last_mesh_desc = MeshDesc {};
|
||||
}
|
||||
|
||||
bool in_render_pass = false;
|
||||
bool mesh_bound = false;
|
||||
RenderPassDesc last_render_pass_desc {};
|
||||
MeshDesc last_mesh_desc {};
|
||||
DrawDesc last_draw_desc {};
|
||||
const char* shader_name = nullptr;
|
||||
const char* last_uniform_name = nullptr;
|
||||
std::size_t last_uniform_bytes = 0;
|
||||
@@ -810,6 +835,41 @@ void validates_viewports_and_mesh_descriptors(pp::tests::Harness& h)
|
||||
PP_EXPECT(h, invalid_slot.code == StatusCode::out_of_range);
|
||||
}
|
||||
|
||||
void validates_draw_descriptors(pp::tests::Harness& h)
|
||||
{
|
||||
const MeshDesc vertex_mesh {
|
||||
.vertex_count = 8,
|
||||
.index_count = 0,
|
||||
.topology = PrimitiveTopology::triangles,
|
||||
};
|
||||
const MeshDesc indexed_mesh {
|
||||
.vertex_count = 8,
|
||||
.index_count = 12,
|
||||
.topology = PrimitiveTopology::triangles,
|
||||
};
|
||||
|
||||
PP_EXPECT(h, validate_draw_desc(vertex_mesh, DrawDesc { .first_vertex = 2, .vertex_count = 3 }).ok());
|
||||
PP_EXPECT(h, validate_draw_desc(indexed_mesh, DrawDesc { .first_index = 3, .index_count = 6 }).ok());
|
||||
PP_EXPECT(h, validate_draw_desc(indexed_mesh, DrawDesc { .index_count = 12, .instance_count = 4 }).ok());
|
||||
|
||||
const auto empty_draw = validate_draw_desc(vertex_mesh, DrawDesc {});
|
||||
const auto zero_instances = validate_draw_desc(vertex_mesh, DrawDesc { .vertex_count = 3, .instance_count = 0 });
|
||||
const auto vertex_overrun = validate_draw_desc(vertex_mesh, DrawDesc { .first_vertex = 7, .vertex_count = 2 });
|
||||
const auto indexed_without_indices = validate_draw_desc(vertex_mesh, DrawDesc { .index_count = 3 });
|
||||
const auto index_overrun = validate_draw_desc(indexed_mesh, DrawDesc { .first_index = 11, .index_count = 2 });
|
||||
|
||||
PP_EXPECT(h, !empty_draw.ok());
|
||||
PP_EXPECT(h, empty_draw.code == StatusCode::invalid_argument);
|
||||
PP_EXPECT(h, !zero_instances.ok());
|
||||
PP_EXPECT(h, zero_instances.code == StatusCode::invalid_argument);
|
||||
PP_EXPECT(h, !vertex_overrun.ok());
|
||||
PP_EXPECT(h, vertex_overrun.code == StatusCode::out_of_range);
|
||||
PP_EXPECT(h, !indexed_without_indices.ok());
|
||||
PP_EXPECT(h, indexed_without_indices.code == StatusCode::invalid_argument);
|
||||
PP_EXPECT(h, !index_overrun.ok());
|
||||
PP_EXPECT(h, index_overrun.code == StatusCode::out_of_range);
|
||||
}
|
||||
|
||||
void validates_render_pass_descriptors(pp::tests::Harness& h)
|
||||
{
|
||||
const auto valid = validate_render_pass_desc(RenderPassDesc {
|
||||
@@ -1034,10 +1094,10 @@ void renderer_interfaces_support_backend_neutral_dispatch(pp::tests::Harness& h)
|
||||
})
|
||||
.ok());
|
||||
PP_EXPECT(h, context.bind_mesh(mesh).ok());
|
||||
PP_EXPECT(h, context.draw().ok());
|
||||
PP_EXPECT(h, context.draw(DrawDesc { .vertex_count = 3 }).ok());
|
||||
context.end_render_pass();
|
||||
|
||||
const auto draw_after_end = context.draw();
|
||||
const auto draw_after_end = context.draw(DrawDesc { .vertex_count = 3 });
|
||||
PP_EXPECT(h, !draw_after_end.ok());
|
||||
PP_EXPECT(h, draw_after_end.code == StatusCode::invalid_argument);
|
||||
PP_EXPECT(h, context.upload_texture(
|
||||
@@ -1073,6 +1133,8 @@ void renderer_interfaces_support_backend_neutral_dispatch(pp::tests::Harness& h)
|
||||
PP_EXPECT(h, device.context.last_depth_state.compare == CompareOp::less_or_equal);
|
||||
PP_EXPECT(h, device.context.last_uniform_name == std::string_view("mvp"));
|
||||
PP_EXPECT(h, device.context.last_uniform_bytes == 64U);
|
||||
PP_EXPECT(h, device.context.last_draw_desc.vertex_count == 3U);
|
||||
PP_EXPECT(h, device.context.last_draw_desc.instance_count == 1U);
|
||||
PP_EXPECT(h, device.context.last_texture_slot == 2U);
|
||||
PP_EXPECT(h, device.context.last_texture_bytes == 8192U);
|
||||
PP_EXPECT(h, device.context.last_sampler_slot == 2U);
|
||||
@@ -1259,7 +1321,7 @@ void recording_renderer_records_valid_command_sequences(pp::tests::Harness& h)
|
||||
})
|
||||
.ok());
|
||||
PP_EXPECT(h, context.bind_mesh(mesh).ok());
|
||||
PP_EXPECT(h, context.draw().ok());
|
||||
PP_EXPECT(h, context.draw(DrawDesc { .vertex_count = 3, .index_count = 3 }).ok());
|
||||
context.end_render_pass();
|
||||
|
||||
const auto commands = device.commands();
|
||||
@@ -1309,6 +1371,9 @@ void recording_renderer_records_valid_command_sequences(pp::tests::Harness& h)
|
||||
PP_EXPECT(h, commands[10].mesh_desc.vertex_count == 3U);
|
||||
PP_EXPECT(h, commands[10].mesh_desc.index_count == 3U);
|
||||
PP_EXPECT(h, commands[10].mesh_desc.topology == PrimitiveTopology::triangles);
|
||||
PP_EXPECT(h, commands[10].draw_desc.vertex_count == 3U);
|
||||
PP_EXPECT(h, commands[10].draw_desc.index_count == 3U);
|
||||
PP_EXPECT(h, commands[10].draw_desc.instance_count == 1U);
|
||||
PP_EXPECT(h, commands[11].kind == RecordedRenderCommandKind::end_render_pass);
|
||||
PP_EXPECT(h, recorded_render_command_kind_name(commands[10].kind) == std::string_view("draw"));
|
||||
|
||||
@@ -1403,7 +1468,7 @@ void recording_renderer_rejects_invalid_command_order_and_targets(pp::tests::Har
|
||||
RecordingMesh empty_mesh(MeshDesc {});
|
||||
|
||||
auto& context = device.immediate_context();
|
||||
const auto draw_before_begin = context.draw();
|
||||
const auto draw_before_begin = context.draw(DrawDesc { .vertex_count = 3 });
|
||||
PP_EXPECT(h, !draw_before_begin.ok());
|
||||
PP_EXPECT(h, draw_before_begin.code == StatusCode::invalid_argument);
|
||||
|
||||
@@ -1513,7 +1578,7 @@ void recording_renderer_rejects_invalid_command_order_and_targets(pp::tests::Har
|
||||
})
|
||||
.ok());
|
||||
|
||||
const auto draw_without_bindings = context.draw();
|
||||
const auto draw_without_bindings = context.draw(DrawDesc { .vertex_count = 3 });
|
||||
PP_EXPECT(h, !draw_without_bindings.ok());
|
||||
PP_EXPECT(h, draw_without_bindings.code == StatusCode::invalid_argument);
|
||||
|
||||
@@ -1535,7 +1600,7 @@ void recording_renderer_rejects_invalid_command_order_and_targets(pp::tests::Har
|
||||
|
||||
PP_EXPECT(h, context.bind_sampler(0, SamplerDesc {}).ok());
|
||||
|
||||
const auto draw_without_mesh = context.draw();
|
||||
const auto draw_without_mesh = context.draw(DrawDesc { .vertex_count = 3 });
|
||||
PP_EXPECT(h, !draw_without_mesh.ok());
|
||||
PP_EXPECT(h, draw_without_mesh.code == StatusCode::invalid_argument);
|
||||
|
||||
@@ -1544,7 +1609,10 @@ void recording_renderer_rejects_invalid_command_order_and_targets(pp::tests::Har
|
||||
PP_EXPECT(h, invalid_mesh.code == StatusCode::invalid_argument);
|
||||
|
||||
PP_EXPECT(h, context.bind_mesh(mesh).ok());
|
||||
PP_EXPECT(h, context.draw().ok());
|
||||
const auto draw_outside_mesh = context.draw(DrawDesc { .first_vertex = 2, .vertex_count = 2 });
|
||||
PP_EXPECT(h, !draw_outside_mesh.ok());
|
||||
PP_EXPECT(h, draw_outside_mesh.code == StatusCode::out_of_range);
|
||||
PP_EXPECT(h, context.draw(DrawDesc { .vertex_count = 3 }).ok());
|
||||
context.end_render_pass();
|
||||
|
||||
const auto viewport_after_end = context.set_viewport(Viewport { .x = 0, .y = 0, .width = 1, .height = 1 });
|
||||
@@ -1659,6 +1727,7 @@ int main()
|
||||
harness.run("validates_depth_contract", validates_depth_contract);
|
||||
harness.run("validates_sampler_contract", validates_sampler_contract);
|
||||
harness.run("validates_viewports_and_mesh_descriptors", validates_viewports_and_mesh_descriptors);
|
||||
harness.run("validates_draw_descriptors", validates_draw_descriptors);
|
||||
harness.run("validates_render_pass_descriptors", validates_render_pass_descriptors);
|
||||
harness.run("validates_shader_program_descriptors", validates_shader_program_descriptors);
|
||||
harness.run("validates_shader_uniform_writes", validates_shader_uniform_writes);
|
||||
|
||||
Reference in New Issue
Block a user