From 1151781920e0ab925cd2e5578474b7da9ebd6a75 Mon Sep 17 00:00:00 2001 From: vortex Date: Mon, 2 May 2011 02:09:59 +0000 Subject: [PATCH] Transparent sorting: added maxdist and array size cvars which can be tweaked to increase performance (can give up to 10-20% with no quality loss on scenes with large amount of blended surfaces). Added "dpnortlight" shader keyword which disables full rtlight rendering on a surface, useful with grass which (when blended) can cause deadly speed loss. git-svn-id: svn://svn.icculus.org/twilight/trunk/darkplaces@11090 d7cf8633-e32d-0410-b094-e92efae38249 ::stable-branch::merge=ec581e708c6874f1e1fa64343421683fd16f8609 --- cl_particles.c | 7 +++--- gl_rmain.c | 9 ++++--- gl_rsurf.c | 3 ++- meshqueue.c | 66 +++++++++++++++++++++++++++++++++++--------------- meshqueue.h | 3 +++ model_brush.h | 2 ++ model_shared.c | 4 +++ model_shared.h | 1 + 8 files changed, 68 insertions(+), 27 deletions(-) diff --git a/cl_particles.c b/cl_particles.c index 392b46b7..43fb79f4 100644 --- a/cl_particles.c +++ b/cl_particles.c @@ -2281,14 +2281,13 @@ static void r_part_newmap(void) CL_Particles_LoadEffectInfo(); } -#define BATCHSIZE 256 -unsigned short particle_elements[BATCHSIZE*6]; -float particle_vertex3f[BATCHSIZE*12], particle_texcoord2f[BATCHSIZE*8], particle_color4f[BATCHSIZE*16]; +unsigned short particle_elements[MESHQUEUE_TRANSPARENT_BATCHSIZE*6]; +float particle_vertex3f[MESHQUEUE_TRANSPARENT_BATCHSIZE*12], particle_texcoord2f[MESHQUEUE_TRANSPARENT_BATCHSIZE*8], particle_color4f[MESHQUEUE_TRANSPARENT_BATCHSIZE*16]; void R_Particles_Init (void) { int i; - for (i = 0;i < BATCHSIZE;i++) + for (i = 0;i < MESHQUEUE_TRANSPARENT_BATCHSIZE;i++) { particle_elements[i*6+0] = i*4+0; particle_elements[i*6+1] = i*4+1; diff --git a/gl_rmain.c b/gl_rmain.c index ffcf1e68..4facb05d 100644 --- a/gl_rmain.c +++ b/gl_rmain.c @@ -121,6 +121,8 @@ cvar_t r_fog_exp2 = {0, "r_fog_exp2", "0", "uses GL_EXP2 fog (as in Nehahra) rat cvar_t r_fog_clear = {0, "r_fog_clear", "1", "clears renderbuffer with fog color before render starts"}; cvar_t r_drawfog = {CVAR_SAVE, "r_drawfog", "1", "allows one to disable fog rendering"}; cvar_t r_transparentdepthmasking = {CVAR_SAVE, "r_transparentdepthmasking", "0", "enables depth writes on transparent meshes whose materially is normally opaque, this prevents seeing the inside of a transparent mesh"}; +cvar_t r_transparent_sortmaxdist = {CVAR_SAVE, "r_transparent_sortmaxdist", "32768", "upper distance limit for transparent sorting"}; +cvar_t r_transparent_sortarraysize = {CVAR_SAVE, "r_transparent_sortarraysize", "4096", "number of distance-sorting layers"}; cvar_t gl_fogenable = {0, "gl_fogenable", "0", "nehahra fog enable (for Nehahra compatibility only)"}; cvar_t gl_fogdensity = {0, "gl_fogdensity", "0.25", "nehahra fog density (recommend values below 0.1) (for Nehahra compatibility only)"}; @@ -4101,6 +4103,8 @@ void GL_Main_Init(void) Cvar_RegisterVariable(&r_fog_clear); Cvar_RegisterVariable(&r_drawfog); Cvar_RegisterVariable(&r_transparentdepthmasking); + Cvar_RegisterVariable(&r_transparent_sortmaxdist); + Cvar_RegisterVariable(&r_transparent_sortarraysize); Cvar_RegisterVariable(&r_texture_dds_load); Cvar_RegisterVariable(&r_texture_dds_save); Cvar_RegisterVariable(&r_texture_sRGB_2d); @@ -9965,8 +9969,7 @@ static void R_DrawSurface_TransparentCallback(const entity_render_t *ent, const int texturenumsurfaces, endsurface; texture_t *texture; const msurface_t *surface; -#define MAXBATCH_TRANSPARENTSURFACES 256 - const msurface_t *texturesurfacelist[MAXBATCH_TRANSPARENTSURFACES]; + const msurface_t *texturesurfacelist[MESHQUEUE_TRANSPARENT_BATCHSIZE]; // if the model is static it doesn't matter what value we give for // wantnormals and wanttangents, so this logic uses only rules applicable @@ -10051,7 +10054,7 @@ static void R_DrawSurface_TransparentCallback(const entity_render_t *ent, const texture = surface->texture; rsurface.texture = R_GetCurrentTexture(texture); // scan ahead until we find a different texture - endsurface = min(i + MAXBATCH_TRANSPARENTSURFACES, numsurfaces); + endsurface = min(i + MESHQUEUE_TRANSPARENT_BATCHSIZE, numsurfaces); texturenumsurfaces = 0; texturesurfacelist[texturenumsurfaces++] = surface; if(FAKELIGHT_ENABLED) diff --git a/gl_rsurf.c b/gl_rsurf.c index 06d8fb03..9d5bca92 100644 --- a/gl_rsurf.c +++ b/gl_rsurf.c @@ -1487,7 +1487,8 @@ void R_Q1BSP_DrawLight(entity_render_t *ent, int numsurfaces, const int *surface for (kend = k;kend < batchnumsurfaces && tex == batchsurfacelist[kend]->texture;kend++) ; // now figure out what to do with this particular range of surfaces - if (!(rsurface.texture->currentmaterialflags & MATERIALFLAG_WALL)) + // VorteX: added MATERIALFLAG_NORTLIGHT + if ((rsurface.texture->currentmaterialflags & (MATERIALFLAG_WALL + MATERIALFLAG_NORTLIGHT)) != MATERIALFLAG_WALL) continue; if (r_waterstate.renderingscene && (rsurface.texture->currentmaterialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_REFLECTION | MATERIALFLAG_CAMERA))) continue; diff --git a/meshqueue.c b/meshqueue.c index a5510be7..aecb6ab6 100644 --- a/meshqueue.c +++ b/meshqueue.c @@ -13,7 +13,14 @@ typedef struct meshqueue_s } meshqueue_t; +int trans_sortarraysize; +meshqueue_t **trans_hash = NULL; +meshqueue_t ***trans_hashpointer = NULL; +extern cvar_t r_transparent_sortarraysize; +extern cvar_t r_transparent_sortmaxdist; + float mqt_viewplanedist; +float mqt_viewmindist; float mqt_viewmaxdist; meshqueue_t *mqt_array; int mqt_count; @@ -24,6 +31,7 @@ void R_MeshQueue_BeginScene(void) mqt_count = 0; mqt_viewplanedist = DotProduct(r_refdef.view.origin, r_refdef.view.forward); mqt_viewmaxdist = 0; + mqt_viewmindist = 999999999; } void R_MeshQueue_AddTransparent(const vec3_t center, void (*callback)(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist), const entity_render_t *ent, int surfacenumber, const rtlight_t *rtlight) @@ -49,47 +57,67 @@ void R_MeshQueue_AddTransparent(const vec3_t center, void (*callback)(const enti mq->dist = DotProduct(center, r_refdef.view.forward) - mqt_viewplanedist; mq->next = NULL; mqt_viewmaxdist = max(mqt_viewmaxdist, mq->dist); + mqt_viewmindist = min(mqt_viewmindist, mq->dist); } void R_MeshQueue_RenderTransparent(void) { - int i; - int hashdist; - int batchnumsurfaces; + int i, hashindex, maxhashindex, batchnumsurfaces; float distscale; const entity_render_t *ent; const rtlight_t *rtlight; void (*callback)(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfaceindices); + int batchsurfaceindex[MESHQUEUE_TRANSPARENT_BATCHSIZE]; meshqueue_t *mqt; - static meshqueue_t *hash[4096], **hashpointer[4096]; - int batchsurfaceindex[256]; + if (!mqt_count) return; - memset(hash, 0, sizeof(hash)); - for (i = 0;i < 4096;i++) - hashpointer[i] = &hash[i]; - distscale = 4095.0f / max(mqt_viewmaxdist, 4095); - for (i = 0, mqt = mqt_array;i < mqt_count;i++, mqt++) + + // check for bad cvars + if (r_transparent_sortarraysize.integer < 1 || r_transparent_sortarraysize.integer > 32768) + Cvar_SetValueQuick(&r_transparent_sortarraysize, bound(1, r_transparent_sortarraysize.integer, 32768)); + if (r_transparent_sortmaxdist.integer < 1 || r_transparent_sortmaxdist.integer > 32768) + Cvar_SetValueQuick(&r_transparent_sortmaxdist, bound(1, r_transparent_sortmaxdist.integer, 32768)); + + // update hash array + if (trans_sortarraysize != r_transparent_sortarraysize.integer) { - // generate index - hashdist = (int) (mqt->dist * distscale); - hashdist = bound(0, hashdist, 4095); + trans_sortarraysize = r_transparent_sortarraysize.integer; + if (trans_hash) + Mem_Free(trans_hash); + trans_hash = Mem_Alloc(cls.permanentmempool, sizeof(trans_hash) * trans_sortarraysize); + if (trans_hashpointer) + Mem_Free(trans_hashpointer); + trans_hashpointer = Mem_Alloc(cls.permanentmempool, sizeof(trans_hashpointer) * trans_sortarraysize); + } + + // build index + memset(trans_hash, 0, sizeof(trans_hash) * trans_sortarraysize); + for (i = 0; i < trans_sortarraysize; i++) + trans_hashpointer[i] = &trans_hash[i]; + distscale = (trans_sortarraysize - 1) / max( min(mqt_viewmaxdist, r_transparent_sortmaxdist.integer) - mqt_viewmindist, 64 ); + maxhashindex = trans_sortarraysize - 1; + for (i = 0, mqt = mqt_array; i < mqt_count; i++, mqt++) + { + hashindex = bound(0, (int)(min(mqt->dist - mqt_viewmindist, r_transparent_sortmaxdist.integer) * distscale - 0.1), maxhashindex); // link to tail of hash chain (to preserve render order) mqt->next = NULL; - *hashpointer[hashdist] = mqt; - hashpointer[hashdist] = &mqt->next; + *trans_hashpointer[hashindex] = mqt; + trans_hashpointer[hashindex] = &mqt->next; } callback = NULL; ent = NULL; rtlight = NULL; batchnumsurfaces = 0; - for (i = 4095;i >= 0;i--) + + // draw + for (i = maxhashindex; i >= 0; i--) { - if (hash[i]) + if (trans_hash[i]) { - for (mqt = hash[i];mqt;mqt = mqt->next) + for (mqt = trans_hash[i]; mqt; mqt = mqt->next) { - if (ent != mqt->ent || rtlight != mqt->rtlight || callback != mqt->callback || batchnumsurfaces >= 256) + if (ent != mqt->ent || rtlight != mqt->rtlight || callback != mqt->callback || batchnumsurfaces >= MESHQUEUE_TRANSPARENT_BATCHSIZE) { if (batchnumsurfaces) callback(ent, rtlight, batchnumsurfaces, batchsurfaceindex); diff --git a/meshqueue.h b/meshqueue.h index 8e5b36e7..f54c4ce3 100644 --- a/meshqueue.h +++ b/meshqueue.h @@ -2,6 +2,9 @@ #ifndef MESHQUEUE_H #define MESHQUEUE_H +// VorteX: seems this value is hardcoded in other several defines as it's changing makes mess +#define MESHQUEUE_TRANSPARENT_BATCHSIZE 256 + void R_MeshQueue_BeginScene(void); void R_MeshQueue_AddTransparent(const vec3_t center, void (*callback)(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist), const entity_render_t *ent, int surfacenumber, const rtlight_t *rtlight); void R_MeshQueue_RenderTransparent(void); diff --git a/model_brush.h b/model_brush.h index cec78463..906594ad 100644 --- a/model_brush.h +++ b/model_brush.h @@ -116,6 +116,8 @@ mplane_t; #define MATERIALFLAG_TRANSDEPTH 33554432 // like refraction, but doesn't distort etc. #define MATERIALFLAG_CAMERA 67108864 +// disable rtlight on surface, use R_LightPoint instead +#define MATERIALFLAG_NORTLIGHT 134217728 // combined mask of all attributes that require depth sorted rendering #define MATERIALFLAGMASK_DEPTHSORTED (MATERIALFLAG_BLENDED | MATERIALFLAG_NODEPTHTEST) // combined mask of all attributes that cause some sort of transparency diff --git a/model_shared.c b/model_shared.c index 9ea0751a..5257863d 100644 --- a/model_shared.c +++ b/model_shared.c @@ -2073,6 +2073,8 @@ void Mod_LoadQ3Shaders(void) shader.dpshadow = true; else if (!strcasecmp(parameter[0], "dpnoshadow")) shader.dpnoshadow = true; + else if (!strcasecmp(parameter[0], "dpnortlight")) + shader.dpnortlight = true; else if (!strcasecmp(parameter[0], "dpreflectcube")) strlcpy(shader.dpreflectcube, parameter[1], sizeof(shader.dpreflectcube)); else if (!strcasecmp(parameter[0], "dpmeshcollisions")) @@ -2420,6 +2422,8 @@ nothing GL_ZERO GL_ONE texture->basematerialflags &= ~MATERIALFLAG_NOSHADOW; if (shader->dpnoshadow) texture->basematerialflags |= MATERIALFLAG_NOSHADOW; + if (shader->dpnortlight) + texture->basematerialflags |= MATERIALFLAG_NORTLIGHT; memcpy(texture->deforms, shader->deforms, sizeof(texture->deforms)); texture->reflectmin = shader->reflectmin; texture->reflectmax = shader->reflectmax; diff --git a/model_shared.h b/model_shared.h index b79c1330..a7ecd4fe 100644 --- a/model_shared.h +++ b/model_shared.h @@ -445,6 +445,7 @@ typedef struct q3shaderinfo_s // dp-specific additions: // shadow control + qboolean dpnortlight; qboolean dpshadow; qboolean dpnoshadow; -- 2.39.2