diff --git a/src/r_draw.cpp b/src/r_draw.cpp index 91de5e102..ed233e387 100644 --- a/src/r_draw.cpp +++ b/src/r_draw.cpp @@ -488,6 +488,92 @@ void R_FlushTranslationColormapCache(void) // in reality, the few routines that can work for either mode, are // put here +enum columncontext_e columncontext = COLUMNCONTEXT_DIRECT; + +enum ColumnFlushType +{ + FLUSH_NONE = 0x0000, + FLUSH_OPAQUE = 0x0001, + FLUSH_TRANS = 0x0002, + FLUSH_COLORMAP = 0x0004, + FLUSH_COLORMAP_TRANS = 0x0008, +}; + +typedef struct drawcolumndata_temp_s +{ + INT32 x; + INT32 yl[8], yh[8]; + + // e6y: resolution limitation is removed + UINT8 *buf; + + INT32 startx; + ColumnFlushType type; + INT32 commontop, commonbot; + UINT8 *transmap; + // SoM 7-28-04: Fix the fuzz problem. + UINT8 *translation; +} drawcolumndata_temp_t; + +drawcolumndata_temp_t temp_dc = {}; + +// +// Error functions that will abort if R_FlushColumns tries to flush +// columns without a column type. +// +FUNCNORETURN static ATTRNORETURN void R_FlushWholeError(void) +{ + I_Error("R_FlushWholeColumns called without being initialized.\n"); +} + +FUNCNORETURN static ATTRNORETURN void R_FlushHTError(void) +{ + I_Error("R_FlushHTColumns called without being initialized.\n"); +} + +FUNCNORETURN static ATTRNORETURN void R_QuadFlushError(void) +{ + I_Error("R_FlushQuadColumn called without being initialized.\n"); +} + +static void (*R_FlushWholeColumns)(void) = R_FlushWholeError; +static void (*R_FlushHTColumns)(void) = R_FlushHTError; +static void (*R_FlushQuadColumn)(void) = R_QuadFlushError; + +static void R_FlushColumns(void) +{ + if (temp_dc.x != 8 || temp_dc.commontop >= temp_dc.commonbot) + R_FlushWholeColumns(); + else + { + R_FlushHTColumns(); + R_FlushQuadColumn(); + } + + temp_dc.x = 0; +} + +// +// R_ResetColumnBuffer +// +// haleyjd 09/13/04: new function to call from main rendering loop +// which gets rid of the unnecessary reset of various variables during +// column drawing. +// +void R_ResetColumnBuffer(void) +{ + // haleyjd 10/06/05: this must not be done if x == 0! + if (temp_dc.x) + { + R_FlushColumns(); + } + + temp_dc.type = FLUSH_NONE; + R_FlushWholeColumns = R_FlushWholeError; + R_FlushHTColumns = R_FlushHTError; + R_FlushQuadColumn = R_QuadFlushError; +} + /** \brief The R_InitViewBuffer function Creates lookup tables for getting the framebuffer address @@ -532,7 +618,26 @@ void R_InitViewBuffer(INT32 width, INT32 height) viewwindowx = 0; viewwindowy = 0; + INT32 bufsize = (vid.width * 8) * sizeof(*temp_dc.buf); + if (temp_dc.buf) + { +#if defined(__SSE__) + aligned_free(temp_dc.buf); +#else + Z_Free(temp_dc.buf); +#endif + } + + memset(&temp_dc, 0, sizeof(temp_dc)); + +#if defined(__SSE__) + while (bufsize & 15) + bufsize++; + temp_dc.buf = static_cast(aligned_alloc(16, bufsize)); +#else + temp_dc.buf = static_cast(Z_Calloc(bufsize, PU_STATIC, NULL)); +#endif } /** \brief The R_VideoErase function diff --git a/src/r_draw.h b/src/r_draw.h index eaee19039..cd1356522 100644 --- a/src/r_draw.h +++ b/src/r_draw.h @@ -100,6 +100,16 @@ extern floatv3_t *ds_su, *ds_sv, *ds_sz; extern float focallengthf; +enum columncontext_e +{ + COLUMNCONTEXT_DIRECT = 0, + COLUMNCONTEXT_FLUSH, +}; + +extern enum columncontext_e columncontext; +void R_SetColumnContext(enum columncontext_e _columncontext); + +void R_ResetColumnBuffer(void); typedef void (coldrawfunc_t)(drawcolumndata_t*); typedef void (spandrawfunc_t)(drawspandata_t*); @@ -220,8 +230,18 @@ void R_DrawTranslatedTranslucentColumn(drawcolumndata_t* dc); void R_Draw2sMultiPatchColumn(drawcolumndata_t* dc); void R_Draw2sMultiPatchTranslucentColumn(drawcolumndata_t* dc); +// column drawers which use buffered drawing with flush +void R_DrawColumnFlush(drawcolumndata_t* dc); +void R_DrawTranslucentColumnFlush(drawcolumndata_t* dc); +void R_DrawTranslatedColumnFlush(drawcolumndata_t* dc); +void R_DrawColumnShadowedFlush(drawcolumndata_t* dc); +void R_DrawTranslatedTranslucentColumnFlush(drawcolumndata_t* dc); +void R_Draw2sMultiPatchColumnFlush(drawcolumndata_t* dc); +void R_Draw2sMultiPatchTranslucentColumnFlush(drawcolumndata_t* dc); + void R_DrawFogColumn(drawcolumndata_t* dc); + // span drawers void R_DrawSpan(drawspandata_t* ds); diff --git a/src/r_draw_column.cpp b/src/r_draw_column.cpp index bae220e6d..3ac814e8d 100644 --- a/src/r_draw_column.cpp +++ b/src/r_draw_column.cpp @@ -21,6 +21,8 @@ // a has a constant z depth from top to bottom. // +#include "r_draw_flush.cpp" + enum DrawColumnType { DC_BASIC = 0x0000, @@ -28,10 +30,12 @@ enum DrawColumnType DC_TRANSMAP = 0x0002, DC_HOLES = 0x0004, DC_LIGHTLIST = 0x0008, + DC_DIRECT = 0x0010, // draw our columns directly to screen! }; template -static constexpr UINT8 R_GetColumnTranslated(drawcolumndata_t* dc, UINT8 col, const UINT8 * restrict colormap) +FUNCINLINE static ATTRINLINE constexpr UINT8 +R_GetColumnTranslated(const drawcolumndata_t* dc, UINT8 col, const UINT8 * restrict colormap) { if constexpr (Type & DrawColumnType::DC_COLORMAP) { @@ -41,8 +45,10 @@ static constexpr UINT8 R_GetColumnTranslated(drawcolumndata_t* dc, UINT8 col, co return colormap[col]; } +// translucency is handled on flush side now! template -static constexpr UINT8 R_GetColumnTranslucent(drawcolumndata_t* dc, UINT8 * restrict dest, UINT8 col, const UINT8 * restrict colormap) +FUNCINLINE static ATTRINLINE constexpr UINT8 +R_GetColumnTranslucent(const drawcolumndata_t* dc, UINT8 * restrict dest, UINT8 col, const UINT8 * restrict colormap) { col = R_GetColumnTranslated(dc, col, colormap); @@ -57,7 +63,8 @@ static constexpr UINT8 R_GetColumnTranslucent(drawcolumndata_t* dc, UINT8 * rest } template -static constexpr UINT8 R_DrawColumnPixel(drawcolumndata_t* dc, UINT8 * restrict dest, UINT32 bit, const UINT8 * restrict source, const UINT8 * restrict colormap) +FUNCINLINE static ATTRINLINE constexpr UINT8 +R_DrawColumnPixel(const drawcolumndata_t* dc, UINT8 * restrict dest, UINT32 bit, const UINT8 * restrict source, const UINT8 * restrict colormap) { UINT8 col = source[bit]; @@ -69,7 +76,14 @@ static constexpr UINT8 R_DrawColumnPixel(drawcolumndata_t* dc, UINT8 * restrict } } - return R_GetColumnTranslucent(dc, dest, col, colormap); + if constexpr (Type & DrawColumnType::DC_DIRECT) + { // if we dont buffer our columns, we need to handle translucency again + return R_GetColumnTranslucent(dc, dest, col, colormap); + } + else + { + return R_GetColumnTranslated(dc, col, colormap); + } } /** \brief The R_DrawColumn function @@ -80,8 +94,18 @@ static void R_DrawColumnTemplate(drawcolumndata_t *dc) { INT32 count; + // leban 1/17/99: + // removed the + 1 here, adjusted the if test, and added an increment + // later. this helps a compiler pipeline a bit better. the x86 + // assembler also does this. count = dc->yh - dc->yl; + // leban 1/17/99: + // this case isn't executed too often. depending on how many instructions + // there are between here and the second if test below, this case could + // be moved down and might save instructions overall. since there are + // probably different wads that favor one way or the other, i'll leave + // this alone for now. if (count < 0) // Zero length, column does not exceed a pixel. { return; @@ -150,6 +174,7 @@ static void R_DrawColumnTemplate(drawcolumndata_t *dc) } R_DrawColumnTemplate(&dc_copy); + if (solid) { dc_copy.yl = bheight; @@ -183,19 +208,37 @@ static void R_DrawColumnTemplate(drawcolumndata_t *dc) // killough 2/1/98: more performance tuning intptr_t frac; + // Looks familiar. const intptr_t fracstep = dc->iscale; - const intptr_t heightmask = dc->sourcelength-1; + const intptr_t heightmask = dc->sourcelength-1; // CPhipps - specify type constexpr INT32 npow2min = -1; const INT32 npow2max = dc->sourcelength; - const INT32 stride = vid.width; const UINT8 * restrict source = dc->source; const lighttable_t * restrict colormap = dc->colormap; // Framebuffer destination address. - UINT8 * restrict dest = R_Address(dc->x, dc->yl); + // SoM: MAGIC + UINT8 * restrict dest; - count++; + if constexpr (Type & DrawColumnType::DC_DIRECT) + dest = R_Address(dc->x, dc->yl); + else if constexpr ((Type & (DrawColumnType::DC_COLORMAP | DrawColumnType::DC_TRANSMAP)) + == (DrawColumnType::DC_COLORMAP | DrawColumnType::DC_TRANSMAP)) + dest = R_GetBufferColormapTrans(dc); + else if constexpr (Type & DrawColumnType::DC_TRANSMAP) + dest = R_GetBufferTrans(dc); + else if constexpr (Type & DrawColumnType::DC_COLORMAP) + dest = R_GetBufferColormap(dc); + else + dest = R_GetBufferOpaque(dc); + + INT32 stride = 8; //SoM: Oh, Oh it's MAGIC! You know... + + if constexpr (Type & DrawColumnType::DC_DIRECT) + stride = vid.width; + + count++; // killough 1/99: minor tuning // Determine scaling, which is the only mapping to be done. frac = (dc->texturemid + FixedMul((dc->yl << FRACBITS) - centeryfrac, fracstep)); @@ -205,15 +248,16 @@ static void R_DrawColumnTemplate(drawcolumndata_t *dc) case 255: case 127: { - while(count--) + while (count--) { *dest = R_DrawColumnPixel(dc, dest, (frac>>FRACBITS) & heightmask, source, colormap); + dest += stride; frac += fracstep; } } break; - case -1: + case npow2min: { if (frac < 0) // adjust in case we underread @@ -223,6 +267,7 @@ static void R_DrawColumnTemplate(drawcolumndata_t *dc) while (--count >= 0) { *dest = R_DrawColumnPixel(dc, dest, frac>>FRACBITS, source, colormap); + dest += stride; frac += fracstep; } @@ -235,10 +280,12 @@ static void R_DrawColumnTemplate(drawcolumndata_t *dc) while ((count -= 2) >= 0) // texture height is a power of 2 -- killough { *dest = R_DrawColumnPixel(dc, dest, (frac>>FRACBITS) & heightmask, source, colormap); + dest += stride; frac += fracstep; *dest = R_DrawColumnPixel(dc, dest, (frac>>FRACBITS) & heightmask, source, colormap); + dest += stride; frac += fracstep; } @@ -271,7 +318,7 @@ static void R_DrawColumnTemplate(drawcolumndata_t *dc) { // Re-map color indices from wall texture column // using a lighting/special effects LUT. - // heightmask is the Tutti-Frutti fix + // heightmask is the Tutti-Frutti fix -- killough // -1 is the lower clamp bound because column posts have a "safe" byte before the real data // and a few bytes after as well @@ -311,13 +358,24 @@ static void R_DrawColumnTemplate(drawcolumndata_t *dc) R_DrawColumnTemplate(dc); \ } -DEFINE_COLUMN_FUNC(R_DrawColumn, DC_BASIC) -DEFINE_COLUMN_FUNC(R_DrawTranslucentColumn, DC_TRANSMAP) -DEFINE_COLUMN_FUNC(R_DrawTranslatedColumn, DC_COLORMAP) -DEFINE_COLUMN_FUNC(R_DrawColumnShadowed, DC_LIGHTLIST) -DEFINE_COLUMN_FUNC(R_DrawTranslatedTranslucentColumn, DC_COLORMAP|DC_TRANSMAP) -DEFINE_COLUMN_FUNC(R_Draw2sMultiPatchColumn, DC_HOLES) -DEFINE_COLUMN_FUNC(R_Draw2sMultiPatchTranslucentColumn, DC_HOLES|DC_TRANSMAP) +DEFINE_COLUMN_FUNC(R_DrawColumn, DC_DIRECT|DC_BASIC) +DEFINE_COLUMN_FUNC(R_DrawTranslucentColumn, DC_DIRECT|DC_TRANSMAP) +DEFINE_COLUMN_FUNC(R_DrawTranslatedColumn, DC_DIRECT|DC_COLORMAP) +DEFINE_COLUMN_FUNC(R_DrawColumnShadowed, DC_DIRECT|DC_LIGHTLIST) +DEFINE_COLUMN_FUNC(R_DrawTranslatedTranslucentColumn, DC_DIRECT|DC_COLORMAP|DC_TRANSMAP) +DEFINE_COLUMN_FUNC(R_Draw2sMultiPatchColumn, DC_DIRECT|DC_HOLES) +DEFINE_COLUMN_FUNC(R_Draw2sMultiPatchTranslucentColumn, DC_DIRECT|DC_HOLES|DC_TRANSMAP) + +DEFINE_COLUMN_FUNC(R_DrawColumnFlush, DC_BASIC) +DEFINE_COLUMN_FUNC(R_DrawTranslucentColumnFlush, DC_TRANSMAP) +DEFINE_COLUMN_FUNC(R_DrawTranslatedColumnFlush, DC_COLORMAP) +DEFINE_COLUMN_FUNC(R_DrawColumnShadowedFlush, DC_LIGHTLIST) +DEFINE_COLUMN_FUNC(R_DrawTranslatedTranslucentColumnFlush, DC_COLORMAP|DC_TRANSMAP) +DEFINE_COLUMN_FUNC(R_Draw2sMultiPatchColumnFlush, DC_HOLES) +DEFINE_COLUMN_FUNC(R_Draw2sMultiPatchTranslucentColumnFlush, DC_HOLES|DC_TRANSMAP) + +//skymyass +//DEFINE_COLUMN_FUNC(R_DrawSkyColumn, DC_SKY) /** \brief The R_DrawFogColumn function Fog wall. diff --git a/src/r_draw_flush.cpp b/src/r_draw_flush.cpp new file mode 100644 index 000000000..80da61705 --- /dev/null +++ b/src/r_draw_flush.cpp @@ -0,0 +1,247 @@ +// SONIC ROBO BLAST 2 KART +//----------------------------------------------------------------------------- +// Copyright (C) 2025 by Kart Krew. +// Copyright (C) 2020 by Sonic Team Junior. +// Copyright (C) 2000 by DooM Legacy Team. +// Copyright (C) 1996 by id Software, Inc. +// Copyright (C) 1999 by Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman +// Copyright (C) 1999-2000 by Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze +// Copyright (C) Copyright 2005, 2006 by Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko +// Copyright (C) 2013 by James Haley, Stephen McGranahan, et al. +// +// This program is free software distributed under the +// terms of the GNU General Public License, version 2. +// See the 'LICENSE' file for more details. +//----------------------------------------------------------------------------- +/// \file r_draw_flush.cpp +/// \brief Optimized quad column buffer code. By SoM. +/// \note no includes because this is included as part of r_draw.cpp + +template +FUNCINLINE static ATTRINLINE constexpr UINT8 +R_GetFlushPixelTranslated(const drawcolumndata_temp_t *t_dc, UINT8 col) +{ + if constexpr (Type & (ColumnFlushType::FLUSH_COLORMAP | ColumnFlushType::FLUSH_COLORMAP_TRANS)) + { + col = t_dc->translation[col]; + } + + return col; +} + +template +FUNCINLINE static ATTRINLINE constexpr UINT8 +R_GetFlushPixelTranslucent(const drawcolumndata_temp_t *t_dc, UINT8 * restrict dest, UINT8 col) +{ + col = R_GetFlushPixelTranslated(t_dc, col); + + if constexpr (Type & (ColumnFlushType::FLUSH_TRANS | ColumnFlushType::FLUSH_COLORMAP_TRANS)) + { + // haleyjd 09/11/04: use temptranmap here + return *(t_dc->transmap + (col << 8) + (*dest)); + } + else + { + return col; + } +} + +template +FUNCINLINE static ATTRINLINE constexpr UINT8 +R_DrawFlushPixel(const drawcolumndata_temp_t *t_dc, UINT8 * restrict dest, const UINT8 * restrict source) +{ + UINT8 col = *source; + return R_GetFlushPixelTranslucent(t_dc, dest, col); +} + +// +// R_FlushWhole +// +// Flushes the entire columns in the buffer, one at a time. +// This is used when a quad flush isn't possible. +// +template +static void R_FlushWhole(void) +{ + UINT8 * restrict source; + UINT8 * restrict dest; + INT32 count, yl; + const INT32 stride = vid.width; + drawcolumndata_temp_t *t_dc = &temp_dc; + UINT8 *restrict buf = t_dc->buf; + + while (--t_dc->x >= 0) + { + yl = t_dc->yl[t_dc->x]; + source = &buf[t_dc->x + (yl << 3)]; + dest = R_Address(t_dc->startx + t_dc->x, yl); + count = t_dc->yh[t_dc->x] - yl + 1; + + while (--count >= 0) + { + *dest = R_DrawFlushPixel(t_dc, dest, source); + source += 8; + dest += stride; + } + } +} + +// +// R_FlushHT +// +// Flushes the head and tail of columns in the buffer in +// preparation for a quad flush. +// +template +static void R_FlushHT(void) +{ + UINT8 * restrict source; + UINT8 * restrict dest; + INT32 count, colnum = 0; + INT32 yl, yh; + const INT32 stride = vid.width; + const drawcolumndata_temp_t *t_dc = &temp_dc; + UINT8 *restrict buf = t_dc->buf; + + while (colnum < 8) + { + yl = t_dc->yl[colnum]; + yh = t_dc->yh[colnum]; + + // flush column head + if (yl < t_dc->commontop) + { + source = &buf[colnum + (yl << 3)]; + dest = R_Address(t_dc->startx + colnum, yl); + count = t_dc->commontop - yl; + + while (--count >= 0) + { + *dest = R_DrawFlushPixel(t_dc, dest, source); + source += 8; + dest += stride; + } + } + + // flush column tail + if (yh > t_dc->commonbot) + { + source = &buf[colnum + ((t_dc->commonbot + 1) << 3)]; + dest = R_Address(t_dc->startx + colnum, t_dc->commonbot + 1); + count = yh - t_dc->commonbot; + + while (--count >= 0) + { + *dest = R_DrawFlushPixel(t_dc, dest, source); + source += 8; + dest += stride; + } + } + + ++colnum; + } +} + +// Begin: Quad column flushing functions. +template +static void R_FlushQuad(void) +{ + const INT32 stride = vid.width; + const drawcolumndata_temp_t *t_dc = &temp_dc; + INT32 count = t_dc->commonbot - t_dc->commontop + 1; + const UINT8 *restrict buf = t_dc->buf; + + if constexpr (Type & ColumnFlushType::FLUSH_OPAQUE) + { + const INT64 *source = reinterpret_cast(buf + (t_dc->commontop << 3)); + INT64 *dest = reinterpret_cast(R_Address(t_dc->startx, t_dc->commontop)); + const INT32 deststep = stride / 8; + + while (--count >= 0) + { + *dest = *source++; + dest += deststep; + } + } + else + { + const UINT8 * restrict source = buf + (t_dc->commontop << 3); + UINT8 * restrict dest = R_Address(t_dc->startx, t_dc->commontop); + + while (--count >= 0) + { + dest[0] = R_DrawFlushPixel(t_dc, &dest[0], &source[0]); + dest[1] = R_DrawFlushPixel(t_dc, &dest[1], &source[1]); + dest[2] = R_DrawFlushPixel(t_dc, &dest[2], &source[2]); + dest[3] = R_DrawFlushPixel(t_dc, &dest[3], &source[3]); + dest[4] = R_DrawFlushPixel(t_dc, &dest[4], &source[4]); + dest[5] = R_DrawFlushPixel(t_dc, &dest[5], &source[5]); + dest[6] = R_DrawFlushPixel(t_dc, &dest[6], &source[6]); + dest[7] = R_DrawFlushPixel(t_dc, &dest[7], &source[7]); + source += 8; + dest += stride; + } + } +} + +// haleyjd 09/12/04: split up R_GetBuffer into various different +// functions to minimize the number of branches and take advantage +// of as much precalculated information as possible. +template +static UINT8 *R_GetBuffer(drawcolumndata_t *dc) +{ + drawcolumndata_temp_t *t_dc = &temp_dc; + + // haleyjd: reordered predicates + if (t_dc->x == 8 || + (t_dc->x && (t_dc->type != Type || t_dc->x + t_dc->startx != dc->x))) + R_FlushColumns(); + + if (!t_dc->x) + { + ++t_dc->x; + t_dc->startx = dc->x; + t_dc->yl[0] = t_dc->commontop = dc->yl; + t_dc->yh[0] = t_dc->commonbot = dc->yh; + t_dc->type = Type; + + if constexpr (Type & (ColumnFlushType::FLUSH_TRANS | ColumnFlushType::FLUSH_COLORMAP_TRANS)) + { + t_dc->transmap = dc->transmap; + } + + if constexpr (Type & (ColumnFlushType::FLUSH_COLORMAP | ColumnFlushType::FLUSH_COLORMAP_TRANS)) + { + t_dc->translation = dc->translation; + } + + R_FlushWholeColumns = R_FlushWhole; + R_FlushHTColumns = R_FlushHT; + R_FlushQuadColumn = R_FlushQuad; + + return &t_dc->buf[dc->yl << 3]; + } + + t_dc->yl[t_dc->x] = dc->yl; + t_dc->yh[t_dc->x] = dc->yh; + + if (dc->yl > t_dc->commontop) + t_dc->commontop = dc->yl; + if (dc->yh < t_dc->commonbot) + t_dc->commonbot = dc->yh; + + return &t_dc->buf[(dc->yl << 3) + t_dc->x++]; +} + +#define DEFINE_GETBUF_FUNC(name, flags) \ + FUNCINLINE static ATTRINLINE UINT8 *name(drawcolumndata_t *dc) \ + { \ + constexpr ColumnFlushType opt = static_cast(flags); \ + return R_GetBuffer(dc); \ + } + +DEFINE_GETBUF_FUNC(R_GetBufferOpaque, FLUSH_OPAQUE) +DEFINE_GETBUF_FUNC(R_GetBufferTrans, FLUSH_TRANS) +DEFINE_GETBUF_FUNC(R_GetBufferColormap, FLUSH_COLORMAP) +DEFINE_GETBUF_FUNC(R_GetBufferColormapTrans, FLUSH_COLORMAP_TRANS) + diff --git a/src/r_draw_span.cpp b/src/r_draw_span.cpp index cfa053382..b1870685c 100644 --- a/src/r_draw_span.cpp +++ b/src/r_draw_span.cpp @@ -50,7 +50,8 @@ enum DrawSpanType }; template -static constexpr UINT8 R_GetSpanTranslated(drawspandata_t* ds, UINT8 col) +FUNCINLINE static ATTRINLINE constexpr UINT8 +R_GetSpanTranslated(const drawspandata_t* ds, UINT8 col) { if constexpr (Type & DrawSpanType::DS_COLORMAP) { @@ -63,7 +64,8 @@ static constexpr UINT8 R_GetSpanTranslated(drawspandata_t* ds, UINT8 col) } template -static constexpr UINT8 R_GetSpanTranslucent(drawspandata_t* ds, UINT8 *dsrc, const UINT8 *colormap, UINT8 col) +FUNCINLINE static ATTRINLINE constexpr UINT8 +R_GetSpanTranslucent(const drawspandata_t* ds, UINT8 *dsrc, const UINT8 *colormap, UINT8 col) { col = colormap[R_GetSpanTranslated(ds, col)]; @@ -78,7 +80,8 @@ static constexpr UINT8 R_GetSpanTranslucent(drawspandata_t* ds, UINT8 *dsrc, con } template -static constexpr UINT8 R_DrawSpanPixel(drawspandata_t* ds, UINT8 *dsrc, const UINT8 *colormap, UINT32 bit, const UINT8 *source) +FUNCINLINE static ATTRINLINE constexpr UINT8 +R_DrawSpanPixel(const drawspandata_t* ds, UINT8 *dsrc, const UINT8 *colormap, UINT32 bit, const UINT8 *source) { UINT8 col = source[bit]; @@ -157,14 +160,18 @@ static void R_DrawSpanTemplate(drawspandata_t* ds) { bit = ((yposition >> ds->nflatyshift) & ds->nflatmask) | (xposition >> ds->nflatxshift); - dest[i] = R_DrawSpanPixel(ds, &dsrc[i], colormap, bit, source); + if constexpr (Type & DS_RIPPLE) + dest[i] = R_DrawSpanPixel(ds, &dsrc[i], colormap, bit, source); + else + dest[i] = R_DrawSpanPixel(ds, &dest[i], colormap, bit, source); xposition += xstep; yposition += ystep; } dest += 8; - dsrc += 8; + if constexpr (Type & DS_RIPPLE) + dsrc += 8; count -= 8; } @@ -173,10 +180,14 @@ static void R_DrawSpanTemplate(drawspandata_t* ds) { bit = ((yposition >> ds->nflatyshift) & ds->nflatmask) | (xposition >> ds->nflatxshift); - *dest = R_DrawSpanPixel(ds, dsrc, colormap, bit, source); + if constexpr (Type & DS_RIPPLE) + *dest = R_DrawSpanPixel(ds, dsrc, colormap, bit, source); + else + *dest = R_DrawSpanPixel(ds, dest, colormap, bit, source); dest++; - dsrc++; + if constexpr (Type & DS_RIPPLE) + dsrc++; xposition += xstep; yposition += ystep; @@ -243,15 +254,14 @@ static void R_DrawTiltedSpanTemplate(drawspandata_t* ds) local_for_thread std::vector tiltlighting; iz = ds->szp.z + ds->szp.y*(centery-ds->y) + ds->szp.x*(ds->x1-centerx); + uz = ds->sup.z + ds->sup.y*(centery-ds->y) + ds->sup.x*(ds->x1-centerx); + vz = ds->svp.z + ds->svp.y*(centery-ds->y) + ds->svp.x*(ds->x1-centerx); // Lighting is simple. It's just linear interpolation from start to end R_GetTiltedLighting(tiltlighting, ds, iz, width, stride); - uz = ds->sup.z + ds->sup.y*(centery-ds->y) + ds->sup.x*(ds->x1-centerx); - vz = ds->svp.z + ds->svp.y*(centery-ds->y) + ds->svp.x*(ds->x1-centerx); - - const UINT8 *source = ds->source; - const UINT8 *colormap = ds->colormap; + const UINT8 * restrict source = ds->source; + const UINT8 * restrict colormap = ds->colormap; if constexpr (Type & DS_RIPPLE) { @@ -313,12 +323,16 @@ static void R_DrawTiltedSpanTemplate(drawspandata_t* ds) { bit = (((v + stepv * i) >> nflatyshift) & nflatmask) | ((u + stepu * i) >> nflatxshift); colormap = ds->planezlight[tiltlighting[x1 + i]] + (ds->colormap - colormaps); - dest[i] = R_DrawSpanPixel(ds, &dsrc[i], colormap, bit, source); + if constexpr (Type & DS_RIPPLE) + dest[i] = R_DrawSpanPixel(ds, &dsrc[i], colormap, bit, source); + else + dest[i] = R_DrawSpanPixel(ds, &dest[i], colormap, bit, source); } ds->x1 += SPANSIZE; dest += SPANSIZE; - dsrc += SPANSIZE; + if constexpr (Type & DS_RIPPLE) + dsrc += SPANSIZE; startu = endu; startv = endv; width -= SPANSIZE; @@ -332,7 +346,10 @@ static void R_DrawTiltedSpanTemplate(drawspandata_t* ds) v = (INT64)(startv); bit = ((v >> nflatyshift) & nflatmask) | (u >> nflatxshift); colormap = ds->planezlight[tiltlighting[ds->x1]] + (ds->colormap - colormaps); - *dest = R_DrawSpanPixel(ds, dsrc, colormap, bit, source); + if constexpr (Type & DS_RIPPLE) + *dest = R_DrawSpanPixel(ds, dsrc, colormap, bit, source); + else + *dest = R_DrawSpanPixel(ds, dest, colormap, bit, source); ds->x1++; } else @@ -355,10 +372,14 @@ static void R_DrawTiltedSpanTemplate(drawspandata_t* ds) { bit = ((v >> ds->nflatyshift) & ds->nflatmask) | (u >> ds->nflatxshift); colormap = ds->planezlight[tiltlighting[ds->x1]] + (ds->colormap - colormaps); - *dest = R_DrawSpanPixel(ds, dsrc, colormap, bit, source); + if constexpr (Type & DS_RIPPLE) + *dest = R_DrawSpanPixel(ds, dsrc, colormap, bit, source); + else + *dest = R_DrawSpanPixel(ds, dest, colormap, bit, source); dest++; + if constexpr (Type & DS_RIPPLE) + dsrc++; ds->x1++; - dsrc++; u += stepu; v += stepv; } @@ -389,11 +410,11 @@ DEFINE_SPAN_COMBO(R_DrawTranslucentWaterSpan, DS_TRANSMAP|DS_RIPPLE) */ void R_DrawFogSpan(drawspandata_t* ds) { + INT32 count = ds->x2 - ds->x1 + 1; + const UINT8 * restrict colormap = ds->colormap; UINT8 * restrict dest = R_Address(ds->x1, ds->y); - intptr_t count = ds->x2 - ds->x1 + 1; - while (count >= 4) { dest[0] = colormap[dest[0]]; @@ -401,7 +422,7 @@ void R_DrawFogSpan(drawspandata_t* ds) dest[2] = colormap[dest[2]]; dest[3] = colormap[dest[3]]; - dest += 4; + dest += 4; count -= 4; } diff --git a/src/r_main.cpp b/src/r_main.cpp index a392db087..37cfed8c5 100644 --- a/src/r_main.cpp +++ b/src/r_main.cpp @@ -1402,9 +1402,12 @@ void R_RenderPlayerView(player_t *player) R_ClearPlanes(); R_ClearSprites(); + R_SetColumnContext(COLUMNCONTEXT_FLUSH); R_RenderViewpoint(&masks[nummasks - 1], false); R_ClipSprites(drawsegs, NULL); + R_ResetColumnBuffer(); + R_SetColumnContext(COLUMNCONTEXT_DIRECT); R_DrawSkyPlanes(); // draw the fucker again to prevent some artifacts R_DrawPlanes(); R_DrawMasked(masks, nummasks); @@ -1439,6 +1442,7 @@ void R_RenderPlayerView(player_t *player) // check for new console commands. NetUpdate(); + R_SetColumnContext(COLUMNCONTEXT_FLUSH); ps_numbspcalls.value.i = ps_numpolyobjects.value.i = ps_numdrawnodes.value.i = 0; PS_START_TIMING(ps_bsptime); R_RenderViewpoint(&masks[nummasks - 1], true); @@ -1446,6 +1450,7 @@ void R_RenderPlayerView(player_t *player) PS_START_TIMING(ps_sw_spritecliptime); R_ClipSprites(drawsegs, NULL); PS_STOP_TIMING(ps_sw_spritecliptime); + R_ResetColumnBuffer(); ps_numsprites.value.i = numvisiblesprites; @@ -1482,12 +1487,14 @@ void R_RenderPlayerView(player_t *player) R_RenderViewpoint(&masks[nummasks - 1], true); R_ClipSprites(ds_p - (masks[nummasks - 1].drawsegs[1] - masks[nummasks - 1].drawsegs[0]), portal); + R_ResetColumnBuffer(); Portal_Remove(portal); } } PS_STOP_TIMING(ps_sw_portaltime); + R_SetColumnContext(COLUMNCONTEXT_DIRECT); PS_START_TIMING(ps_sw_planetime); if (!skybox) R_DrawSkyPlanes(); @@ -1498,7 +1505,6 @@ void R_RenderPlayerView(player_t *player) PS_START_TIMING(ps_sw_maskedtime); R_DrawMasked(masks, nummasks); PS_STOP_TIMING(ps_sw_maskedtime); - free(masks); // Check for new console commands. diff --git a/src/r_plane.cpp b/src/r_plane.cpp index 484aab49c..f4eb61410 100644 --- a/src/r_plane.cpp +++ b/src/r_plane.cpp @@ -716,13 +716,10 @@ void R_DrawPlanes(void) visplane_t *pl; INT32 i; drawspandata_t ds = {}; -#ifdef HAVE_THREADS - srb2::ThreadPool::Sema tp_sema; -#endif - R_UpdatePlaneRipple(&ds); #ifdef HAVE_THREADS + srb2::ThreadPool::Sema tp_sema; srb2::g_main_threadpool->begin_sema(); #endif for (i = 0; i < MAXVISPLANES; i++, pl++) @@ -1159,7 +1156,7 @@ void R_DrawSinglePlane(drawspandata_t* ds, visplane_t *pl, boolean allow_paralle offset = (scry*vid.width) + scrx; // No idea if this works - VID_BlitLinearScreen(renderscreen + offset, + VID_BlitLinearScreen(vid.screens[0] + offset, vid.screens[1] + (top*vid.width), // intentionally not +offset viewwidth, bottom-top, vid.width, vid.width); diff --git a/src/r_things.cpp b/src/r_things.cpp index d69e7ea4e..673fdfc6c 100644 --- a/src/r_things.cpp +++ b/src/r_things.cpp @@ -2801,6 +2801,11 @@ void R_ClipSprites(drawseg_t* dsstart, portal_t* portal) drawseg_t* ds; INT32 i; + if (visspritecount - clippedvissprites <= 0) + { + return; + } + // e6y // Reducing of cache misses in the following R_DrawSprite() // Makes sense for scenes with huge amount of drawsegs. @@ -2810,11 +2815,6 @@ void R_ClipSprites(drawseg_t* dsstart, portal_t* portal) drawsegs_xranges[i].count = 0; } - if (visspritecount - clippedvissprites <= 0) - { - return; - } - if (drawsegs_xrange_size < maxdrawsegs) { // haleyjd: fix reallocation to track 2x size diff --git a/src/screen.c b/src/screen.c index 9a8109066..78cfefd4f 100644 --- a/src/screen.c +++ b/src/screen.c @@ -80,7 +80,7 @@ consvar_t cv_accuratefps = {"fpssampling", "1", CV_SAVE, accuratefps_cons_t, NUL // SCREEN VARIABLES // ========================================================================= -static void SCR_SetDrawFuncs(void) +static void SCR_SetDrawFuncs(enum columncontext_e _columncontext) { // // setup the right draw routines @@ -99,13 +99,27 @@ static void SCR_SetDrawFuncs(void) spanfuncs[SPANDRAWFUNC_FOG] = R_DrawFogSpan; spanfuncs[SPANDRAWFUNC_TILTEDFOG] = R_DrawFogSpan_Tilted; - colfuncs[BASEDRAWFUNC] = R_DrawColumn; - colfuncs[COLDRAWFUNC_FUZZY] = R_DrawTranslucentColumn; - colfuncs[COLDRAWFUNC_TRANS] = R_DrawTranslatedColumn; - colfuncs[COLDRAWFUNC_SHADOWED] = R_DrawColumnShadowed; - colfuncs[COLDRAWFUNC_TRANSTRANS] = R_DrawTranslatedTranslucentColumn; - colfuncs[COLDRAWFUNC_TWOSMULTIPATCH] = R_Draw2sMultiPatchColumn; - colfuncs[COLDRAWFUNC_TWOSMULTIPATCHTRANS] = R_Draw2sMultiPatchTranslucentColumn; + if (_columncontext == COLUMNCONTEXT_FLUSH) + { + colfuncs[BASEDRAWFUNC] = R_DrawColumnFlush; + colfuncs[COLDRAWFUNC_FUZZY] = R_DrawTranslucentColumnFlush; + colfuncs[COLDRAWFUNC_TRANS] = R_DrawTranslatedColumnFlush; + colfuncs[COLDRAWFUNC_SHADOWED] = R_DrawColumnShadowedFlush; + colfuncs[COLDRAWFUNC_TRANSTRANS] = R_DrawTranslatedTranslucentColumnFlush; + colfuncs[COLDRAWFUNC_TWOSMULTIPATCH] = R_Draw2sMultiPatchColumnFlush; + colfuncs[COLDRAWFUNC_TWOSMULTIPATCHTRANS] = R_Draw2sMultiPatchTranslucentColumnFlush; + } + else + { + colfuncs[BASEDRAWFUNC] = R_DrawColumn; + colfuncs[COLDRAWFUNC_FUZZY] = R_DrawTranslucentColumn; + colfuncs[COLDRAWFUNC_TRANS] = R_DrawTranslatedColumn; + colfuncs[COLDRAWFUNC_SHADOWED] = R_DrawColumnShadowed; + colfuncs[COLDRAWFUNC_TRANSTRANS] = R_DrawTranslatedTranslucentColumn; + colfuncs[COLDRAWFUNC_TWOSMULTIPATCH] = R_Draw2sMultiPatchColumn; + colfuncs[COLDRAWFUNC_TWOSMULTIPATCHTRANS] = R_Draw2sMultiPatchTranslucentColumn; + } + colfuncs[COLDRAWFUNC_FOG] = R_DrawFogColumn; R_SetColumnFunc(BASEDRAWFUNC); @@ -127,12 +141,23 @@ void SCR_SetMode(void) V_SetPalette(0); - SCR_SetDrawFuncs(); + SCR_SetDrawFuncs(COLUMNCONTEXT_DIRECT); // set the apprpriate drawer for the sky (tall or INT16) setmodeneeded = 0; } +// used to switch between column buffering and drawing them directly to screen +// our sky "plane" drawer cannot handle the buffer system due to multithreading +// (that would require alot of extra complexity for smth with massive diminishing results) +// Our masked drawing step draws things in a very particular order, which results in alot of flushing to screen +// effectively adding massive overhead due to excessive flushing, so we draw our masked thing directly to screen instead +void R_SetColumnContext(enum columncontext_e _columncontext) +{ + columncontext = _columncontext; + SCR_SetDrawFuncs(_columncontext); // set our column drawers +} + void R_SetColumnFunc(size_t id) { I_Assert(id < COLDRAWFUNC_MAX); diff --git a/src/screen.h b/src/screen.h index fb234324f..0a912e97a 100644 --- a/src/screen.h +++ b/src/screen.h @@ -94,6 +94,7 @@ extern consvar_t cv_vidwait; extern consvar_t cv_votebgscaling; +//void R_SetColumnContext(enum columncontext_e _columncontext); // declared in r_draw! void R_SetColumnFunc(size_t id); void R_SetSpanFunc(size_t id); boolean R_CheckColumnFunc(size_t id);