diff --git a/src/hardware/hw_batching.c b/src/hardware/hw_batching.c index dc0b5ee5b00fae1b28591f78ab3cb39627f11645..a640a9917ad169cbeb8a141e6741614081d251df 100644 --- a/src/hardware/hw_batching.c +++ b/src/hardware/hw_batching.c @@ -116,8 +116,36 @@ void HWR_ProcessPolygon(FSurfaceInfo *pSurf, FOutVector *pOutVerts, FUINT iNumPt polygonArray[polygonArraySize].texture = current_texture; polygonArray[polygonArraySize].shader = shader; polygonArray[polygonArraySize].horizonSpecial = horizonSpecial; + // default to polygonArraySize so we don't lose order on horizon lines + // (yes, it's supposed to be negative, since we're sorting in that direction) + polygonArray[polygonArraySize].hash = -polygonArraySize; polygonArraySize++; + if (!(PolyFlags & PF_NoTexture) && !horizonSpecial) + { + // use FNV-1a to hash polygons for later sorting. + INT32 hash = 0x811c9dc5; +#define DIGEST(h, x) h ^= (x); h *= 0x01000193 + if (current_texture) + { + 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 + // remove the sign bit to ensure that skybox and horizon line comes first. + polygonArray[polygonArraySize-1].hash = (hash & INT32_MAX); + } + memcpy(&unsortedVertexArray[unsortedVertexArraySize], pOutVerts, iNumPts * sizeof(FOutVector)); unsortedVertexArraySize += iNumPts; } @@ -135,84 +163,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 +214,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 @@ -362,46 +310,45 @@ void HWR_RenderBatches(void) { // check if a state change is required, set the change bools and next vars int nextIndex = polygonIndexArray[polygonReadPos]; - nextShader = polygonArray[nextIndex].shader; - nextTexture = polygonArray[nextIndex].texture; - nextPolyFlags = polygonArray[nextIndex].polyFlags; - nextSurfaceInfo = polygonArray[nextIndex].surf; - if (nextPolyFlags & PF_NoTexture) - nextTexture = 0; - if (currentShader != nextShader && cv_glshaders.value && gl_shadersavailable) - { - changeState = true; - changeShader = true; - } - if (currentTexture != nextTexture) - { - changeState = true; - changeTexture = true; - } - if (currentPolyFlags != nextPolyFlags) + if (polygonArray[index].hash != polygonArray[nextIndex].hash) { changeState = true; - changePolyFlags = true; - } - if (cv_glshaders.value && gl_shadersavailable) - { - if (currentSurfaceInfo.PolyColor.rgba != nextSurfaceInfo.PolyColor.rgba || - currentSurfaceInfo.TintColor.rgba != nextSurfaceInfo.TintColor.rgba || - currentSurfaceInfo.FadeColor.rgba != nextSurfaceInfo.FadeColor.rgba || - currentSurfaceInfo.LightInfo.light_level != nextSurfaceInfo.LightInfo.light_level || - currentSurfaceInfo.LightInfo.fade_start != nextSurfaceInfo.LightInfo.fade_start || - currentSurfaceInfo.LightInfo.fade_end != nextSurfaceInfo.LightInfo.fade_end) + nextShader = polygonArray[nextIndex].shader; + nextTexture = polygonArray[nextIndex].texture; + nextPolyFlags = polygonArray[nextIndex].polyFlags; + nextSurfaceInfo = polygonArray[nextIndex].surf; + if (nextPolyFlags & PF_NoTexture) + nextTexture = 0; + if (currentShader != nextShader && cv_glshaders.value && gl_shadersavailable) { - changeState = true; - changeSurfaceInfo = true; + changeShader = true; } - } - else - { - if (currentSurfaceInfo.PolyColor.rgba != nextSurfaceInfo.PolyColor.rgba) + if (currentTexture != nextTexture) + { + changeTexture = true; + } + if (currentPolyFlags != nextPolyFlags) { - changeState = true; - changeSurfaceInfo = true; + changePolyFlags = true; + } + if (cv_glshaders.value && gl_shadersavailable) + { + if (currentSurfaceInfo.PolyColor.rgba != nextSurfaceInfo.PolyColor.rgba || + currentSurfaceInfo.TintColor.rgba != nextSurfaceInfo.TintColor.rgba || + currentSurfaceInfo.FadeColor.rgba != nextSurfaceInfo.FadeColor.rgba || + currentSurfaceInfo.LightInfo.light_level != nextSurfaceInfo.LightInfo.light_level || + currentSurfaceInfo.LightInfo.fade_start != nextSurfaceInfo.LightInfo.fade_start || + currentSurfaceInfo.LightInfo.fade_end != nextSurfaceInfo.LightInfo.fade_end) + { + changeSurfaceInfo = true; + } + } + else + { + if (currentSurfaceInfo.PolyColor.rgba != nextSurfaceInfo.PolyColor.rgba) + { + changeSurfaceInfo = true; + } } } } @@ -423,36 +370,39 @@ void HWR_RenderBatches(void) if (stopFlag) break; // change state according to change bools and next vars, update current vars and reset bools - if (changeShader) + if (changeState) { - HWD.pfnSetShader(nextShader); - currentShader = nextShader; - changeShader = false; + if (changeShader) + { + HWD.pfnSetShader(nextShader); + currentShader = nextShader; + changeShader = false; - ps_hw_numshaders.value.i++; - } - if (changeTexture) - { - // texture should be already ready for use from calls to SetTexture during batch collection - HWD.pfnSetTexture(nextTexture); - currentTexture = nextTexture; - changeTexture = false; + ps_hw_numshaders.value.i++; + } + if (changeTexture) + { + // texture should be already ready for use from calls to SetTexture during batch collection + HWD.pfnSetTexture(nextTexture); + currentTexture = nextTexture; + changeTexture = false; - ps_hw_numtextures.value.i++; - } - if (changePolyFlags) - { - currentPolyFlags = nextPolyFlags; - changePolyFlags = false; + ps_hw_numtextures.value.i++; + } + if (changePolyFlags) + { + currentPolyFlags = nextPolyFlags; + changePolyFlags = false; - ps_hw_numpolyflags.value.i++; - } - if (changeSurfaceInfo) - { - currentSurfaceInfo = nextSurfaceInfo; - changeSurfaceInfo = false; + ps_hw_numpolyflags.value.i++; + } + if (changeSurfaceInfo) + { + currentSurfaceInfo = nextSurfaceInfo; + changeSurfaceInfo = false; - ps_hw_numcolors.value.i++; + ps_hw_numcolors.value.i++; + } } // and that should be it? } diff --git a/src/hardware/hw_batching.h b/src/hardware/hw_batching.h index c7fd7afe3098ffaa9510c001e5d79e953e41da81..df1a4c38be5ceeea84fb61fa22ad31b8a8063dea 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; + INT32 hash; } PolygonArrayEntry; void HWR_StartBatching(void);