diff --git a/docs/modernization/build-inventory.md b/docs/modernization/build-inventory.md index 7c3991d..dc0a0e4 100644 --- a/docs/modernization/build-inventory.md +++ b/docs/modernization/build-inventory.md @@ -285,14 +285,14 @@ Known local toolchain state: source code reintroduces raw `GL_*`/`WGL_*` constants outside the allowed legacy OpenGL implementation files. - `pp_renderer_api` exposes a headless `RecordingRenderDevice` that validates - command order, scissor state, blend state, texture-slot binding, + command order, scissor state, depth state, blend state, texture-slot binding, texture-upload byte counts, readback bounds, frame-capture sources, destination buffer sizes, and render-target blit regions, records - render/scissor/blend/texture-bind/upload/readback/frame-capture/blit + render/scissor/depth/blend/texture-bind/upload/readback/frame-capture/blit commands, and records trace markers without a window or GL context. - `pano_cli record-render` exposes the recording renderer through JSON - automation, including scissor/blend/texture-bind/upload/readback/frame- - capture/blit command and byte totals, and is covered by + automation, including scissor/depth/blend/texture-bind/upload/readback/ + frame-capture/blit command and byte totals, and is covered by `pano_cli_record_render_smoke` plus `pano_cli_record_render_rejects_oversized_target`. - `pano_cli simulate-document-history` exposes `pp_document::DocumentHistory` diff --git a/docs/modernization/roadmap.md b/docs/modernization/roadmap.md index 51bdb50..65350c6 100644 --- a/docs/modernization/roadmap.md +++ b/docs/modernization/roadmap.md @@ -419,9 +419,9 @@ context, render device, shader program descriptor, mesh, render target, readback byte-size helpers, texture-upload/readback command validation, frame-capture byte-size helpers, frame-capture command validation, render-target blit validation, texture-slot binding validation, blend-state -validation, scissor-state validation, trace interface validation, and the -canonical PanoPainter shader catalog now consumed by the legacy OpenGL app -initialization path. +validation, scissor-state validation, depth-state validation, trace interface +validation, and the canonical PanoPainter shader catalog now consumed by the +legacy OpenGL app initialization path. `pp_renderer_gl` now exists as the first OpenGL backend library and owns pure OpenGL capability detection for framebuffer fetch, map-buffer alignment, and float texture support. It also owns the OpenGL texture upload-type mapping used @@ -724,7 +724,7 @@ Results: validation, texture-upload byte-count validation, frame-capture byte-size and command-order validation, render-target blit validation, texture-slot binding validation, blend-state validation, scissor-state validation, recording - scissor/blend/texture-bind/upload/readback/frame-capture/blit command + scissor/depth/blend/texture-bind/upload/readback/frame-capture/blit command capture, and invalid catalog rejection. - `pp_paint_renderer_compositor_tests` passed. - `pp_ui_core_color_tests` passed. @@ -819,16 +819,16 @@ Results: reintroduces raw `GL_*`/`WGL_*` constants outside the allowed legacy OpenGL implementation files. - `pp_renderer_api` now includes a headless `RecordingRenderDevice` with strict - command-order/scissor-state/blend-state/texture-bind/texture-upload/readback/ - frame-capture/blit validation; it records commands, trace markers, scissor - state, blend state, texture binds, uploads/readbacks, frame captures, and - render-target blits, giving automation a backend-neutral render path that - does not require a window or GL context. + command-order/scissor-state/depth-state/blend-state/texture-bind/ + texture-upload/readback/frame-capture/blit validation; it records commands, + trace markers, scissor state, depth state, blend state, texture binds, + uploads/readbacks, frame captures, and render-target blits, giving automation + a backend-neutral render path that does not require a window or GL context. - `pano_cli record-render` exercises that headless recording renderer and emits JSON command counts, target dimensions, backend name, trace/draw summary, and - scissor/blend-state plus texture-bind/upload/readback/frame-capture/blit - command/byte totals for agent automation, with an expected-failure smoke for - oversized render/readback targets. + scissor/depth/blend-state plus texture-bind/upload/readback/frame-capture/ + blit command/byte totals for agent automation, with an expected-failure smoke + for oversized render/readback targets. - `pano_cli simulate-document-history` exercises pure document history apply/undo/redo behavior and emits JSON layer/frame/history state for agent automation. diff --git a/src/renderer_api/recording_renderer.cpp b/src/renderer_api/recording_renderer.cpp index 132400c..91ab4f0 100644 --- a/src/renderer_api/recording_renderer.cpp +++ b/src/renderer_api/recording_renderer.cpp @@ -158,6 +158,24 @@ pp::foundation::Status RecordingCommandContext::set_blend_state(BlendState state return pp::foundation::Status::success(); } +pp::foundation::Status RecordingCommandContext::set_depth_state(DepthState state) noexcept +{ + if (!in_render_pass_) { + return pp::foundation::Status::invalid_argument("render pass has not begun"); + } + + const auto status = validate_depth_state(state); + if (!status.ok()) { + return status; + } + + push_command(commands_, RecordedRenderCommand { + .kind = RecordedRenderCommandKind::set_depth_state, + .depth_state = state, + }); + return pp::foundation::Status::success(); +} + pp::foundation::Status RecordingCommandContext::bind_shader(IShaderProgram& shader) noexcept { if (!in_render_pass_) { @@ -440,6 +458,8 @@ const char* recorded_render_command_kind_name(RecordedRenderCommandKind kind) no return "set_scissor"; case RecordedRenderCommandKind::set_blend_state: return "set_blend_state"; + case RecordedRenderCommandKind::set_depth_state: + return "set_depth_state"; case RecordedRenderCommandKind::bind_shader: return "bind_shader"; case RecordedRenderCommandKind::bind_texture: diff --git a/src/renderer_api/recording_renderer.h b/src/renderer_api/recording_renderer.h index f19ceba..53a1255 100644 --- a/src/renderer_api/recording_renderer.h +++ b/src/renderer_api/recording_renderer.h @@ -12,6 +12,7 @@ enum class RecordedRenderCommandKind : std::uint8_t { set_viewport, set_scissor, set_blend_state, + set_depth_state, bind_shader, bind_texture, bind_mesh, @@ -31,6 +32,7 @@ struct RecordedRenderCommand { Viewport viewport {}; ScissorRect scissor {}; BlendState blend_state {}; + DepthState depth_state {}; MeshDesc mesh_desc {}; TextureDesc texture_desc {}; std::uint32_t texture_slot = 0; @@ -104,6 +106,7 @@ public: [[nodiscard]] pp::foundation::Status set_viewport(Viewport viewport) noexcept override; [[nodiscard]] pp::foundation::Status set_scissor(ScissorRect scissor) noexcept override; [[nodiscard]] pp::foundation::Status set_blend_state(BlendState state) noexcept override; + [[nodiscard]] pp::foundation::Status set_depth_state(DepthState state) noexcept override; [[nodiscard]] pp::foundation::Status bind_shader(IShaderProgram& shader) noexcept override; [[nodiscard]] pp::foundation::Status bind_texture( std::uint32_t slot, diff --git a/src/renderer_api/renderer_api.cpp b/src/renderer_api/renderer_api.cpp index 16c4a53..89bf7fd 100644 --- a/src/renderer_api/renderer_api.cpp +++ b/src/renderer_api/renderer_api.cpp @@ -220,6 +220,28 @@ pp::foundation::Status validate_blend_state(BlendState state) noexcept return validate_blend_op(state.alpha_op); } +pp::foundation::Status validate_compare_op(CompareOp op) noexcept +{ + switch (op) { + case CompareOp::never: + case CompareOp::less: + case CompareOp::equal: + case CompareOp::less_or_equal: + case CompareOp::greater: + case CompareOp::not_equal: + case CompareOp::greater_or_equal: + case CompareOp::always: + return pp::foundation::Status::success(); + } + + return pp::foundation::Status::invalid_argument("depth compare operation is not supported"); +} + +pp::foundation::Status validate_depth_state(DepthState state) noexcept +{ + return validate_compare_op(state.compare); +} + pp::foundation::Status validate_mesh_desc(MeshDesc desc) noexcept { if (desc.vertex_count == 0) { @@ -447,4 +469,28 @@ const char* blend_op_name(BlendOp op) noexcept return "unknown"; } +const char* compare_op_name(CompareOp op) noexcept +{ + switch (op) { + case CompareOp::never: + return "never"; + case CompareOp::less: + return "less"; + case CompareOp::equal: + return "equal"; + case CompareOp::less_or_equal: + return "less_or_equal"; + case CompareOp::greater: + return "greater"; + case CompareOp::not_equal: + return "not_equal"; + case CompareOp::greater_or_equal: + return "greater_or_equal"; + case CompareOp::always: + return "always"; + } + + return "unknown"; +} + } diff --git a/src/renderer_api/renderer_api.h b/src/renderer_api/renderer_api.h index 217c774..e4cdbcb 100644 --- a/src/renderer_api/renderer_api.h +++ b/src/renderer_api/renderer_api.h @@ -88,6 +88,17 @@ enum class BlendOp : std::uint8_t { reverse_subtract, }; +enum class CompareOp : std::uint8_t { + never, + less, + equal, + less_or_equal, + greater, + not_equal, + greater_or_equal, + always, +}; + struct BlendState { bool enabled = false; BlendFactor source_color = BlendFactor::one; @@ -102,6 +113,12 @@ struct BlendState { bool write_a = true; }; +struct DepthState { + bool test_enabled = false; + bool write_enabled = false; + CompareOp compare = CompareOp::less_or_equal; +}; + struct MeshDesc { std::uint32_t vertex_count = 0; std::uint32_t index_count = 0; @@ -165,6 +182,7 @@ public: [[nodiscard]] virtual pp::foundation::Status set_viewport(Viewport viewport) noexcept = 0; [[nodiscard]] virtual pp::foundation::Status set_scissor(ScissorRect scissor) noexcept = 0; [[nodiscard]] virtual pp::foundation::Status set_blend_state(BlendState state) noexcept = 0; + [[nodiscard]] virtual pp::foundation::Status set_depth_state(DepthState state) noexcept = 0; [[nodiscard]] virtual pp::foundation::Status bind_shader(IShaderProgram& shader) noexcept = 0; [[nodiscard]] virtual pp::foundation::Status bind_texture( std::uint32_t slot, @@ -206,6 +224,8 @@ public: [[nodiscard]] pp::foundation::Status validate_blend_factor(BlendFactor factor) noexcept; [[nodiscard]] pp::foundation::Status validate_blend_op(BlendOp op) noexcept; [[nodiscard]] pp::foundation::Status validate_blend_state(BlendState state) noexcept; +[[nodiscard]] pp::foundation::Status validate_compare_op(CompareOp op) noexcept; +[[nodiscard]] pp::foundation::Status validate_depth_state(DepthState state) noexcept; [[nodiscard]] pp::foundation::Status validate_mesh_desc(MeshDesc desc) noexcept; [[nodiscard]] pp::foundation::Status validate_texture_slot(std::uint32_t slot) noexcept; [[nodiscard]] pp::foundation::Status validate_shader_program_desc(ShaderProgramDesc desc) noexcept; @@ -224,5 +244,6 @@ public: [[nodiscard]] const char* blit_filter_name(BlitFilter filter) noexcept; [[nodiscard]] const char* blend_factor_name(BlendFactor factor) noexcept; [[nodiscard]] const char* blend_op_name(BlendOp op) noexcept; +[[nodiscard]] const char* compare_op_name(CompareOp op) noexcept; } diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 128dd74..867c60a 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -365,7 +365,7 @@ if(TARGET pano_cli) COMMAND pano_cli record-render --width 32 --height 16) set_tests_properties(pano_cli_record_render_smoke PROPERTIES LABELS "renderer;integration;desktop-fast" - PASS_REGULAR_EXPRESSION "\"backend\":\"recording\".*\"width\":32.*\"height\":16.*\"commands\":14.*\"drawCommands\":1.*\"scissorCommands\":1.*\"blendCommands\":1.*\"bindTextureCommands\":1.*\"boundTextureBytes\":2048.*\"uploadCommands\":1.*\"uploadBytes\":4.*\"readbackCommands\":1.*\"readbackBytes\":2048.*\"captureCommands\":1.*\"captureBytes\":2048.*\"blitCommands\":1.*\"blitSourceBytes\":2048.*\"blitDestinationBytes\":2048") + PASS_REGULAR_EXPRESSION "\"backend\":\"recording\".*\"width\":32.*\"height\":16.*\"commands\":15.*\"drawCommands\":1.*\"scissorCommands\":1.*\"blendCommands\":1.*\"depthCommands\":1.*\"bindTextureCommands\":1.*\"boundTextureBytes\":2048.*\"uploadCommands\":1.*\"uploadBytes\":4.*\"readbackCommands\":1.*\"readbackBytes\":2048.*\"captureCommands\":1.*\"captureBytes\":2048.*\"blitCommands\":1.*\"blitSourceBytes\":2048.*\"blitDestinationBytes\":2048") add_test(NAME pano_cli_record_render_rejects_oversized_target COMMAND "${CMAKE_COMMAND}" diff --git a/tests/renderer_api/renderer_api_tests.cpp b/tests/renderer_api/renderer_api_tests.cpp index 9d3d127..8b4ea2b 100644 --- a/tests/renderer_api/renderer_api_tests.cpp +++ b/tests/renderer_api/renderer_api_tests.cpp @@ -16,6 +16,9 @@ using pp::renderer::BlendOp; using pp::renderer::blend_op_name; using pp::renderer::BlendState; using pp::renderer::ClearColor; +using pp::renderer::CompareOp; +using pp::renderer::compare_op_name; +using pp::renderer::DepthState; using pp::renderer::Extent2D; using pp::renderer::frame_capture_byte_size; using pp::renderer::ICommandContext; @@ -56,6 +59,8 @@ using pp::renderer::validate_blit_filter; using pp::renderer::validate_blend_factor; 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_mesh_desc; using pp::renderer::validate_readback_region; using pp::renderer::validate_scissor; @@ -184,6 +189,19 @@ public: return pp::foundation::Status::success(); } + [[nodiscard]] pp::foundation::Status set_depth_state(DepthState state) noexcept override + { + if (!in_render_pass) { + return pp::foundation::Status::invalid_argument("render pass has not begun"); + } + const auto status = validate_depth_state(state); + if (!status.ok()) { + return status; + } + last_depth_state = state; + return pp::foundation::Status::success(); + } + [[nodiscard]] pp::foundation::Status bind_texture( std::uint32_t slot, pp::renderer::ITexture2D& texture) noexcept override @@ -303,6 +321,7 @@ public: const char* shader_name = nullptr; ScissorRect last_scissor {}; BlendState last_blend_state {}; + DepthState last_depth_state {}; std::uint32_t last_texture_slot = 0; std::uint64_t last_texture_bytes = 0; std::uint64_t last_upload_bytes = 0; @@ -510,6 +529,27 @@ void validates_blend_contract(pp::tests::Harness& h) PP_EXPECT(h, blend_op_name(static_cast(255)) == std::string_view("unknown")); } +void validates_depth_contract(pp::tests::Harness& h) +{ + const DepthState read_write_depth { + .test_enabled = true, + .write_enabled = true, + .compare = CompareOp::less_or_equal, + }; + + PP_EXPECT(h, validate_depth_state(read_write_depth).ok()); + PP_EXPECT(h, validate_compare_op(CompareOp::always).ok()); + PP_EXPECT(h, compare_op_name(CompareOp::greater_or_equal) == std::string_view("greater_or_equal")); + + auto bad_compare = read_write_depth; + bad_compare.compare = static_cast(255); + const auto bad_compare_status = validate_depth_state(bad_compare); + + PP_EXPECT(h, !bad_compare_status.ok()); + PP_EXPECT(h, bad_compare_status.code == StatusCode::invalid_argument); + PP_EXPECT(h, compare_op_name(static_cast(255)) == std::string_view("unknown")); +} + void validates_viewports_and_mesh_descriptors(pp::tests::Harness& h) { const Extent2D target { .width = 64, .height = 32 }; @@ -692,6 +732,12 @@ void renderer_interfaces_support_backend_neutral_dispatch(pp::tests::Harness& h) .destination_color = BlendFactor::one_minus_source_alpha, }) .ok()); + PP_EXPECT(h, context.set_depth_state(DepthState { + .test_enabled = true, + .write_enabled = true, + .compare = CompareOp::less_or_equal, + }) + .ok()); PP_EXPECT(h, context.bind_shader(shader).ok()); PP_EXPECT(h, context.bind_texture(2, texture).ok()); PP_EXPECT(h, context.bind_mesh(mesh).ok()); @@ -726,6 +772,9 @@ void renderer_interfaces_support_backend_neutral_dispatch(pp::tests::Harness& h) PP_EXPECT(h, device.context.last_blend_state.enabled); PP_EXPECT(h, device.context.last_blend_state.source_color == BlendFactor::source_alpha); PP_EXPECT(h, device.context.last_blend_state.destination_color == BlendFactor::one_minus_source_alpha); + PP_EXPECT(h, device.context.last_depth_state.test_enabled); + PP_EXPECT(h, device.context.last_depth_state.write_enabled); + PP_EXPECT(h, device.context.last_depth_state.compare == CompareOp::less_or_equal); PP_EXPECT(h, device.context.last_texture_slot == 2U); PP_EXPECT(h, device.context.last_texture_bytes == 8192U); PP_EXPECT(h, device.context.last_upload_bytes == 80U); @@ -774,6 +823,12 @@ void recording_renderer_records_valid_command_sequences(pp::tests::Harness& h) .destination_alpha = BlendFactor::one_minus_source_alpha, }) .ok()); + PP_EXPECT(h, context.set_depth_state(DepthState { + .test_enabled = true, + .write_enabled = true, + .compare = CompareOp::less_or_equal, + }) + .ok()); PP_EXPECT(h, context.bind_shader(shader).ok()); PP_EXPECT(h, context.bind_texture(1, texture).ok()); PP_EXPECT(h, context.bind_mesh(mesh).ok()); @@ -781,7 +836,7 @@ void recording_renderer_records_valid_command_sequences(pp::tests::Harness& h) context.end_render_pass(); const auto commands = device.commands(); - PP_EXPECT(h, commands.size() == 10U); + PP_EXPECT(h, commands.size() == 11U); PP_EXPECT(h, commands[0].kind == RecordedRenderCommandKind::trace_marker); PP_EXPECT(h, commands[0].component == std::string_view("renderer")); PP_EXPECT(h, commands[0].name == std::string_view("frame")); @@ -799,17 +854,22 @@ void recording_renderer_records_valid_command_sequences(pp::tests::Harness& h) PP_EXPECT(h, commands[4].blend_state.enabled); PP_EXPECT(h, commands[4].blend_state.destination_color == BlendFactor::one_minus_source_alpha); PP_EXPECT(h, recorded_render_command_kind_name(commands[4].kind) == std::string_view("set_blend_state")); - PP_EXPECT(h, commands[5].kind == RecordedRenderCommandKind::bind_shader); - PP_EXPECT(h, commands[5].name == std::string_view("recorded-shader")); - PP_EXPECT(h, commands[6].kind == RecordedRenderCommandKind::bind_texture); - PP_EXPECT(h, commands[6].texture_slot == 1U); - PP_EXPECT(h, commands[6].texture_desc.extent.height == 32U); - PP_EXPECT(h, recorded_render_command_kind_name(commands[6].kind) == std::string_view("bind_texture")); - PP_EXPECT(h, commands[7].kind == RecordedRenderCommandKind::bind_mesh); - PP_EXPECT(h, commands[7].mesh_desc.vertex_count == 3U); - PP_EXPECT(h, commands[8].kind == RecordedRenderCommandKind::draw); - PP_EXPECT(h, commands[9].kind == RecordedRenderCommandKind::end_render_pass); - PP_EXPECT(h, recorded_render_command_kind_name(commands[8].kind) == std::string_view("draw")); + PP_EXPECT(h, commands[5].kind == RecordedRenderCommandKind::set_depth_state); + PP_EXPECT(h, commands[5].depth_state.test_enabled); + PP_EXPECT(h, commands[5].depth_state.write_enabled); + PP_EXPECT(h, commands[5].depth_state.compare == CompareOp::less_or_equal); + PP_EXPECT(h, recorded_render_command_kind_name(commands[5].kind) == std::string_view("set_depth_state")); + PP_EXPECT(h, commands[6].kind == RecordedRenderCommandKind::bind_shader); + PP_EXPECT(h, commands[6].name == std::string_view("recorded-shader")); + PP_EXPECT(h, commands[7].kind == RecordedRenderCommandKind::bind_texture); + PP_EXPECT(h, commands[7].texture_slot == 1U); + PP_EXPECT(h, commands[7].texture_desc.extent.height == 32U); + PP_EXPECT(h, recorded_render_command_kind_name(commands[7].kind) == std::string_view("bind_texture")); + PP_EXPECT(h, commands[8].kind == RecordedRenderCommandKind::bind_mesh); + PP_EXPECT(h, commands[8].mesh_desc.vertex_count == 3U); + PP_EXPECT(h, commands[9].kind == RecordedRenderCommandKind::draw); + PP_EXPECT(h, commands[10].kind == RecordedRenderCommandKind::end_render_pass); + PP_EXPECT(h, recorded_render_command_kind_name(commands[9].kind) == std::string_view("draw")); PP_EXPECT(h, context.upload_texture( texture, @@ -817,12 +877,12 @@ void recording_renderer_records_valid_command_sequences(pp::tests::Harness& h) upload_bytes) .ok()); const auto commands_after_upload = device.commands(); - PP_EXPECT(h, commands_after_upload.size() == 11U); - PP_EXPECT(h, commands_after_upload[10].kind == RecordedRenderCommandKind::upload_texture); - PP_EXPECT(h, commands_after_upload[10].texture_desc.extent.width == 64U); - PP_EXPECT(h, commands_after_upload[10].readback_region.x == 4U); - PP_EXPECT(h, commands_after_upload[10].upload_bytes == 96U); - PP_EXPECT(h, recorded_render_command_kind_name(commands_after_upload[10].kind) == std::string_view("upload_texture")); + PP_EXPECT(h, commands_after_upload.size() == 12U); + PP_EXPECT(h, commands_after_upload[11].kind == RecordedRenderCommandKind::upload_texture); + PP_EXPECT(h, commands_after_upload[11].texture_desc.extent.width == 64U); + PP_EXPECT(h, commands_after_upload[11].readback_region.x == 4U); + PP_EXPECT(h, commands_after_upload[11].upload_bytes == 96U); + PP_EXPECT(h, recorded_render_command_kind_name(commands_after_upload[11].kind) == std::string_view("upload_texture")); PP_EXPECT(h, context.read_texture( texture, @@ -830,22 +890,22 @@ void recording_renderer_records_valid_command_sequences(pp::tests::Harness& h) readback_buffer) .ok()); const auto commands_after_readback = device.commands(); - PP_EXPECT(h, commands_after_readback.size() == 12U); - PP_EXPECT(h, commands_after_readback[11].kind == RecordedRenderCommandKind::read_texture); - PP_EXPECT(h, commands_after_readback[11].texture_desc.extent.width == 64U); - PP_EXPECT(h, commands_after_readback[11].readback_region.x == 4U); - PP_EXPECT(h, commands_after_readback[11].readback_region.height == 3U); - PP_EXPECT(h, commands_after_readback[11].readback_bytes == 96U); - PP_EXPECT(h, recorded_render_command_kind_name(commands_after_readback[11].kind) == std::string_view("read_texture")); + PP_EXPECT(h, commands_after_readback.size() == 13U); + PP_EXPECT(h, commands_after_readback[12].kind == RecordedRenderCommandKind::read_texture); + PP_EXPECT(h, commands_after_readback[12].texture_desc.extent.width == 64U); + PP_EXPECT(h, commands_after_readback[12].readback_region.x == 4U); + PP_EXPECT(h, commands_after_readback[12].readback_region.height == 3U); + PP_EXPECT(h, commands_after_readback[12].readback_bytes == 96U); + PP_EXPECT(h, recorded_render_command_kind_name(commands_after_readback[12].kind) == std::string_view("read_texture")); PP_EXPECT(h, context.capture_frame(target, readback_buffer).ok()); const auto commands_after_capture = device.commands(); - PP_EXPECT(h, commands_after_capture.size() == 13U); - PP_EXPECT(h, commands_after_capture[12].kind == RecordedRenderCommandKind::capture_frame); - PP_EXPECT(h, commands_after_capture[12].target_desc.extent.width == 64U); - PP_EXPECT(h, commands_after_capture[12].target_desc.extent.height == 32U); - PP_EXPECT(h, commands_after_capture[12].capture_bytes == 8192U); - PP_EXPECT(h, recorded_render_command_kind_name(commands_after_capture[12].kind) == std::string_view("capture_frame")); + PP_EXPECT(h, commands_after_capture.size() == 14U); + PP_EXPECT(h, commands_after_capture[13].kind == RecordedRenderCommandKind::capture_frame); + PP_EXPECT(h, commands_after_capture[13].target_desc.extent.width == 64U); + PP_EXPECT(h, commands_after_capture[13].target_desc.extent.height == 32U); + PP_EXPECT(h, commands_after_capture[13].capture_bytes == 8192U); + PP_EXPECT(h, recorded_render_command_kind_name(commands_after_capture[13].kind) == std::string_view("capture_frame")); PP_EXPECT(h, context.blit_render_target( target, @@ -855,16 +915,16 @@ void recording_renderer_records_valid_command_sequences(pp::tests::Harness& h) BlitFilter::linear) .ok()); const auto commands_after_blit = device.commands(); - PP_EXPECT(h, commands_after_blit.size() == 14U); - PP_EXPECT(h, commands_after_blit[13].kind == RecordedRenderCommandKind::blit_render_target); - PP_EXPECT(h, commands_after_blit[13].source_desc.extent.width == 64U); - PP_EXPECT(h, commands_after_blit[13].destination_desc.extent.height == 32U); - PP_EXPECT(h, commands_after_blit[13].source_region.width == 16U); - PP_EXPECT(h, commands_after_blit[13].destination_region.x == 2U); - PP_EXPECT(h, commands_after_blit[13].blit_filter == BlitFilter::linear); - PP_EXPECT(h, commands_after_blit[13].blit_source_bytes == 512U); - PP_EXPECT(h, commands_after_blit[13].blit_destination_bytes == 128U); - PP_EXPECT(h, recorded_render_command_kind_name(commands_after_blit[13].kind) == std::string_view("blit_render_target")); + PP_EXPECT(h, commands_after_blit.size() == 15U); + PP_EXPECT(h, commands_after_blit[14].kind == RecordedRenderCommandKind::blit_render_target); + PP_EXPECT(h, commands_after_blit[14].source_desc.extent.width == 64U); + PP_EXPECT(h, commands_after_blit[14].destination_desc.extent.height == 32U); + PP_EXPECT(h, commands_after_blit[14].source_region.width == 16U); + PP_EXPECT(h, commands_after_blit[14].destination_region.x == 2U); + PP_EXPECT(h, commands_after_blit[14].blit_filter == BlitFilter::linear); + PP_EXPECT(h, commands_after_blit[14].blit_source_bytes == 512U); + PP_EXPECT(h, commands_after_blit[14].blit_destination_bytes == 128U); + PP_EXPECT(h, recorded_render_command_kind_name(commands_after_blit[14].kind) == std::string_view("blit_render_target")); device.clear(); PP_EXPECT(h, device.commands().empty()); @@ -914,6 +974,10 @@ void recording_renderer_rejects_invalid_command_order_and_targets(pp::tests::Har PP_EXPECT(h, !scissor_before_begin.ok()); PP_EXPECT(h, scissor_before_begin.code == StatusCode::invalid_argument); + const auto depth_before_begin = context.set_depth_state(DepthState {}); + PP_EXPECT(h, !depth_before_begin.ok()); + PP_EXPECT(h, depth_before_begin.code == StatusCode::invalid_argument); + const auto invalid_target = context.begin_render_pass(non_render_target, ClearColor {}); PP_EXPECT(h, !invalid_target.ok()); PP_EXPECT(h, invalid_target.code == StatusCode::invalid_argument); @@ -982,6 +1046,19 @@ void recording_renderer_rejects_invalid_command_order_and_targets(pp::tests::Har PP_EXPECT(h, !invalid_scissor.ok()); PP_EXPECT(h, invalid_scissor.code == StatusCode::out_of_range); + auto invalid_depth = DepthState {}; + invalid_depth.compare = static_cast(255); + const auto invalid_depth_state = context.set_depth_state(invalid_depth); + PP_EXPECT(h, !invalid_depth_state.ok()); + PP_EXPECT(h, invalid_depth_state.code == StatusCode::invalid_argument); + + PP_EXPECT(h, context.set_depth_state(DepthState { + .test_enabled = true, + .write_enabled = true, + .compare = CompareOp::less_or_equal, + }) + .ok()); + const auto draw_without_bindings = context.draw(); PP_EXPECT(h, !draw_without_bindings.ok()); PP_EXPECT(h, draw_without_bindings.code == StatusCode::invalid_argument); @@ -1016,6 +1093,10 @@ void recording_renderer_rejects_invalid_command_order_and_targets(pp::tests::Har PP_EXPECT(h, !scissor_after_end.ok()); PP_EXPECT(h, scissor_after_end.code == StatusCode::invalid_argument); + const auto depth_after_end = context.set_depth_state(DepthState {}); + PP_EXPECT(h, !depth_after_end.ok()); + PP_EXPECT(h, depth_after_end.code == StatusCode::invalid_argument); + const auto bind_texture_after_end = context.bind_texture(0, texture); PP_EXPECT(h, !bind_texture_after_end.ok()); PP_EXPECT(h, bind_texture_after_end.code == StatusCode::invalid_argument); @@ -1105,6 +1186,7 @@ int main() harness.run("computes_frame_capture_byte_sizes", computes_frame_capture_byte_sizes); harness.run("validates_blit_contract", validates_blit_contract); harness.run("validates_blend_contract", validates_blend_contract); + harness.run("validates_depth_contract", validates_depth_contract); harness.run("validates_viewports_and_mesh_descriptors", validates_viewports_and_mesh_descriptors); harness.run("validates_shader_program_descriptors", validates_shader_program_descriptors); harness.run("validates_panopainter_shader_catalog", validates_panopainter_shader_catalog); diff --git a/tools/pano_cli/main.cpp b/tools/pano_cli/main.cpp index 6fb8da7..a798490 100644 --- a/tools/pano_cli/main.cpp +++ b/tools/pano_cli/main.cpp @@ -2292,6 +2292,11 @@ int record_render(int argc, char** argv) .source_alpha = pp::renderer::BlendFactor::one, .destination_alpha = pp::renderer::BlendFactor::one_minus_source_alpha, }); + const auto depth_status = context.set_depth_state(pp::renderer::DepthState { + .test_enabled = true, + .write_enabled = true, + .compare = pp::renderer::CompareOp::less_or_equal, + }); const auto bind_texture_status = context.bind_texture(0, texture); const auto mesh_status = context.bind_mesh(mesh); const auto draw_status = context.draw(); @@ -2305,6 +2310,10 @@ int record_render(int argc, char** argv) print_error("record-render", blend_status.message); return 2; } + if (!depth_status.ok()) { + print_error("record-render", depth_status.message); + return 2; + } if (!bind_texture_status.ok()) { print_error("record-render", bind_texture_status.message); return 2; @@ -2362,6 +2371,7 @@ int record_render(int argc, char** argv) std::size_t draw_commands = 0; std::size_t scissor_commands = 0; std::size_t blend_commands = 0; + std::size_t depth_commands = 0; std::size_t bind_texture_commands = 0; std::size_t upload_commands = 0; std::size_t readback_commands = 0; @@ -2382,6 +2392,8 @@ int record_render(int argc, char** argv) ++scissor_commands; } else if (command.kind == pp::renderer::RecordedRenderCommandKind::set_blend_state) { ++blend_commands; + } else if (command.kind == pp::renderer::RecordedRenderCommandKind::set_depth_state) { + ++depth_commands; } else if (command.kind == pp::renderer::RecordedRenderCommandKind::bind_texture) { ++bind_texture_commands; const auto bound_bytes = pp::renderer::texture_byte_size(command.texture_desc); @@ -2415,6 +2427,7 @@ int record_render(int argc, char** argv) << ",\"drawCommands\":" << draw_commands << ",\"scissorCommands\":" << scissor_commands << ",\"blendCommands\":" << blend_commands + << ",\"depthCommands\":" << depth_commands << ",\"bindTextureCommands\":" << bind_texture_commands << ",\"boundTextureBytes\":" << bound_texture_bytes << ",\"uploadCommands\":" << upload_commands