You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Add a Color Format core option: 24-bit and 30-bit truecolor rendering
The software renderer wrote RGB565 unconditionally. That is fine for the
palette's own colours but it quantises everything derived from them: the
light ramp in V_Palette16 carries 64 weights per colour and the Smooth
shading ramp 256, yet a 5-bit channel can only express about 17 distinct
levels of either, so distance shading and smooth gradients band. Native
24/32-bit source art (PNG title cards, the help screen, the intermission
backdrop) was narrowed on the way to the surface for the same reason.
Add a "Color Format" core option selecting the output pixel format:
16bits RGB565 (default, the historical renderer)
24bits (truecolor) XRGB8888
30bits (HDR) XRGB2101010
Both truecolor formats are native pipelines rather than a conversion
stage. The palette (V_PaletteTC), the composed colour tables and the
Smooth ramp are all built at the output's channel width from the same
8-bit gamma-corrected palette source, so no value is ever produced in
565 and re-expanded, and no value passes through 8-bit on its way to
10-bit. Measured on the shading ramp, a 256-step gradient resolves to
roughly 17 levels per channel at 16 bits, about 135 at 24 and close to
the full 256 at 30 -- the gap widening in dark colours, which is where
the banding is most visible.
The renderer twin lives in r_drawtc.c. The column/span/wall-run drawers,
composed-LUT machinery and dispatch tables mirror r_draw.c exactly with a
16->32-bit surface retype; the two 32-bit formats share that single
instantiation, because an opaque drawer writes lut[texel] and is correct
for any format given a format-correct table. Only the read-modify-write
blend kernels carry per-format channel constants, so only those are
compiled twice, from r_drawtcfmt.inl (SSE2 and NEON, with the scalar
forms as the bit-exact references, matching the existing 565 kernels).
Everything that wrote the surface directly is routed the same way: the
direct sprite column, the voxel rasteriser, the skybox scratch, the
plane and wall dynamic-light tints, the underwater tint, the wipe melt
and the ACS overlay compositors. Several of those become simpler rather
than more complex -- the ACS alpha compositors previously expanded the
565 destination to 8 bits, blended, and re-narrowed on store; in
truecolor the blend just runs at the destination's own width.
SURFACE_PIXEL_DEPTH becomes a runtime value (vid_pixelbytes). It was
never used in preprocessor arithmetic, so this is a straight
substitution; the cache and scratch buffers that size themselves from it
needed no other change. The skybox scratch moves from a fixed 8 MB
16-bit static to a lazily sized allocation, which is smaller than before
in the 16-bit build.
Format selection happens once in retro_load_game, before any surface,
palette or table is built. 30-bit is gated on the new
RETRO_ENVIRONMENT_GET_SCREEN_10BPC_CAPABLE query rather than on
SET_PIXEL_FORMAT alone: SET_PIXEL_FORMAT accepts XRGB2101010
unconditionally and the frontend silently narrows the frame when the
driver cannot present 10 bits, and that narrowing truncates where our own
XRGB8888 path rounds. So on a non-capable driver, emitting 10-bit is not
merely wasted work but measurably worse output than rendering 24-bit;
the core falls back to 24-bit and logs why. An older frontend that does
not recognise the call returns false, which the contract defines as "no
guarantee of native 10-bit" -- the same branch. A SET_PIXEL_FORMAT
rejection still degrades 30 -> 24 -> 16 underneath.
Note that XRGB2101010 here is deeper-precision SDR; the core emits no HDR
transfer function or metadata.
Also sync libretro-common with RetroArch f3fea37, which is where that
environment call comes from. Only include/libretro.h differs from the
vendored copy; the other commits in that range touch image/mp4/webm
sources this core does not vendor.
The 16-bit path is untouched and stays the reference: frame-hash output
over Doom, Doom II, Heretic and zdcmp2.pk3 is byte-identical to the
parent commit. 24-bit and 30-bit were checked over the same content
through the title screen, the 3D scene, sprites, the status bar, the
intermission and the wipes.
"Output colour depth. '16bits' is the classic RGB565 renderer. '24bits' renders in full 8-bit-per-channel truecolor, which removes the banding the 16-bit light ramp introduces in distance shading and smooth gradients. '30bits' renders at 10 bits per channel for finer gradients still; it is used only when the frontend can actually present a 10-bit surface, otherwise the core falls back to 24bits automatically.",
0 commit comments