Atomic pipeline bind reading from `RenderPassDescriptor`. Declares the full backend state every draw needs and forwards to the state- helper functions (`ApplyDepthMode`, `ApplyBlendMode`, etc.) which keep their own per-state caches (`_vertexShaderSel`, `_pixelShaderSel`, `_formatSet`, `_texGenMode`) to short-circuit redundant work. Single source of truth: each helper's own cache. ApplyPipeline
| 153 | // mirrored / shadow / double-sided draws bind the right winding |
| 154 | // without a force-bind defensive symptom-fix. |
| 155 | void EngineGL33::ApplyPipeline(const Poseidon::render::RenderPassDescriptor& d) |
| 156 | { |
| 157 | if (!_glContext) |
| 158 | return; |
| 159 | |
| 160 | // Pass-state dedup (perf effort 06): identical descriptor under the same |
| 161 | // pass context means identical GL state — skip the re-apply. The A2C |
| 162 | // inputs (3D pass + coverage toggle) are part of the key because the |
| 163 | // alpha-test branch below derives from them, not just from d. |
| 164 | const bool ctxIn3d = IsIn3DPass(); |
| 165 | const bool ctxA2c = GetAlphaToCoverage(); |
| 166 | const PipelineVertexInput vertexInput = _pipelineVertexInput; |
| 167 | const bool meshVertexInput = vertexInput == PipelineVertexInput::Mesh || |
| 168 | (vertexInput == PipelineVertexInput::ActivePass && IsIn3DPass()); |
| 169 | if (_lastApplied.valid && ctxIn3d == _lastApplied.in3d && ctxA2c == _lastApplied.a2c && |
| 170 | vertexInput == _lastApplied.vertexInput && d == _lastApplied.d) |
| 171 | return; |
| 172 | |
| 173 | // Validate the descriptor against the invariants listed in |
| 174 | // `ValidateRenderPassDescriptor.hpp`. Violations come from a |
| 175 | // producer / translation bug (not from runtime data), so logging |
| 176 | // once per draw is fine — the warning identifies which invariant |
| 177 | // broke and the rest of the pipeline still binds. In release |
| 178 | // builds the check is effectively free (return-on-success in a |
| 179 | // header-inlined linear scan). |
| 180 | if (const char* invariant = Poseidon::render::ValidateRenderPassDescriptor(d)) |
| 181 | { |
| 182 | LOG_DEBUG(Graphics, "GL33: descriptor invariant violated: {} (pass={}, blend={}, depth={}, fog={})", invariant, |
| 183 | static_cast<int>(d.pass), static_cast<int>(d.blend), static_cast<int>(d.depth), |
| 184 | static_cast<int>(d.fog)); |
| 185 | } |
| 186 | |
| 187 | // -- Sampler -------------------------------------------------------- |
| 188 | _pointSampling = (d.sampler.filter == Poseidon::render::SamplerFilter::Point); |
| 189 | _lastClampU = d.sampler.clampU; |
| 190 | _lastClampV = d.sampler.clampV; |
| 191 | ApplySamplerState(); |
| 192 | |
| 193 | // -- Depth + stencil ------------------------------------------------ |
| 194 | // Poseidon::render::DepthMode / BlendMode positions match the engine enums; |
| 195 | // static_cast through the underlying type keeps the conversion |
| 196 | // trivial. A switch would be more defensive against future |
| 197 | // reordering, but the static_asserts further down would catch that. |
| 198 | ApplyDepthMode(static_cast<DepthMode>(static_cast<int>(d.depth))); |
| 199 | |
| 200 | // -- Blend ---------------------------------------------------------- |
| 201 | ApplyBlendMode(static_cast<BlendMode>(static_cast<int>(d.blend))); |
| 202 | |
| 203 | // -- Fog ------------------------------------------------------------ |
| 204 | SetShaderFogEnabled(d.fog == Poseidon::render::FogMode::Enabled); |
| 205 | |
| 206 | // -- Alpha test ---------------------------------------------------- |
| 207 | const bool alphaTest = |
| 208 | (d.alpha == Poseidon::render::AlphaMode::Test || d.alpha == Poseidon::render::AlphaMode::TestAndBlend); |
| 209 | // Alpha-to-coverage only on OPAQUE cutout draws in the 3D pass. The |
| 210 | // blend gate is load-bearing: AlphaMode::Test also rides on blended |
| 211 | // descriptors (IsAlphaFog glass / IsLight flares / shadow quads use a |
| 212 | // ref=1 discard as a reject-fully-transparent optimization), and the A2C |
nothing calls this directly
no test coverage detected