# Renderer API Backend-Neutral Contract ## Purpose `pp_renderer_api` defines the backend-neutral rendering contract used by `pp_paint_renderer` and the higher-level app core. This document captures the minimum behavior that any concrete backend (`pp_renderer_gl` today, Vulkan/Metal later) must preserve. ## Contract Scope - Public interfaces: - `pp::renderer::IRenderDevice` - `pp::renderer::ICommandContext` - `pp::renderer::ITexture2D` - `pp::renderer::IRenderTarget` - `pp::renderer::IShaderProgram` - `pp::renderer::IMesh` - `pp::renderer::IReadbackBuffer` - `pp::renderer::IRenderTrace` - `pp::renderer::Recording*` helpers in `renderer_api/recording_renderer.*` - Validation helpers in `renderer_api.h` and shader catalog helpers in `renderer_api/shader_catalog.*` ## Behavioral Invariants - No exceptions are part of API control flow; failures are reported through `pp::foundation::Status` / `pp::foundation::Result`. - Object lifetimes remain backend-owned; API consumers pass references/handles only. - Resource descriptors and command/state descriptors must be validated and constrained by the helper functions. - Backends may reject unsupported operations via explicit non-OK status but must not mutate visible program state before reporting failure. - Error codes and debug names are deterministic and backend-neutral (human-readable and test-stable where feasible). ## Surface Contracts 1. `IRenderDevice` - `backend_name()` identifies backend family. - `features()` returns capability bits used for planner decisions. - Resource creation methods return `Result` and report allocation/validation failures. - `immediate_context()` is stable for the lifetime of the device object. - `trace()` may return `nullptr`; callers must tolerate no trace provider. 2. `ICommandContext` - State mutation (`set_viewport`, `set_scissor`, blend/depth/shader/sampler/mesh/program binds) is explicit and backend-agnostic. - Command methods that can fail must return status. - `end_render_pass()` is always side-effect safe and non-throwing. - `read_texture` / `capture_frame` readback contracts are byte-sized and descriptor-driven. - Texture upload/copy/readback/transition methods must respect descriptor bounds and ordering rules. 3. Resource descriptors and helpers - `TextureDesc`, `Extent2D`, `Viewport`, `ScissorRect`, `RenderPassDesc`, `TextureUsage`, `TextureState`, `BlendState`, `DepthState`, sampler/topology enums are shared semantic vocabulary across backends. - Validation helpers (`validate_*`) are the compatibility fence for contract behavior. - `PaintFeedbackPlan` and `plan_paint_feedback(...)` are the feature/algorithm decision seam for framebuffer feedback vs ping-pong workflows. 4. Trace and recording - `IRenderTrace` is optional and may be elided, but implementations should support scoped markers and markers where used. - Recording backend (`RecordingRenderDevice`, `RecordingCommandContext`) must preserve command order and reject invalid sequences through status/command visibility. ## Feature semantics Backends are expected to honor all feature bits consistently: - `framebuffer_fetch` - `explicit_texture_transitions` - `texture_copy` - `render_target_blit` - `frame_capture` - `float16_render_targets` - `float32_render_targets` - `float32_linear_filtering` Feature gates must be enforced by planners before issuing backend commands. ## Existing conformance coverage Current renderer-api conformance tests (non-backend): - `pp_renderer_api_tests` - `pp_renderer_api` test cases: - `validates_texture_usage_contract` - `validates_texture_transition_contract` - `validates_mipmap_generation_contract` - `validates_texture_copy_contract` - `validates_blit_contract` - `plans_paint_feedback_paths` - `renderer_interfaces_support_backend_neutral_dispatch` - `recording_renderer_*` command-sequence and validation tests OpenGL-specific conformance remains in `pp_renderer_gl` suites: - `pp_renderer_gl_capabilities_tests` - `pp_renderer_gl_command_plan_tests` - `pp_renderer_gl_gpu_readback_tests` (where GPU context is available) - `panopainter_renderer_conformance_matrix_self_test` - `ctest --preset renderer-conformance` - `panopainter_renderer_api_contract_self_test` (tooling guard for renderer API and paint renderer backend-neutral contract source purity). ## Open items for RND-007 - Ensure Vulkan/Metal planning/lifecycle tests run the same contract surfaces without backend leakage. - Keep `pp_renderer_api` implementation/usage free from backend-only headers and raw platform state. - Keep new backend labs opt-in until this contract and conformance matrix are complete.