RdpTexture class
Texture object of the RDP backend (aliased as RHI::Texture).
The RDP samples textures out of TMEM, a 4 KB on-chip buffer the device loads per primitive from an ordinary RDRAM surface - so unlike the PowerVR there is no separate "video memory" store to manage, and unlike the GE there is no per-axis addressing limit to page around: the texture keeps ONE RDRAM store in a format the RDP's load commands accept, and the device uploads the sub-window a primitive samples into TMEM before drawing it. The store's requirements are libdragon's texture rules: an 8-byte aligned base (64 here, a full cache line), a row stride that is a multiple of 8 bytes, and a CPU cache writeback after every CPU write - the RDP DMAs straight from RDRAM and never sees the data cache.
Formats:
- R8 index textures ARE their RDP store: the bytes of a
FMT_CI8surface are the palette indices themselves, so no second copy is kept and no conversion ever runs - the palette is resolved by the TLUT the device loads into the upper half of TMEM per draw (the analogue of the PowerVR's palette banks and the GE's CLUT). This is also what makes R8 streaming free (see MapStreamingTexels()). - RG8 (index + per-pixel alpha) has no paletted equivalent - a CI texel's alpha comes from the TLUT entry - so it takes the same per-palette-row CPU bake the other consoles use, into
FMT_RGBA16(EnsureBakedStore()). RGBA5551 keeps only one alpha bit, so the per-pixel alpha is thresholded; content that needs the smooth gradient would have to bake toFMT_RGBA32at double the memory and half the TMEM window (TODO if it ever shows). - RGBA8 / RGB8 / RGB565 convert to
FMT_RGBA16(RGBA5551) at the first draw that samples them, halving RDRAM against a 32-bit store. The linear host copy in the uploaded format exists only until that conversion: the device reads a host copy back through GetPixels() for ONE role, the palette a draw resolves indices with (the shared palette texture, or the recolored preview palettes of the profile menu bound touTexturePalette), and a palette is never the texture a primitive samples - so a texture that has produced its RDP store has proven it is not one, and keeping its host copy alive would be two copies of every image in the game. Later sub-uploads (a minimap line, an ImGui atlas patch) convert straight into the store from then on. The shared 256x256 palette texture (labelled "Palettes") is intercepted: it keeps only the linear RGBA8 store and the device converts its rows into RGBA5551 TLUTs on demand.
Render targets allocate their FMT_RGBA16 surface eagerly; the same surface is what rdpq_attach() renders into and what the sampling passes later upload windows from. Mip levels above 0 and compressed formats are accepted but not stored.
Public static variables
-
static std::
uint32_t MaxTextureUnits constexpr - Number of texture units tracked by the device.
Public static functions
-
static auto Unbind(std::
uint32_t textureUnit) -> bool - Unbinds any texture from the specified texture unit.
-
static void SetUnpackAlignment(std::
int32_t alignment) - Sets the client pixel-row alignment of uploads (ignored, uploads are tightly packed).
- static auto SupportsImmutableStorage() -> bool
- static auto SupportsTextureReadback() -> bool
- static void ClearErrors()
- static auto CheckErrors() -> bool
- static void CheckFormatSupport(PixelFormat format)
-
static auto BytesPerPixel(PixelFormat format) -> std::
int32_t - Returns the number of bytes occupied by one texel of the given format (0 if unsupported).
Constructors, destructors, conversion operators
- RdpTexture(TextureTarget target) explicit
- ~RdpTexture()
- RdpTexture(const RdpTexture&) deleted
Public functions
- auto operator=(const RdpTexture&) -> RdpTexture& deleted
-
auto GetUniqueId() const -> std::
uint32_t - Returns a backend-neutral identifier uniquely identifying the texture (feeds material sort keys).
- auto GetTarget() const -> TextureTarget
- Returns the texture target.
-
auto GetWidth() const -> std::
int32_t - Returns the width of level 0 in texels.
-
auto GetHeight() const -> std::
int32_t - Returns the height of level 0 in texels.
- auto GetFormat() const -> PixelFormat
- Returns the pixel format of the linear host store (native, like the software backend).
- auto GetUploadFormat() const -> PixelFormat
- Returns the original upload format (R8/RG8 kept so the palette path can tell them apart).
-
auto GetStrideBytes() const -> std::
int32_t - Returns the byte distance between two consecutive rows of the linear host store.
-
auto GetPixels(std::
int32_t level = 0) const -> const std:: uint8_t* - Returns the base pointer of the linear host store (may be
nullptrbefore an upload). -
auto MutablePixels() -> std::
uint8_t* - Returns a writable base pointer of the linear host store (
nullptrwhen none exists). - auto GetWrapS() const -> SamplerWrapping
- Returns the horizontal texture-coordinate wrap mode.
- auto GetWrapT() const -> SamplerWrapping
- Returns the vertical texture-coordinate wrap mode (single stored mode).
- auto GetSwizzle() const -> const SwizzleChannel*
- Returns the four-channel sampling swizzle (identity by default; informational on RDP).
-
auto GetMagFiltering() const -> nCine::
SamplerFilter - Returns the magnification filter.
-
auto GetMagFilter() const -> nCine::
SamplerFilter - Alias of GetMagFiltering().
- auto IsRenderTarget() const -> bool
- Returns
trueif the texture is bound as a color render target. - void SetRenderTarget(bool isRenderTarget)
- Marks the texture as (or no longer as) a color render target; becoming one allocates its surface.
-
auto GetContentVersion() const -> std::
uint32_t - Returns a globally monotonic stamp of the texel store, advanced by every allocation or upload.
-
auto GetSurfaceStamp() const -> std::
uint32_t - Returns the stamp of the surface a draw would sample right now.
- auto IsIndexed() const -> bool
- Returns
truewhen the store holds palette indices (draws resolve them through a TLUT). - auto NeedsPaletteBake() const -> bool
- Returns
truewhen the texture needs the per-palette-row CPU bake (RG8 index + alpha). - auto IsPaletteTexture() const -> bool
- Returns
truewhen this is the intercepted shared palette texture (rows become TLUTs). - auto AcquireSurface() -> const surface_t*
- Builds the RDP-sampleable surface if it is missing and returns it, or
nullptr. -
auto EnsureBakedStore(const std::
uint32_t* paletteRow, std:: uint32_t paletteRowIndex, std:: uint32_t paletteGeneration, const void* palette) -> bool - Makes the active RDP store this RG8 texture baked through one palette row.
-
auto MapStreamingTexels(std::
int32_t& strideBytes) -> void* - Returns a writable pointer to the RDP store, for content that is rebuilt every frame.
- auto GetRenderTargetSurface() const -> const surface_t*
- Returns the surface the RDP renders into when this texture is a render target, or
nullptr. -
auto Bind(std::
uint32_t textureUnit) const -> bool - Binds the texture to the specified texture unit on the device.
- auto Bind() const -> bool
- Binds the texture to texture unit 0.
- auto Unbind() const -> bool
- Unbinds the texture from the unit it was last bound to.
-
void TexImage2D(std::
int32_t level, PixelFormat format, bool bgr, std:: int32_t width, std:: int32_t height, const void* data) - Allocates level-0 storage of the given format/size and optionally uploads its texels.
-
void TexSubImage2D(std::
int32_t level, std:: int32_t xoffset, std:: int32_t yoffset, std:: int32_t width, std:: int32_t height, PixelFormat format, bool bgr, const void* data) - Updates a rectangular subregion of level 0.
-
void TexStorage2D(std::
int32_t levels, PixelFormat format, std:: int32_t width, std:: int32_t height) - Allocates immutable level-0 storage of the given format/size (no texels yet).
-
void CompressedTexImage2D(std::
int32_t level, PixelFormat format, std:: int32_t width, std:: int32_t height, std:: int32_t imageSize, const void* data) - Compressed upload (unsupported, accepted as a no-op).
-
void CompressedTexSubImage2D(std::
int32_t level, std:: int32_t xoffset, std:: int32_t yoffset, std:: int32_t width, std:: int32_t height, PixelFormat format, std:: int32_t imageSize, const void* data) - Compressed sub-upload (unsupported, accepted as a no-op).
-
void GetTexImage(std::
int32_t level, PixelFormat format, bool bgr, void* pixels) - Reads back level-0 texels of the linear host store into client memory.
-
void SetMinFiltering(nCine::
SamplerFilter filter) - Sets the minification filter.
-
void SetMagFiltering(nCine::
SamplerFilter filter) - Sets the magnification filter.
- void SetWrap(SamplerWrapping wrap)
- Sets the wrap mode.
- void SetSwizzle(SwizzleChannel r, SwizzleChannel g, SwizzleChannel b, SwizzleChannel a)
- Sets the sampling swizzle (stored, informational - the palette path keys off the upload format instead).
-
void SetMaxLevel(std::
int32_t maxLevel) - Sets the highest defined mipmap level (ignored).
- void SetObjectLabel(StringView label)
- Sets a debug label; "Palettes" marks the shared palette texture whose rows become TLUTs.
Function documentation
const std:: uint8_t* nCine:: RHI:: RDP:: RdpTexture:: GetPixels(std:: int32_t level = 0) const
Returns the base pointer of the linear host store (may be nullptr before an upload).
For R8 the RDP store IS the host store (identity bytes, padded stride); RG8 keeps a linear copy in the uploaded format for as long as it lives (the per-palette-row bakes read it); a direct-color texture keeps one until its RGBA5551 store has been built, which is enough for the palette path (a palette is read on the CPU, never sampled, so it never builds a store); a render target has none.
std:: uint32_t nCine:: RHI:: RDP:: RdpTexture:: GetSurfaceStamp() const
Returns the stamp of the surface a draw would sample right now.
The content version for an ordinary store; for an RG8 texture, the stamp of the ACTIVE bake - every rebuild gets a fresh one, so a bake slot recycled in place for another palette row can never satisfy the device's TMEM residency check with the previous row's texels.
const surface_t* nCine:: RHI:: RDP:: RdpTexture:: AcquireSurface()
Builds the RDP-sampleable surface if it is missing and returns it, or nullptr.
For an RG8 texture this returns the pages of the ACTIVE bake, so EnsureBakedStore() must have selected one first; nullptr means there is nothing to sample (no upload yet, an unsupported format, or a bake that was never requested).
bool nCine:: RHI:: RDP:: RdpTexture:: EnsureBakedStore(const std:: uint32_t* paletteRow,
std:: uint32_t paletteRowIndex,
std:: uint32_t paletteGeneration,
const void* palette)
Makes the active RDP store this RG8 texture baked through one palette row.
Index resolved through paletteRow (256 RGBA8 entries), alpha thresholded from the texel's own alpha byte into RGBA5551's single bit - the analogue of GU::GuTexture::EnsureBakedStore(). Two bakes are cached, so the common "one extra palette row" case (a sprite and its recolored twin drawn in the same frame) rebuilds nothing; AcquireSurface() then hands out the surface of the matching bake. Returns false when the bake could not be produced.
void* nCine:: RHI:: RDP:: RdpTexture:: MapStreamingTexels(std:: int32_t& strideBytes)
Returns a writable pointer to the RDP store, for content that is rebuilt every frame.
Answered only for R8, whose store bytes are the palette indices themselves - which is exactly the format the cinematics produce on the paletted consoles, so a frame is decoded straight where the RDP will read it. Direct-color formats return nullptr (their store is RGBA5551, not the engine layout the writer would produce), and the caller takes the copy-through-a-buffer upload path, which converts.
strideBytes receives the row pitch, which is the 8-byte padded store stride rather than the texture's own width. The caller must rewrite the mapped content in full; the cache writeback for the RDP happens at the next AcquireSurface() (i.e. the next draw that samples this texture).