Faster sorting Algorithm replacement for qsort #118

Merged
alufolie91 merged 8 commits from qs22j into Saturn-Next 2024-03-17 12:18:26 +01:00
8 changed files with 312 additions and 15 deletions

No files matched your search

+1
View File
@@ -459,6 +459,7 @@ DBGNAME?=$(EXENAME).debug
# SRB2kart kart.o on line 433 below
OBJS:=$(i_main_o) \
$(OBJDIR)/comptime.o \
$(OBJDIR)/qs22j.o \
$(OBJDIR)/string.o \
$(OBJDIR)/d_main.o \
$(OBJDIR)/d_protocol.o \
+5 -2
View File
@@ -15,6 +15,9 @@
#include "hw_main.h"
#include "../i_system.h"
#include "../qs22j.h"
// The texture for the next polygon given to HWR_ProcessPolygon.
// Set with HWR_SetCurrentTexture.
GLMipmap_t *current_texture = NULL;
@@ -264,9 +267,9 @@ void HWR_RenderBatches(void)
// sort polygons
PS_START_TIMING(ps_hw_batchsorttime);
if (cv_grshaders.value && gr_shadersavailable)
qsort(polygonIndexArray, polygonArraySize, sizeof(unsigned int), comparePolygons);
qs22j(polygonIndexArray, polygonArraySize, sizeof(unsigned int), comparePolygons);
else
qsort(polygonIndexArray, polygonArraySize, sizeof(unsigned int), comparePolygonsNoShaders);
qs22j(polygonIndexArray, polygonArraySize, sizeof(unsigned int), comparePolygonsNoShaders);
PS_STOP_TIMING(ps_hw_batchsorttime);
// sort order
// 1. shader
+6 -4
View File
@@ -15,6 +15,8 @@
#include "../doomstat.h"
#include "../qs22j.h"
#ifdef HWRENDER
#include "hw_main.h"
#include "hw_glob.h"
@@ -1030,7 +1032,7 @@ void HWR_ProjectWall(FOutVector *wallVerts, FSurfaceInfo *pSurf, FBITFIELD blend
if (HWR_UseShader())
{
shader = SHADER_WALL; // wall shader
shader = SHADER_WALL;
blendmode |= PF_ColorMapped;
}
@@ -1041,7 +1043,7 @@ void HWR_ProjectWall(FOutVector *wallVerts, FSurfaceInfo *pSurf, FBITFIELD blend
blendmode &= ~PF_Masked;
}
HWR_ProcessPolygon(pSurf, wallVerts, 4, blendmode|PF_Modulated|PF_Occlude, shader, false); // wall shader
HWR_ProcessPolygon(pSurf, wallVerts, 4, blendmode|PF_Modulated|PF_Occlude, shader, false);
#ifdef WALLSPLATS
if (gr_curline->linedef->splats && cv_splats.value)
@@ -4433,7 +4435,7 @@ static void HWR_SortVisSprites(void)
{
gr_vsprorder[i] = HWR_GetVisSprite(i);
}
qsort(gr_vsprorder, gr_visspritecount, sizeof(gr_vissprite_t*), CompareVisSprites);
qs22j(gr_vsprorder, gr_visspritecount, sizeof(gr_vissprite_t*), CompareVisSprites);
}
// A drawnode is something that points to a 3D floor, 3D side, or masked
@@ -4641,7 +4643,7 @@ static void HWR_RenderDrawNodes(void)
if (run_end > run_start) // if there are multiple consecutive planes, not just one
{
// consecutive run of planes found, now sort it
qsort(sortindex + run_start, run_end - run_start + 1, sizeof(INT32), CompareDrawNodePlanes);
qs22j(sortindex + run_start, run_end - run_start + 1, sizeof(INT32), CompareDrawNodePlanes);
}
run_start = run_end + 1; // continue looking for runs coming right after this one
}
+8 -6
View File
@@ -50,6 +50,8 @@
#include "p_setup.h"
#include "f_finale.h"
#include "qs22j.h"
#ifdef HWRENDER
#include "hardware/hw_main.h"
#endif
@@ -9739,22 +9741,22 @@ void M_SortServerList(void)
switch(cv_serversort.value)
{
case 0: // Ping.
qsort(serverlist, serverlistcount, sizeof(serverelem_t), ServerListEntryComparator_time);
qs22j(serverlist, serverlistcount, sizeof(serverelem_t), ServerListEntryComparator_time);
break;
case 1: // Modified state.
qsort(serverlist, serverlistcount, sizeof(serverelem_t), ServerListEntryComparator_modified);
qs22j(serverlist, serverlistcount, sizeof(serverelem_t), ServerListEntryComparator_modified);
break;
case 2: // Most players.
qsort(serverlist, serverlistcount, sizeof(serverelem_t), ServerListEntryComparator_numberofplayer_reverse);
qs22j(serverlist, serverlistcount, sizeof(serverelem_t), ServerListEntryComparator_numberofplayer_reverse);
break;
case 3: // Least players.
qsort(serverlist, serverlistcount, sizeof(serverelem_t), ServerListEntryComparator_numberofplayer);
qs22j(serverlist, serverlistcount, sizeof(serverelem_t), ServerListEntryComparator_numberofplayer);
break;
case 4: // Max players.
qsort(serverlist, serverlistcount, sizeof(serverelem_t), ServerListEntryComparator_maxplayer_reverse);
qs22j(serverlist, serverlistcount, sizeof(serverelem_t), ServerListEntryComparator_maxplayer_reverse);
break;
case 5: // Gametype.
qsort(serverlist, serverlistcount, sizeof(serverelem_t), ServerListEntryComparator_gametype);
qs22j(serverlist, serverlistcount, sizeof(serverelem_t), ServerListEntryComparator_gametype);
break;
}
#endif
+278
View File
@@ -0,0 +1,278 @@
// License: 0BSD
//
// Copyright 2022 Raymond Gardner
//
// Permission to use, copy, modify, and/or distribute this software for any
// purpose with or without fee is hereby granted.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
// SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
// IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
//
#include <stddef.h>
#include <stdint.h>
#include "qs22j.h"
#define INSORTTHRESH 5 // if n < this use insertion sort
// MUST be >= 2
#define MIDTHRESH 20 // < this use middle as pivot
#define MEDOF3THRESH 50 // < this use median-of-3 as pivot
// larger subfiles use med-of-3-medians
#define min(a,b) (((a) < (b)) ? (a) : (b))
typedef int32_t WORD;
typedef int64_t DWORD;
typedef void *pref_typ;
// if no uintptr_t, use Bentley-McIlroy trick (undefined behavior)
//#define ptr_to_int(p) (p-(char*)0)
#define ptr_to_int(p) ((uintptr_t)(void *)p)
#define ASWAP(a, b, t) ((void)(t = a, a = b, b = t))
#define SWAP(a, b) if (swap_type) swapf(a, b, size);\
else do {pref_typ t; ASWAP(*(pref_typ*)(a), *(pref_typ*)(b), t);} while (0)
#define COMP(a, b) ((*compar)((void *)(a), (void *)(b)))
static void swapbytes(void *a0, void *b0, size_t n)
{
char *a = a0, *b = b0, t;
do {ASWAP(*a, *b, t); a++; b++;} while (--n);
}
static void swapdword(void *a0, void *b0, size_t n)
{
DWORD *a = a0, *b = b0, t;
ASWAP(*a, *b, t);
(void)n;
}
static void swapdwords(void *a0, void *b0, size_t n)
{
DWORD *a = a0, *b = b0, t;
do {ASWAP(*a, *b, t); a++; b++;} while (n -= sizeof(DWORD));
}
static void swapword(void *a0, void *b0, size_t n)
{
WORD *a = a0, *b = b0, t;
ASWAP(*a, *b, t);
(void)n;
}
static void swapwords(void *a0, void *b0, size_t n)
{
WORD *a = a0, *b = b0, t;
do {ASWAP(*a, *b, t); a++; b++;} while (n -= sizeof(WORD));
}
typedef void (*swapf_typ)(void *, void *, size_t);
static char *med3(char *a, char *b, char *c, int (*compar)(const void *, const void *))
{
return COMP(a, b) < 0 ?
(COMP(b, c) < 0 ? b : COMP(a, c) < 0 ? c : a) :
(COMP(b, c) > 0 ? b : COMP(a, c) > 0 ? c : a);
}
void qs22j(void *base, size_t nmemb, size_t size,
int (*compar)(const void *, const void *))
{
char *stack[2*8*sizeof(size_t)], **sp = stack; // stack and stack pointer
char *left = base; // set up char * base pointer
char *limit = left + nmemb * size; // pointer past end of array
char *i, *ii, *j, *jj; // scan pointers
int ki = 0, kj = 0;
int swap_type = 1;
swapf_typ swapf, vecswapf;
vecswapf = swapf = swapbytes;
if ((ptr_to_int(left) | size) % sizeof(WORD))
{
; // unaligned or not multple of WORD size; swap bytes
}
else if (size == sizeof(DWORD))
{
swapf = swapdword;
vecswapf = swapdwords;
if (size == sizeof(pref_typ))
swap_type = 0;
}
else if (size == sizeof(WORD))
{
swapf = swapword;
vecswapf = swapwords;
if (size == sizeof(pref_typ))
swap_type = 0;
}
else if ((size % sizeof(DWORD)) == 0)
{
swapf = vecswapf = swapdwords;
}
else if ((size % sizeof(WORD)) == 0)
{
swapf = vecswapf = swapwords;
}
for (;;)
{
nmemb = (limit - left) / size;
for (i = left + size; i < limit && COMP(i - size, i) <= 0; i += size)
;
if (i == limit) // if already in order
goto pop;
if (nmemb >= INSORTTHRESH) // otherwise use insertion sort
{
char *right = limit - size;
// best so far? fewer compares, a few more swaps
char *p = left + (nmemb / 2) * size;
if (nmemb >= MIDTHRESH)
{
char *pleft = left + size;
char *pright = right - size;
if (nmemb >= MEDOF3THRESH)
{
size_t k = (nmemb / 8) * size;
pleft = med3(pleft, left + k, left + k * 2, compar);
p = med3(p - k, p, p + k, compar);
pright = med3(right - k * 2, right - k, pright, compar);
}
p = med3(pleft, p, pright, compar);
}
i = ii = left; // i scans left to right
j = jj = right; // j scans right to left
for (;;)
{
while (i <= j)
{
if (i != p && ((ki = COMP(i, p)) >= 0))
{
if (ki)
break;
if (ii == p)
{
p = i;
}
else if (i != ii)
{
SWAP(i, ii);
}
ii += size;
}
i += size;
}
while (i < j)
{
if (j != p && ((kj = COMP(j, p)) <= 0))
{
if (kj)
break;
if (jj == p)
{
p = j;
}
else if (j != jj)
{
SWAP(j, jj);
}
jj -= size;
}
j -= size;
}
if (i >= j)
break;
SWAP(i, j);
i += size;
j -= size;
}
if (p < i)
i -= size;
if (p != i)
{
SWAP(p, i);
}
ptrdiff_t lessthan = i - ii;
size_t k = min(lessthan, ii - left);
if (k)
vecswapf(left, i - k, k);
ptrdiff_t morethan = jj - i;
k = min(morethan, right - jj);
if (k)
vecswapf(i + size, limit - k, k);
if (lessthan > morethan)
{
if (lessthan > 1)
{
sp[0] = left;
sp[1] = left + lessthan;
sp += 2; // increment stack pointer
}
if (morethan <= 1)
goto pop;
left = limit - morethan;
}
else
{
if (morethan > 1)
{
sp[0] = limit - morethan;
sp[1] = limit;
sp += 2; // increment stack pointer
}
if (lessthan <= 1)
goto pop;
limit = left + lessthan;
}
}
else // else subfile is small, use insertion sort
{
for (i = left + size; i < limit; i += size)
{
for (j = i; j != left && COMP(j - size, j) > 0; j -= size)
{
SWAP(j - size, j);
}
}
pop:
if (sp != stack) // if any entries on stack
{
sp -= 2; // pop the left and limit
left = sp[0];
limit = sp[1];
}
else // else stack empty, done
break;
}
}
}
+7
View File
@@ -0,0 +1,7 @@
#ifndef __QS22J__
#define __QS22J__
void qs22j(void *base, size_t nmemb, size_t size,
int (*compar)(const void *, const void *));
#endif
+4 -2
View File
@@ -21,6 +21,8 @@
#include "p_slopes.h"
#include "z_zone.h" // Check R_Prep3DFloors
#include "qs22j.h"
seg_t *curline;
side_t *sidedef;
line_t *linedef;
@@ -725,7 +727,7 @@ void R_SortPolyObjects(subsector_t *sub)
// 03/10/06: only bother if there are actually polys to sort
if (numpolys >= 2)
{
qsort(po_ptrs, numpolys, sizeof(polyobj_t *),
qs22j(po_ptrs, numpolys, sizeof(polyobj_t *),
R_PolyobjCompare);
}
}
@@ -828,7 +830,7 @@ static void R_AddPolyObjects(subsector_t *sub)
// render polyobjects
for (i = 0; i < numpolys; ++i)
{
qsort(po_ptrs[i]->segs, po_ptrs[i]->segCount, sizeof(seg_t *), R_PolysegCompare);
qs22j(po_ptrs[i]->segs, po_ptrs[i]->segCount, sizeof(seg_t *), R_PolysegCompare);
for (j = 0; j < po_ptrs[i]->segCount; ++j)
R_AddLine(po_ptrs[i]->segs[j]);
}
+3 -1
View File
@@ -36,6 +36,8 @@
#include "hardware/hw_md2.h"
#endif
#include "qs22j.h"
#ifdef PC_DOS
#include <stdio.h> // for snprintf
int snprintf(char *str, size_t n, const char *fmt, ...);
@@ -3283,7 +3285,7 @@ static int skinSortFunc(const void *a, const void *b) //tbh i have no clue what
void sortSkinGrid(void)
{
//CONS_Printf("Sorting skin list (%d)...\n", cv_skinselectgridsort.value);
qsort(skinsorted, numskins, sizeof(UINT8), skinSortFunc);
qs22j(skinsorted, numskins, sizeof(UINT8), skinSortFunc);
}
//