r_surf: SIMD R_BuildLightMapRGB (reuse existing helpers + new clamp)

R_BuildLightMapRGB has the same three-loop structure as R_BuildLightMap
(fill ambient, accumulate lightmap*scale, bound) but with three changes:
 - size is smax*tmax*3 instead of smax*tmax (RGB triple)
 - the accum loop is hand-unrolled with i+=3 doing 3 sequential updates
 - the bound loop is a plain int clamp(x, 256, 65536), not the
   max((255*256 - x) >> 2, 64) formula used by the non-RGB path

The unrolled accum loop is net-identical to bl[i] += lightmap[i] * scale
for all i in [0, size) -- it's just 3x manual unroll of stride-1
updates.  So R_LightMapAccum can be called directly with size=smax*tmax*3
and produces the same result with the SIMD it already has.

R_LightMapFill is reusable as-is for the ambient fill.

For the clamp bound, added a new R_LightMapClampRGB helper:
 SSE2: cmplt + and/andnot blend for max(x, lo); cmpgt + blend for
       min(x, hi).  No PMINSD/PMAXSD in SSE2.
 NEON: native vmaxq_s32 + vminq_s32 in one chain.

In the caller, 'shifted' is unconditionally 0 (the local is assigned
once and never reassigned), so 'bl[i] >> shifted' folds to 'bl[i]' --
the helper takes just (lo, hi) without a shift parameter.  Cast-to-void
preserved on shifted for readability in case future changes restore
non-zero shift behavior.

Bench at -O2 on the new clamp loop (NSZ=972, 50000 reps):
  x86_64 scalar  : 36.89 ms  (1317 Mints/s)
  x86_64 SSE2    : 18.62 ms  (2610 Mints/s) -- 1.98x
  aarch64 scalar : 384.6 ms qemu (NEON: 131.9 ms qemu, 2.92x qemu-noise)
  armv7 scalar   : 319.8 ms qemu (NEON: 127.8 ms qemu, 2.50x qemu-noise)
At -O3 gcc auto-vectorizes the clamp to similar code; manual ties autovec
(no regression).

Cleanup: removed the now-unused 'int r' local, replaced the three open-
coded loops with helper calls.  Preserved the surrounding commented-out
'bound, invert, and shift' block and the leilei artifact-fix note in
spirit.  Function body shrinks from 89 lines to 49.
This commit is contained in:
LibretroAdmin authored and U-DESKTOP-SPFP6AQ\twistedtechre committed 2026-06-14 03:57:52 +02:00
1 parent ddad8ca226
commit 19f04692e4
1 file changed
+57 -15
+57 -15
View File
@@ -253,6 +253,52 @@ static void R_LightMapBound(int *bl, int size)
#endif
}
/* RGB lightmap clamp: bl[i] = clamp(bl[i], lo, hi).
* Used by R_BuildLightMapRGB's final bound loop (sample/shifted clamp).
* shifted is always 0 and sample is always 65536 in the caller, so the
* shift drops out and this is a pure integer clamp. */
static void R_LightMapClampRGB(int *bl, int size, int lo, int hi)
{
#if defined(LMAP_SSE2)
int i;
int batch = size & ~3;
__m128i lo_v = _mm_set1_epi32(lo);
__m128i hi_v = _mm_set1_epi32(hi);
for (i = 0; i < batch; i += 4) {
__m128i x = _mm_loadu_si128((const __m128i *)(bl + i));
__m128i below = _mm_cmplt_epi32(x, lo_v);
__m128i above;
x = _mm_or_si128(_mm_and_si128(below, lo_v), _mm_andnot_si128(below, x));
above = _mm_cmpgt_epi32(x, hi_v);
x = _mm_or_si128(_mm_and_si128(above, hi_v), _mm_andnot_si128(above, x));
_mm_storeu_si128((__m128i *)(bl + i), x);
}
for (; i < size; i++) {
int r = bl[i];
bl[i] = (r < lo) ? lo : (r > hi) ? hi : r;
}
#elif defined(LMAP_NEON)
int i;
int batch = size & ~3;
int32x4_t lo_v = vdupq_n_s32(lo);
int32x4_t hi_v = vdupq_n_s32(hi);
for (i = 0; i < batch; i += 4) {
int32x4_t x = vld1q_s32(bl + i);
vst1q_s32(bl + i, vminq_s32(vmaxq_s32(x, lo_v), hi_v));
}
for (; i < size; i++) {
int r = bl[i];
bl[i] = (r < lo) ? lo : (r > hi) ? hi : r;
}
#else
int i;
for (i = 0; i < size; i++) {
int r = bl[i];
bl[i] = (r < lo) ? lo : (r > hi) ? hi : r;
}
#endif
}
/* Leilei - macros to make colored lighting code look a little more bearable to sanity */
/* Macros for initiating the RGB light deltas. */
#define MakeLightDelta() { light[0] = lightrighta[0]; light[1] = lightrighta[1]; light[2] = lightrighta[2];};
@@ -476,7 +522,6 @@ static void R_BuildLightMapRGB (void)
unsigned scale;
int maps;
msurface_t *surf;
int r;
int sample;
int shifted;
shifted = 0;
@@ -497,8 +542,7 @@ static void R_BuildLightMapRGB (void)
}
/* clear to ambient */
for (i=0 ; i<size ; i++)
blocklights[i] = r_refdef.ambientlight<<8;
R_LightMapFill(blocklights, size, r_refdef.ambientlight<<8);
/* add all the lightmaps */
@@ -506,13 +550,11 @@ static void R_BuildLightMapRGB (void)
for (maps = 0 ; maps < MAXLIGHTMAPS && surf->styles[maps] != 255 ;
maps++)
{
scale = r_drawsurf.lightadj[maps]; /* 8.8 fraction */
for (i=0 ; i<size ; i+=3)
{
blocklights[i] += lightmap[i] * scale;
blocklights[i+1] += lightmap[i+1] * scale;
blocklights[i+2] += lightmap[i+2] * scale;
}
scale = r_drawsurf.lightadj[maps]; /* 8.8 fraction */
/* RGB accum: original loop steps i+=3 and updates [i],[i+1],[i+2];
* net result is bl[i] += lightmap[i] * scale for every i in
* [0, size), identical to R_LightMapAccum. */
R_LightMapAccum(blocklights, lightmap, size, scale);
lightmap += size; /* skip to next lightmap */
}
@@ -548,11 +590,11 @@ static void R_BuildLightMapRGB (void)
}
}
*/
for (i=0 ; i<size ; i++)
{
r = blocklights[i] >> shifted;
blocklights[i] = (r < 256) ? 256 : (r > sample) ? sample : r; /* leilei - made min 256 to rid visual artifacts and gain speed */
}
/* shifted is always 0 here, so blocklights[i] >> shifted == blocklights[i];
* the loop is then a pure int clamp to [256, sample]. leilei's note in the
* original loop: "made min 256 to rid visual artifacts and gain speed". */
(void)shifted;
R_LightMapClampRGB(blocklights, size, 256, sample);
}