RdpDevice class
#include <nCine/Graphics/RHI/RDP/RdpDevice.h>
Pipeline-state and draw-call facade of the RDP backend (aliased as RHI::Device).
The Nintendo 64 twin of the GX/PVR/GU devices: each draw decodes the bound program's instance block(s) exactly like SwDevice::Dispatch, CPU-transforms the four sprite corners to screen pixels and submits them through libdragon's rdpq as screen-space primitives - the RDP rasterizes exactly what it is given (there is no T&L stage in this backend; libdragon's OpenGL would run one on the RSP, but rdpq is driven directly with CPU transforms, the way the PVR backend drives KOS prims). Axis-aligned quads go out as TEXTURE_RECTANGLE commands, rotated ones and synthesized strips as rdpq_triangle pairs.
The one piece of texturing machinery the other consoles do not have is TMEM: the RDP samples only out of a 4 KB on-chip buffer (2 KB for CI8 texels - the upper half holds the palette), so every textured primitive is preceded by an upload of the sub-window it samples out of the texture's RDRAM store, deduplicated against the window already resident (consecutive draws of the same tile or glyph reload nothing). An axis-aligned primitive whose window exceeds TMEM is split into bands that fit; a rotated one clamps its window with a one-time warning (nothing on this tier draws one that big today).
Indexed textures are resolved by the hardware TLUT (FMT_CI8 + rdpq_tex_upload_tlut), loaded per draw from whatever palette texture the material bound - the direct analogue of the PVR's palette banks and the GE's CLUT; RG8 index+alpha content takes the same per-palette-row CPU bake the other consoles use. The RDP has a real raster scissor, so scissored draws are cut by the hardware rather than clipped geometrically.
The game is 2D in painter's order, so no Z buffer is attached (rdpq_attach(surface, NULL)) and depth compare stays off - which also saves 150 KB of the console's RDRAM. Because the RDP has no programmable shaders, the game runs the direct tier (see RhiFwd.h): the scene is rendered straight into the display surface at the logical resolution (the VI upscales 320x240 to the TV) and the CPU lightmap is handed to the device through SetPendingSoftwareLighting().
Public types
- struct ScissorState
- struct BlendingState
- struct DepthTestState
- struct CullFaceState
Public static functions
-
static auto GetSceneCounter() -> std::
uint32_t - Monotonic count of finished frames, used to detect "still referenced by the current frame" resources.
- static auto IsInitialized() -> bool
- Returns
trueonce InitializeRdp() has run (guards the rspq waits of the resource types). -
static auto IsFrameRetired(std::
uint32_t frame) -> bool - Returns
truewhen the RDP has retired every command enqueued for the given frame. -
static void TraceStoreRebuild(std::
uint32_t bytes, bool isBake) - Temporary instrumentation hook: records a texel-store rebuild of
bytes(see TraceDrawStatistics). -
static void WaitForFrame(std::
uint32_t frame) - Blocks until IsFrameRetired(frame) holds (the frame being built drains the whole queue).
- static auto FindGeneratedEffect(const char* program, const char* variant) -> const FixedFunctionGeneratedEffect*
- Returns the generated fixed-function effect of a (program, variant) key, or
nullptr. - static auto IsPlainSpriteEffect(const FixedFunctionGeneratedEffect* effect) -> bool
- Whether the given effect entry is the plain sprite the lean dispatch path takes.
- static void SetBlendingEnabled(bool enabled)
-
static void SetBlendingFactors(nCine::
BlendingFactor srcRgb, nCine:: BlendingFactor dstRgb, nCine:: BlendingFactor srcAlpha, nCine:: BlendingFactor dstAlpha) - static auto GetBlendingState() -> BlendingState
- static void SetBlendingState(const BlendingState& state)
- static void SetDepthTestEnabled(bool enabled)
- static void SetDepthMaskEnabled(bool enabled)
- static auto GetDepthTestState() -> DepthTestState
- static void SetDepthTestState(const DepthTestState& state)
- static void SetCullFaceEnabled(bool enabled)
- static auto GetCullFaceState() -> CullFaceState
- static void SetCullFaceState(const CullFaceState& state)
- static auto GetScissorState() -> ScissorState
- static void SetScissorState(const ScissorState& state)
- static void SetScissor(const Recti& rect)
- static void SetScissorTestEnabled(bool enabled)
- static auto GetViewport() -> Recti
- static void SetViewport(const Recti& rect)
-
static void InitViewport(std::
int32_t x, std:: int32_t y, std:: int32_t width, std:: int32_t height) - static auto GetClearColor() -> Colorf
- static void SetClearColor(const Colorf& color)
- static void Clear(ClearFlags flags)
-
static void DrawArrays(PrimitiveType primitive,
std::
int32_t firstVertex, std:: int32_t numVertices) -
static void DrawArraysInstanced(PrimitiveType primitive,
std::
int32_t firstVertex, std:: int32_t numVertices, std:: int32_t numInstances) -
static void DrawElements(PrimitiveType primitive,
std::
uint32_t numIndices, IndexFormat indexFormat, std:: uintptr_t indexOffset, std:: int32_t baseVertex) -
static void DrawElements(PrimitiveType primitive,
std::
uint32_t numIndices, std:: uintptr_t indexOffset, std:: int32_t baseVertex) -
static void DrawElementsInstanced(PrimitiveType primitive,
std::
uint32_t numIndices, IndexFormat indexFormat, std:: uintptr_t indexOffset, std:: int32_t numInstances, std:: int32_t baseVertex) -
static void DrawElementsInstanced(PrimitiveType primitive,
std::
uint32_t numIndices, std:: uintptr_t indexOffset, std:: int32_t numInstances, std:: int32_t baseVertex) - static auto InsertFence() -> FenceHandle
- static void DeleteFence(FenceHandle& fence)
-
static auto ClientWaitFence(FenceHandle fence,
std::
uint64_t timeoutNs) -> bool - static void SetupInitialState()
-
static auto CreateSwapchain(void* windowHandle,
std::
int32_t width, std:: int32_t height, bool vsync) -> bool - No-op (the window backend owns the presentation path).
- static void DestroySwapchain()
- No-op.
-
static void ResizeSwapchain(std::
int32_t width, std:: int32_t height) - No-op (the logical resolution is driven by ResizeScreenFramebuffer() from the render pipeline).
- static void PresentFrame()
- Closes the frame's RDP work and schedules the display flip (called by the N64 window backend once per frame).
- static void BeginGpuTiming()
- No-op (the RDP counts its own busy cycles, which PresentFrame() reads and reports).
- static void EndGpuTiming()
- No-op.
-
static auto GetMaxTextureDimension() -> std::
int32_t - Returns the maximum supported texture dimension (drives the tileset chunking).
-
static void ResizeScreenFramebuffer(std::
int32_t width, std:: int32_t height) - Sets the logical resolution the scene is rendered at (scaled to 320x240 at submit).
- static void InitializeRdp()
- Brings up the rdpq layer (the window backend has already run display_init).
- static void BindProgram(RdpShaderProgram* program)
- Records the currently bound shader program.
- static auto CurrentProgram() -> RdpShaderProgram*
- Returns the currently bound shader program.
-
static void BindTexture(std::
uint32_t unit, const RdpTexture* texture) - Records the texture bound to a texture unit.
- static void UnbindTexture(const RdpTexture* texture)
- Clears a texture from every unit it is bound to (called from ~RdpTexture).
-
static auto GetBoundTexture(std::
uint32_t unit) -> const RdpTexture* - Returns the texture bound to a texture unit.
-
static void BindUniformRange(std::
uint32_t index, const std:: uint8_t* data, std:: uint32_t size) - Records the host data range bound to a uniform binding point.
- static void SetRenderTarget(RdpRenderTarget* renderTarget)
- Records the current draw render target (draws re-attach the RDP to its surface).
- static void UnbindRenderTarget(const RdpRenderTarget* renderTarget)
- Clears a render target from the device if it is the current one (called from ~RdpRenderTarget).
- static void RegisterPaletteTexture(RdpTexture* texture)
- Registers the intercepted shared palette texture (rows become hardware TLUTs).
-
static void NotifyPaletteTextureChanged(RdpTexture* texture,
std::
int32_t firstRow, std:: int32_t rowCount) - Invalidates the TLUT copies (and RG8 bakes) built from the given palette rows after an upload.
-
static void SetPendingSoftwareLighting(const float* lightmap,
std::
int32_t lmW, std:: int32_t lmH, std:: int32_t scale, std:: int32_t vpX, std:: int32_t vpY, std:: int32_t vpW, std:: int32_t vpH, float ambR, float ambG, float ambB, bool waterActive = false, float waterLevelPx = 0.0f, float waterTime = 0.0f, float waterCamY = 0.0f) - Queues the CPU lightmap combine for the next
Combinedraw (the direct-tier lighting contract). - static void EndFrame()
- Drops any lighting entries not consumed this frame (called by the window backend at present).
Constructors, destructors, conversion operators
- RdpDevice() deleted
- ~RdpDevice() deleted
Function documentation
static bool nCine:: RHI:: RDP:: RdpDevice:: IsFrameRetired(std:: uint32_t frame)
Returns true when the RDP has retired every command enqueued for the given frame.
Frames are numbered by GetSceneCounter(); PresentFrame() plants an rspq syncpoint per frame, so retirement is answered exactly (a cheap check, no stall) whatever the display buffer count. The store-rewrite guards of the resource types call this with their used-in-frame stamps and only wait on a genuine conflict.
static const FixedFunctionGeneratedEffect* nCine:: RHI:: RDP:: RdpDevice:: FindGeneratedEffect(const char* program,
const char* variant)
Returns the generated fixed-function effect of a (program, variant) key, or nullptr.
Called once per program load from RdpShaderProgram::fixed_function block in its .shader file (Lighting, Blur, the Resize* family, ...) and its draws are skipped with a one-time warning, exactly as on the other fixed-function backends.
static bool nCine:: RHI:: RDP:: RdpDevice:: IsPlainSpriteEffect(const FixedFunctionGeneratedEffect* effect)
Whether the given effect entry is the plain sprite the lean dispatch path takes.
The plain sprite - one modulate pass carrying the instance colour - is nearly every draw of a frame, and Dispatch() has a shortcut for it, so the test is answered once per program load (see RdpShaderProgram::fixed_function bodies ONCE and shares the function pointer among every program that compiles to them, so one pointer comparison recognizes all of them - the sprite defaults, their batched forms and both palette remaps - without matching any shader name.
static std:: int32_t nCine:: RHI:: RDP:: RdpDevice:: GetMaxTextureDimension()
Returns the maximum supported texture dimension (drives the tileset chunking).
1024 is what the tile descriptors can address (10.2 fixed-point coordinates); the per-primitive TMEM window is what actually constrains sampling, and the device manages that itself. See the rationale in RdpRhiCapabilities.
static void nCine:: RHI:: RDP:: RdpDevice:: InitializeRdp()
Brings up the rdpq layer (the window backend has already run display_init).
Mirrors PvrDevice::InitializePvr(): the window backend owns the video mode and calls this once after it; per frame it then calls PresentFrame() and EndFrame().
static void nCine:: RHI:: RDP:: RdpDevice:: SetPendingSoftwareLighting(const float* lightmap,
std:: int32_t lmW,
std:: int32_t lmH,
std:: int32_t scale,
std:: int32_t vpX,
std:: int32_t vpY,
std:: int32_t vpW,
std:: int32_t vpH,
float ambR,
float ambG,
float ambB,
bool waterActive = false,
float waterLevelPx = 0.0f,
float waterTime = 0.0f,
float waterCamY = 0.0f)
Queues the CPU lightmap combine for the next Combine draw (the direct-tier lighting contract).
The water half of the compositor is NOT queued here: it is a fixed_function block of the CombineWithWater programs (see CombineWithWater.shader), so the water* parameters of the shared signature are ignored by this backend - only the software one still reads them.