diff --git a/src/hardware/hw_batching.c b/src/hardware/hw_batching.c index dc0b5ee5b..0e3942761 100644 --- a/src/hardware/hw_batching.c +++ b/src/hardware/hw_batching.c @@ -116,8 +116,30 @@ void HWR_ProcessPolygon(FSurfaceInfo *pSurf, FOutVector *pOutVerts, FUINT iNumPt polygonArray[polygonArraySize].texture = current_texture; polygonArray[polygonArraySize].shader = shader; polygonArray[polygonArraySize].horizonSpecial = horizonSpecial; + polygonArray[polygonArraySize].hash = 0; polygonArraySize++; + if (!(PolyFlags & PF_NoTexture) && !horizonSpecial) + { + // use FNV-1a to hash polygons for later sorting. + int32_t hash = 0x811c9dc5; +#define DIGEST(h, x) h ^= (x); h *= 0x01000193 + DIGEST(hash, current_texture->downloaded); + DIGEST(hash, PolyFlags); + DIGEST(hash, pSurf->PolyColor.rgba); + if (cv_glshaders.value && gl_shadersavailable) + { + DIGEST(hash, shader); + DIGEST(hash, pSurf->TintColor.rgba); + DIGEST(hash, pSurf->FadeColor.rgba); + DIGEST(hash, pSurf->LightInfo.light_level); + DIGEST(hash, pSurf->LightInfo.fade_start); + DIGEST(hash, pSurf->LightInfo.fade_end); + } +#undef DIGEST + polygonArray[polygonArraySize-1].hash = hash; + } + memcpy(&unsortedVertexArray[unsortedVertexArraySize], pOutVerts, iNumPts * sizeof(FOutVector)); unsortedVertexArraySize += iNumPts; } @@ -135,84 +157,7 @@ static int comparePolygons(const void *p1, const void *p2) unsigned int index2 = *(const unsigned int*)p2; PolygonArrayEntry* poly1 = &polygonArray[index1]; PolygonArrayEntry* poly2 = &polygonArray[index2]; - int diff; - INT64 diff64; - UINT32 downloaded1 = 0; - UINT32 downloaded2 = 0; - - int shader1 = poly1->shader; - int shader2 = poly2->shader; - // make skywalls and horizon lines first in order - if (poly1->polyFlags & PF_NoTexture || poly1->horizonSpecial) - shader1 = -1; - if (poly2->polyFlags & PF_NoTexture || poly2->horizonSpecial) - shader2 = -1; - diff = shader1 - shader2; - if (diff != 0) return diff; - - // skywalls and horizon lines must retain their order for horizon lines to work - if (shader1 == -1 && shader2 == -1) - return index1 - index2; - - if (poly1->texture) - downloaded1 = poly1->texture->downloaded; // there should be a opengl texture name here, usable for comparisons - if (poly2->texture) - downloaded2 = poly2->texture->downloaded; - diff64 = downloaded1 - downloaded2; - if (diff64 != 0) return diff64; - - diff = poly1->polyFlags - poly2->polyFlags; - if (diff != 0) return diff; - - diff64 = poly1->surf.PolyColor.rgba - poly2->surf.PolyColor.rgba; - if (diff64 < 0) return -1; else if (diff64 > 0) return 1; - diff64 = poly1->surf.TintColor.rgba - poly2->surf.TintColor.rgba; - if (diff64 < 0) return -1; else if (diff64 > 0) return 1; - diff64 = poly1->surf.FadeColor.rgba - poly2->surf.FadeColor.rgba; - if (diff64 < 0) return -1; else if (diff64 > 0) return 1; - - diff = poly1->surf.LightInfo.light_level - poly2->surf.LightInfo.light_level; - if (diff != 0) return diff; - diff = poly1->surf.LightInfo.fade_start - poly2->surf.LightInfo.fade_start; - if (diff != 0) return diff; - diff = poly1->surf.LightInfo.fade_end - poly2->surf.LightInfo.fade_end; - return diff; -} - -static int comparePolygonsNoShaders(const void *p1, const void *p2) -{ - unsigned int index1 = *(const unsigned int*)p1; - unsigned int index2 = *(const unsigned int*)p2; - PolygonArrayEntry* poly1 = &polygonArray[index1]; - PolygonArrayEntry* poly2 = &polygonArray[index2]; - int diff; - INT64 diff64; - - GLMipmap_t *texture1 = poly1->texture; - GLMipmap_t *texture2 = poly2->texture; - UINT32 downloaded1 = 0; - UINT32 downloaded2 = 0; - if (poly1->polyFlags & PF_NoTexture || poly1->horizonSpecial) - texture1 = NULL; - if (poly2->polyFlags & PF_NoTexture || poly2->horizonSpecial) - texture2 = NULL; - if (texture1) - downloaded1 = texture1->downloaded; // there should be a opengl texture name here, usable for comparisons - if (texture2) - downloaded2 = texture2->downloaded; - // skywalls and horizon lines must retain their order for horizon lines to work - if (!texture1 && !texture2) - return index1 - index2; - diff64 = downloaded1 - downloaded2; - if (diff64 != 0) return diff64; - - diff = poly1->polyFlags - poly2->polyFlags; - if (diff != 0) return diff; - - diff64 = poly1->surf.PolyColor.rgba - poly2->surf.PolyColor.rgba; - if (diff64 < 0) return -1; else if (diff64 > 0) return 1; - - return 0; + return poly1->hash - poly2->hash; } // This function organizes the geometry collected by HWR_ProcessPolygon calls into batches and uses @@ -263,10 +208,7 @@ void HWR_RenderBatches(void) // sort polygons PS_START_TIMING(ps_hw_batchsorttime); - if (cv_glshaders.value && gl_shadersavailable) - qsort(polygonIndexArray, polygonArraySize, sizeof(unsigned int), comparePolygons); - else - qsort(polygonIndexArray, polygonArraySize, sizeof(unsigned int), comparePolygonsNoShaders); + qsort(polygonIndexArray, polygonArraySize, sizeof(unsigned int), comparePolygons); PS_STOP_TIMING(ps_hw_batchsorttime); // sort order // 1. shader diff --git a/src/hardware/hw_batching.h b/src/hardware/hw_batching.h index c7fd7afe3..4351737e3 100644 --- a/src/hardware/hw_batching.h +++ b/src/hardware/hw_batching.h @@ -26,6 +26,7 @@ typedef struct int shader; // this tells batching that the plane belongs to a horizon line and must be drawn in correct order with the skywalls boolean horizonSpecial; + uint32_t hash; } PolygonArrayEntry; void HWR_StartBatching(void);