PicaDevice class
Pipeline-state and draw-call facade of the PICA backend (aliased as RHI::Device).
The Nintendo 3DS twin of the GU, GX and PVR 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 to the PICA200 as triangles under a passthrough vertex program (Shaders/Pica/Sprite.v.pica), whose one uniform is the orthographic matrix that maps screen pixels into clip space - Mtx_OrthoTilt for the top screen, whose framebuffer is rotated by 90 degrees, Mtx_Ortho for a render target.
Everything the frame draws goes through citro3d's command buffer, which the GPU consumes when the frame is closed, and vertices come out of a per-frame arena in the linear heap that is written back from the data cache before each draw call - the GPU reads main memory without seeing the ARM11's cache, which is the classic source of "nothing renders" on this hardware. Two arenas alternate between frames, because the GPU is still reading one frame's vertices while the next one is being built. Consecutive primitives that share their whole GPU state are accumulated into a single C3D_DrawArrays, so a tile layer or a text run costs one draw call.
The PICA200 has a real raster scissor, so scissored draws are not clipped geometrically - the rect is programmed (in the rotated framebuffer's coordinates) and the hardware cuts the primitives. Its texture combiner is the GX's TEV in miniature: six stages with the same operand set, an interpolate function and the x2/x4 output scales, so the TintMix and ModulateX* presets are single-stage programs here where the GE had to reject them. What it has NO trace of is a colour lookup table, so indexed textures are baked through their palette row on the CPU (see PicaTexture).
Because the fragment stage has no programs, the game runs the direct tier (see RhiFwd.h): the scene is rendered straight to the display at the logical resolution and the CPU lightmap is handed to the device through SetPendingSoftwareLighting() instead of a compositing shader pass.
Public types
- struct ScissorState
- struct BlendingState
- struct DepthTestState
- struct CullFaceState
Public static variables
-
static std::
int32_t ScreenWidth constexpr - The top screen, which is what the game renders to (the bottom one keeps the boot console).
-
static std::
int32_t ScreenHeight constexpr -
static std::
int32_t HardwareTextureDimension constexpr - The dimension a single PICA200 texture cannot exceed (a hardware limit).
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 FindGeneratedEffect(const char* program, const char* variant) -> const FixedFunctionGeneratedEffect*
- Returns the generated fixed-function effect of a (program, variant) key, or
nullptr. - 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 command list and queues the display transfer to the top screen (called by the Ctr window backend once per frame).
- static void BeginGpuTiming()
- No-op (citro3d times the GPU itself, which PresentFrame() 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 400x240 at submit).
- static auto InitializePica() -> bool
- Brings up citro3d, the screen target, the vertex program and the initial pipeline state;
falseif the GPU cannot be used. - static void ShutdownPica()
- Tears the GPU session down again, so the exit path leaves the hardware idle.
- static void BindProgram(PicaShaderProgram* program)
- Records the currently bound shader program.
- static auto CurrentProgram() -> PicaShaderProgram*
- Returns the currently bound shader program.
-
static void BindTexture(std::
uint32_t unit, const PicaTexture* texture) - Records the texture bound to a texture unit.
- static void UnbindTexture(const PicaTexture* texture)
- Clears a texture from every unit it is bound to (called from ~PicaTexture).
-
static auto GetBoundTexture(std::
uint32_t unit) -> const PicaTexture* - 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(PicaRenderTarget* renderTarget)
- Records the current draw render target (draws redirect the GPU's colour buffer to it).
- static void UnbindRenderTarget(const PicaRenderTarget* renderTarget)
- Clears a render target from the device if it is the current one (called from ~PicaRenderTarget).
- static void UnbindRenderTargetSurface(const C3D_RenderTarget* target)
- Forgets a citro3d target that is about to be deleted (called from the texture that owns it).
- static void ClearRenderTargetSurface(C3D_RenderTarget* target)
- Fills a freshly created render target's colour buffer with black, sequenced with the frame.
- static void DeferredLinearFree(void* block)
- Frees a linear-heap block once the GPU can no longer be reading it.
- static void DeferredFree(void* block, bool inVram)
- Like DeferredLinearFree() for a block that may live in VRAM instead.
- static void RegisterPaletteTexture(PicaTexture* texture)
- Registers the intercepted shared palette texture (its rows are what the bakes resolve through).
-
static void NotifyPaletteTextureChanged(PicaTexture* texture,
std::
int32_t firstRow, std:: int32_t rowCount) - Invalidates the 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
- PicaDevice() deleted
- ~PicaDevice() deleted
Function documentation
static const FixedFunctionGeneratedEffect* nCine:: RHI:: PICA:: PicaDevice:: 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 PicaShaderProgram::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 std:: int32_t nCine:: RHI:: PICA:: PicaDevice:: GetMaxTextureDimension()
Returns the maximum supported texture dimension (drives the tileset chunking).
The GPU's true limit, reported honestly: it makes ContentResolver cut tileset atlases into chunks that each fit one texture (its own preference of 512 rows is below this anyway). Prebaked content that is larger anyway is NOT rejected - PicaTexture splits such an image into pages internally and the draw path picks the page a primitive samples - so Texture::Initialize() only warns about it on this backend instead of asserting.
static void nCine:: RHI:: PICA:: PicaDevice:: DeferredLinearFree(void* block)
Frees a linear-heap block once the GPU can no longer be reading it.
The commands referencing a store sit in a command list that is only run when the frame is closed, and the GPU works on it while the next frame is being built - so a store a texture drops mid-frame (a level load replaces textures while the loading screen is being drawn) stays allocated for two more presents and is freed by the device then. Exactly the hazard that froze the PSP port (see GuDevice::SyncBeforeStoreRelease), solved by deferring instead of by waiting.
static void nCine:: RHI:: PICA:: PicaDevice:: 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.