nCine::RHI namespace

Render Hardware Interface — compile-time-selectable graphics backend abstraction.

Exactly one backend is compiled into a binary, selected by a WITH_RHI_* macro (the OpenGL family is the default). The render pipeline refers only to the backend-neutral aliases declared here (e.g. nCine::RHI::Device, nCine::RHI::Texture), so each backend only has to provide the same set of names with the same surface.

Every backend renders top-down: clip-space y = +1 is the top edge of the viewport for a pass onto the screen and for a pass into a render target alike, the first row of a render target is its top one — so a texture coordinate of v = 0 samples the top of what was rendered, exactly as it samples the first row of an uploaded image — and viewport and scissor rectangles are pixels counted from the top-left corner of the target. Cameras are therefore Y-down wherever they render. OpenGL, whose window space starts at the bottom-left corner, is the one family that translates: the engine flips clip-space Y of every pass into a render target, and the device converts the rectangles of a pass onto the screen (RHI_RENDER_TARGETS_BOTTOM_UP in RhiFwd.h).

Namespaces

namespace GL
OpenGL 3.3 core, OpenGL|ES 3.0/2.0 and WebGL 2.0 backend, selected by WITH_RHI_GL.
namespace Software
CPU software rasterizer backend, selected by WITH_RHI_SOFTWARE.
namespace D3D11
Direct3D 11 backend, selected by WITH_RHI_D3D11.
namespace Vulkan
Vulkan backend, selected by WITH_RHI_VULKAN.
namespace Metal
Metal backend for macOS and iOS, selected by WITH_RHI_METAL.
namespace GX
Nintendo Wii and GameCube fixed-function GX backend, selected by WITH_RHI_GX.
namespace PICA
Nintendo 3DS fixed-function PICA200 backend on top of citro3d, selected by WITH_RHI_PICA.
namespace PVR
Sega Dreamcast fixed-function PowerVR backend on top of KallistiOS, selected by WITH_RHI_PVR.
namespace GU
PlayStation Portable fixed-function GU backend, selected by WITH_RHI_GU.
namespace GS
PlayStation 2 fixed-function Graphics Synthesizer backend, selected by WITH_RHI_GS.
namespace RDP
Nintendo 64 fixed-function Reality Display Processor backend, selected by WITH_RHI_RDP.
namespace LegacyGL
Fixed-function OpenGL 1.x backend, selected by WITH_RHI_LEGACYGL.
namespace GXM
PlayStation Vita backend driving sceGxm natively, selected by WITH_RHI_GXM.
namespace RSX
PlayStation 3 backend driving the RSX through libgcm natively, selected by WITH_RHI_RSX.

Classes

struct BufferRange
Locates a sub-range within a buffer object, together with its mapped memory.
struct FixedFunctionPass
One pass of a fixed-function effect, as described by a shader's fixed_function block.
class IRhiCapabilities
Interface to query the runtime capabilities of the selected RHI backend.
class RhiCapabilitiesBase
Backend-independent part of the RHI capabilities.

Enums

enum class FixedFunctionIntrinsic : std::uint8_t { None, TileMapMesh, LightingCombine, LineStripMesh }
Backend pipeline stage a shader binds itself to with a pipeline <name>; fixed_function block.
enum class FixedFunctionRequirements : std::uint8_t { None = 0, NeedsTexelStep = 0x01, NeedsUniforms = 0x02, NeedsStripBuilder = 0x04, NeedsQuadAxes = 0x08, SamplesTexture = 0x10 }
Optional EffectContext facilities a generated effect function can ever call, as single-bit flags.

Typedefs

using Device = RHI::GL::GLDevice
using Texture = RHI::GL::GLTexture
using Buffer = RHI::GL::GLBufferObject
using Shader = RHI::GL::GLShader
using ShaderProgram = RHI::GL::GLShaderProgram
using ShaderUniforms = RHI::GL::GLShaderUniforms
using ShaderUniformBlocks = RHI::GL::GLShaderUniformBlocks
using Uniform = RHI::GL::GLUniform
using UniformBlock = RHI::GL::GLUniformBlock
using UniformCache = RHI::GL::GLUniformCache
using UniformBlockCache = RHI::GL::GLUniformBlockCache
using Attribute = RHI::GL::GLAttribute
using Framebuffer = RHI::GL::GLFramebuffer
using Renderbuffer = RHI::GL::GLRenderbuffer
using RenderTarget = RHI::GL::GLRenderTarget
using VertexArray = RHI::GL::GLVertexArrayObject
using VertexFormat = RHI::GL::GLVertexFormat
using Capabilities = RHI::GL::GLRhiCapabilities
using Debug = RHI::GL::GLDebug

Functions

auto ClampLightmapChannel(float v) -> float
Clamps one raw lightmap channel into the [0, 1] the factor formula assumes.
auto LightingCombineFactor(float r, float g, float amb) -> float
The multiply-only lighting factor for ONE ambient channel.
void LightingCombineFactors(float r, float g, float ambR, float ambG, float ambB, float& outR, float& outG, float& outB)
The multiply-only lighting factors for all three ambient channels at once.
auto AmbientLuminance(float r, float g, float b) -> float
Rec.601 luminance of an ambient colour, for a lightmap store with no colour channels.
auto HashUniformName(Death::Containers::StringView name) -> std::uint32_t
Fingerprint of a uniform name, so a lookup compares integers instead of strings.

Enum documentation

enum class nCine::RHI::FixedFunctionIntrinsic : std::uint8_t

Backend pipeline stage a shader binds itself to with a pipeline <name>; fixed_function block.

A few programs do not describe shading at all - they feed engine data structures (the tile-layer vertex stream, the weapon-wheel line strip) or hook a compositor stage (the CPU-lightmap lighting) whose implementation is backend mechanism, not effect policy. Their shader files still declare WHICH stage they are (so no shader name ever has to be matched in a backend), and the generated tables carry that declaration here instead of a transpiled function. The geometry-synthesized quad effects (the transition iris, the warped background) are NOT intrinsics anymore - since migration phase 4 they are ordinary transpiled blocks built on the strip-builder half of the contract below.

Enumerators
None

Not an intrinsic - the entry carries a transpiled effect function instead

TileMapMesh

A whole tile layer as one triangle-list mesh (8-float TileMap::AppendTileQuad contract)

LightingCombine

The viewport compositor - the direct-tier CPU-lightmap lighting hook

LineStripMesh

Vertex-fed textured line strip (the weapon wheel)

enum class nCine::RHI::FixedFunctionRequirements : std::uint8_t

Optional EffectContext facilities a generated effect function can ever call, as single-bit flags.

Computed statically by the fixed-function transpiler while it emits the function (a bit is set exactly when the corresponding builtin family appears in the emitted code) and carried in each generated table entry, so a backend's Dispatch can skip the per-draw/per-instance EffectContext setup that only feeds a facility the effect can never touch. This is purely a setup-skipping contract: because the flags come from the same static analysis that emitted the function's calls, gating setup on them can never change what the function submits.

Enumerators
None

The portable minimum: instance colour + submit_quad() only

NeedsTexelStep

Calls texel_size() / has_texel_size() (the texel-step conversion)

NeedsUniforms

Calls has_uniform() / uniform_vec2/vec4() (resolved-uniform plumbing)

NeedsStripBuilder

Calls strip_*() / submit_strip[_shaded]() (the strip-builder scratch and its state)

NeedsQuadAxes

Calls quad_origin() / quad_axis_x/y() (pre-clip quad geometry)

SamplesTexture

Submits at least one primitive that SAMPLES the bound texture: submit_quad(), submit_strip(), or submit_strip_shaded() in a block that can set TevPreset::TintMix (the one shaded form that consumes the texel too).

Unlike its siblings this one does not gate setup but a REQUIREMENT: a dispatch refuses to draw a program whose reflection binds a sampler with nothing bound to it, because a textured primitive would then rasterize garbage. An effect that only submits shaded, untextured strips has no such dependency, and the water overlay of the lighting compositor is exactly that - its program declares uTexture for a fragment stage the console tiers never run.

Typedef documentation

Function documentation

float nCine::RHI::ClampLightmapChannel(float v)

Clamps one raw lightmap channel into the [0, 1] the factor formula assumes.

float nCine::RHI::LightingCombineFactor(float r, float g, float amb)

The multiply-only lighting factor for ONE ambient channel.

r is the lightmap's coverage channel and g its brightness channel, both already clamped (see ClampLightmapChannel); amb is the matching channel of the ambient colour - or a single grey/luma for a backend whose lightmap store has no colour (the GS and the RDP), which is the one place the tiers legitimately differ.

Derived from the shader's mix(main * (1 + light.g), ambient, 1 - light.r): a fully covered texel (r = 1) keeps the scene scaled by 1 + g and takes no ambient, an uncovered one (r = 0) is pure ambient, and everything between interpolates. The result is NOT clamped - a caller whose store cannot hold values above 1 clamps as part of its own quantization.

void nCine::RHI::LightingCombineFactors(float r, float g, float ambR, float ambG, float ambB, float& outR, float& outG, float& outB)

The multiply-only lighting factors for all three ambient channels at once.

Per channel this is exactly LightingCombineFactor(), but the two terms that do NOT depend on the ambient colour - the covered term r * (1 + g) and the uncovered weight 1 - r - are computed once for the three of them instead of three times.

That is worth a function rather than being left to the compiler, because the compiler does not do it. A backend's conversion loop runs this once per lightmap texel, and calling the single-channel form three times leaves the common subexpression to be spotted across three separate inline expansions - which GCC does not manage for the PSP's Allegrex. Measured on that target, the three separate calls compile to 24 mul.s and 24 add.s; this compiles to 7 and 7.

float nCine::RHI::AmbientLuminance(float r, float g, float b)

Rec.601 luminance of an ambient colour, for a lightmap store with no colour channels.

std::uint32_t nCine::RHI::HashUniformName(Death::Containers::StringView name)

Fingerprint of a uniform name, so a lookup compares integers instead of strings.

Uniforms are resolved BY NAME on the hot path: Font::DrawString asks for three block members (texRect, spriteSize and color) for every glyph it draws, so a text-heavy frame such as the main menu runs the lookup a couple of thousand times. Comparing each candidate as a string means chasing a separately heap-allocated name per entry, and on the console CPUs the fixed-function backends run on those scattered loads cost far more than the comparison itself. Hashing the query once and walking a packed array of 32-bit fingerprints keeps the whole scan within a cache line or two; the string comparison then runs exactly once, on the entry whose fingerprint matched, so a collision can never return the wrong uniform.

Shared by every backend that resolves uniforms on the CPU (Software, GX, PVR, GU, GS, RDP), so the scheme can only ever change in one place.