From c5bc17ff5ea667ab3aaf2b49b6c09b4a39db07c5 Mon Sep 17 00:00:00 2001 From: NepDisk Date: Fri, 6 Mar 2026 10:43:31 -0500 Subject: [PATCH] Refactor hwr batching code https://git.do.srb2.org/STJr/SRB2/-/merge_requests/1773/diffs\?commit_id\=707687beea50a2bfcc14638e923ac516195351b1 --- src/hardware/hw_batching.c | 553 +++++++++++++++++++------------------ src/hardware/hw_batching.h | 13 - 2 files changed, 278 insertions(+), 288 deletions(-) diff --git a/src/hardware/hw_batching.c b/src/hardware/hw_batching.c index 0add4e753..85997f0c3 100644 --- a/src/hardware/hw_batching.c +++ b/src/hardware/hw_batching.c @@ -15,6 +15,19 @@ #include "../i_system.h" #include "../qs22j.h" +typedef struct +{ + FSurfaceInfo surf; // surf also has its own polyflags for some reason, but it seems unused + unsigned int vertsIndex; // location of verts in unsortedVertices + FUINT numVerts; + FBITFIELD polyFlags; + GLMipmap_t *texture; + GLMipmap_t *brightmap; + 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; +} DrawCallInfo; + // The texture for the next polygon given to HWR_ProcessPolygon. // Set with HWR_SetCurrentTexture. GLMipmap_t *current_texture = NULL; @@ -22,23 +35,36 @@ GLMipmap_t *current_brightmap = NULL; boolean currently_batching = false; -FOutVector* finalVertexArray = NULL;// contains subset of sorted vertices and texture coordinates to be sent to gpu -UINT32* finalVertexIndexArray = NULL;// contains indexes for glDrawElements, taking into account fan->triangles conversion -// NOTE have this alloced as 3x finalVertexArray size -int finalVertexArrayAllocSize = 65536; -//GLubyte* colorArray = NULL;// contains color data to be sent to gpu, if needed -//int colorArrayAllocSize = 65536; -// not gonna use this for now, just sort by color and change state when it changes -// later maybe when using vertex attributes if it's needed +// Dynamic arrays for: +// - unsorted draw calls +// - sorted order of draw calls +// - unsorted vertices +// - final (sorted) vertices +// - vertex indices for sorted vertices -PolygonArrayEntry* polygonArray = NULL;// contains the polygon data from DrawPolygon, waiting to be processed -int polygonArraySize = 0; -UINT32* polygonIndexArray = NULL;// contains sorting pointers for polygonArray -int polygonArrayAllocSize = 65536; +// contains the draw calls from DrawPolygon, waiting to be processed +DrawCallInfo* drawCalls = NULL; +int drawCallsSize = 0; +int drawCallsCapacity = 65536; -FOutVector* unsortedVertexArray = NULL;// contains unsorted vertices and texture coordinates from DrawPolygon -int unsortedVertexArraySize = 0; -int unsortedVertexArrayAllocSize = 65536; +// contains sorted order (array indices) for drawCalls +// (therefore size and capacity shared with it) +UINT32* drawCallOrder = NULL; + +// contains unsorted vertices and texture coordinates from DrawPolygon +FOutVector* unsortedVertices = NULL; +int unsortedVerticesSize = 0; +int unsortedVerticesCapacity = 65536; + +// contains subset of sorted vertices and texture coordinates to be sent to gpu +FOutVector* finalVertices = NULL; +int finalVerticesSize = 0; +int finalVerticesCapacity = 65536; + +// contains vertex indices into finalVertices for glDrawElements, +// taking into account fan->triangles conversion +UINT32* finalIndices = NULL; // this is alloced with 3x finalVertices size +int finalIndicesSize = 0; // Enables batching mode. HWR_ProcessPolygon will collect polygons instead of passing them directly to the rendering backend. // Call HWR_RenderBatches to render all the collected geometry. @@ -48,13 +74,13 @@ void HWR_StartBatching(void) I_Error("Repeat call to HWR_StartBatching without HWR_RenderBatches"); // init arrays if that has not been done yet - if (!finalVertexArray) + if (!finalVertices) { - finalVertexArray = malloc(finalVertexArrayAllocSize * sizeof(FOutVector)); - finalVertexIndexArray = malloc(finalVertexArrayAllocSize * 3 * sizeof(UINT32)); - polygonArray = malloc(polygonArrayAllocSize * sizeof(PolygonArrayEntry)); - polygonIndexArray = malloc(polygonArrayAllocSize * sizeof(UINT32)); - unsortedVertexArray = malloc(unsortedVertexArrayAllocSize * sizeof(FOutVector)); + finalVertices = malloc(finalVerticesCapacity * sizeof(FOutVector)); + finalIndices = malloc(finalVerticesCapacity * 3 * sizeof(UINT32)); + drawCalls = malloc(drawCallsCapacity * sizeof(DrawCallInfo)); + drawCallOrder = malloc(drawCallsCapacity * sizeof(UINT32)); + unsortedVertices = malloc(unsortedVerticesCapacity * sizeof(FOutVector)); } currently_batching = true; @@ -70,9 +96,7 @@ void HWR_SetCurrentTexture(GLMipmap_t *texture) if (texture != NULL) { if (texture->flags & TF_BRIGHTMAP) - { current_brightmap = texture; - } else { current_texture = texture; @@ -80,14 +104,56 @@ void HWR_SetCurrentTexture(GLMipmap_t *texture) } } else - { current_texture = current_brightmap = NULL; - } } else - { GL_SetTexture(texture); +} + +static void HWR_CollectDrawCallInfo(FSurfaceInfo *pSurf, FUINT iNumPts, FBITFIELD PolyFlags, int shader_target, boolean horizonSpecial) +{ + // make sure dynamic array has capacity + if (drawCallsSize == drawCallsCapacity) + { + DrawCallInfo* new_array; + // ran out of space, make new array double the size + drawCallsCapacity *= 2; + new_array = malloc(drawCallsCapacity * sizeof(DrawCallInfo)); + memcpy(new_array, drawCalls, drawCallsSize * sizeof(DrawCallInfo)); + free(drawCalls); + drawCalls = new_array; + // also need to redo the index array, dont need to copy it though + free(drawCallOrder); + drawCallOrder = malloc(drawCallsCapacity * sizeof(UINT32)); } + // add entry to array + drawCalls[drawCallsSize].surf = *pSurf; + drawCalls[drawCallsSize].vertsIndex = unsortedVerticesSize; + drawCalls[drawCallsSize].numVerts = iNumPts; + drawCalls[drawCallsSize].polyFlags = PolyFlags; + drawCalls[drawCallsSize].texture = current_texture; + drawCalls[drawCallsSize].brightmap = current_brightmap; + drawCalls[drawCallsSize].shader = (shader_target != -1) ? HWR_GetShaderFromTarget(shader_target) : shader_target; + drawCalls[drawCallsSize].horizonSpecial = horizonSpecial; + drawCallsSize++; +} + +static void HWR_CollectDrawCallVertices(FOutVector *pOutVerts, FUINT iNumPts) +{ + // make sure dynamic array has capacity + while (unsortedVerticesSize + (int)iNumPts > unsortedVerticesCapacity) + { + FOutVector* new_array; + // need more space for vertices in unsortedVertices + unsortedVerticesCapacity *= 2; + new_array = malloc(unsortedVerticesCapacity * sizeof(FOutVector)); + memcpy(new_array, unsortedVertices, unsortedVerticesSize * sizeof(FOutVector)); + free(unsortedVertices); + unsortedVertices = new_array; + } + // add vertices to array + memcpy(&unsortedVertices[unsortedVerticesSize], pOutVerts, iNumPts * sizeof(FOutVector)); + unsortedVerticesSize += iNumPts; } // If batching is enabled, this function collects the polygon data and the chosen texture @@ -98,46 +164,13 @@ void HWR_ProcessPolygon(FSurfaceInfo *pSurf, FOutVector *pOutVerts, FUINT iNumPt if (currently_batching) { if (!pSurf) - I_Error("Got a null FSurfaceInfo in batching");// nulls should not come in the stuff that batching currently applies to - if (polygonArraySize == polygonArrayAllocSize) { - PolygonArrayEntry* new_array; - // ran out of space, make new array double the size - polygonArrayAllocSize *= 2; - new_array = malloc(polygonArrayAllocSize * sizeof(PolygonArrayEntry)); - memcpy(new_array, polygonArray, polygonArraySize * sizeof(PolygonArrayEntry)); - free(polygonArray); - polygonArray = new_array; - // also need to redo the index array, dont need to copy it though - free(polygonIndexArray); - polygonIndexArray = malloc(polygonArrayAllocSize * sizeof(UINT32)); + // handling null FSurfaceInfo is not implemented + I_Error("Got a null FSurfaceInfo in batching"); } - while (unsortedVertexArraySize + (int)iNumPts > unsortedVertexArrayAllocSize) - { - FOutVector* new_array; - // need more space for vertices in unsortedVertexArray - unsortedVertexArrayAllocSize *= 2; - new_array = malloc(unsortedVertexArrayAllocSize * sizeof(FOutVector)); - memcpy(new_array, unsortedVertexArray, unsortedVertexArraySize * sizeof(FOutVector)); - free(unsortedVertexArray); - unsortedVertexArray = new_array; - } - - // add the polygon data to the arrays - - polygonArray[polygonArraySize].surf = *pSurf; - polygonArray[polygonArraySize].vertsIndex = unsortedVertexArraySize; - polygonArray[polygonArraySize].numVerts = iNumPts; - polygonArray[polygonArraySize].polyFlags = PolyFlags; - polygonArray[polygonArraySize].texture = current_texture; - polygonArray[polygonArraySize].brightmap = current_brightmap; - polygonArray[polygonArraySize].shader = (shader_target != -1) ? HWR_GetShaderFromTarget(shader_target) : shader_target; - polygonArray[polygonArraySize].horizonSpecial = horizonSpecial; - polygonArraySize++; - - memcpy(&unsortedVertexArray[unsortedVertexArraySize], pOutVerts, iNumPts * sizeof(FOutVector)); - unsortedVertexArraySize += iNumPts; + HWR_CollectDrawCallInfo(pSurf, iNumPts, PolyFlags, shader_target, horizonSpecial); + HWR_CollectDrawCallVertices(pOutVerts, iNumPts); } else { @@ -146,12 +179,12 @@ void HWR_ProcessPolygon(FSurfaceInfo *pSurf, FOutVector *pOutVerts, FUINT iNumPt } } -static int comparePolygons(const void *p1, const void *p2) +static int compareDrawCalls(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]; + UINT32 index1 = *(const UINT32*)p1; + UINT32 index2 = *(const UINT32*)p2; + DrawCallInfo* poly1 = &drawCalls[index1]; + DrawCallInfo* poly2 = &drawCalls[index2]; int diff; INT64 diff64; UINT32 downloaded1 = 0; @@ -209,12 +242,12 @@ static int comparePolygons(const void *p1, const void *p2) return diff; } -static int comparePolygonsNoShaders(const void *p1, const void *p2) +static int compareDrawCallsNoShaders(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]; + DrawCallInfo* poly1 = &drawCalls[index1]; + DrawCallInfo* poly2 = &drawCalls[index2]; int diff; INT64 diff64; @@ -245,60 +278,164 @@ static int comparePolygonsNoShaders(const void *p1, const void *p2) return 0; } -// This function organizes the geometry collected by HWR_ProcessPolygon calls into batches and uses -// the rendering backend to draw them. +static void HWR_CollectVerticesIntoBatch(DrawCallInfo *drawCall) +{ + int firstVIndex; + int lastVIndex; + int numVerts = drawCall->numVerts; + // before writing, check if there is enough room + // using 'while' instead of 'if' here makes sure that there will *always* be enough room. + // probably never will this loop run more than once though + while (finalVerticesSize + numVerts > finalVerticesCapacity) + { + FOutVector* new_array; + UINT32* new_index_array; + finalVerticesCapacity *= 2; + new_array = malloc(finalVerticesCapacity * sizeof(FOutVector)); + memcpy(new_array, finalVertices, finalVerticesSize * sizeof(FOutVector)); + free(finalVertices); + finalVertices = new_array; + // also increase size of index array, 3x of vertex array since + // going from fans to triangles increases vertex count to 3x + new_index_array = malloc(finalVerticesCapacity * 3 * sizeof(UINT32)); + memcpy(new_index_array, finalIndices, finalIndicesSize * sizeof(UINT32)); + free(finalIndices); + finalIndices = new_index_array; + } + // write the vertices of the polygon + memcpy(&finalVertices[finalVerticesSize], &unsortedVertices[drawCall->vertsIndex], + numVerts * sizeof(FOutVector)); + // write the indexes, pointing to the fan vertexes but in triangles format + firstVIndex = finalVerticesSize; + lastVIndex = finalVerticesSize + numVerts; + finalVerticesSize += 2; + while (finalVerticesSize < lastVIndex) + { + finalIndices[finalIndicesSize++] = firstVIndex; + finalIndices[finalIndicesSize++] = finalVerticesSize - 1; + finalIndices[finalIndicesSize++] = finalVerticesSize++; + } +} + +static GLMipmap_t *HWR_GetDrawCallTexture(DrawCallInfo *dc) +{ + return (dc->polyFlags & PF_NoTexture) ? NULL : dc->texture; +} + +static GLMipmap_t *HWR_GetDrawCallBrightmap(DrawCallInfo *dc) +{ + return (dc->polyFlags & PF_NoTexture) ? NULL : dc->brightmap; +} + +// flags returned by HWR_MarkStateChanges +#define SHADER_CHANGED 1 +#define TEXTURE_CHANGED 2 +#define POLYFLAGS_CHANGED 4 +#define SURFACEINFO_CHANGED 8 + +static unsigned int HWR_MarkStateChanges(DrawCallInfo *current, DrawCallInfo *next) +{ + unsigned int stateChanges = 0; + FSurfaceInfo *currentSI = ¤t->surf; + FSurfaceInfo *nextSI = &next->surf; + + // check if a state change is required and flag it to stateChanges + + if (current->shader != next->shader && cv_glshaders.value && gl_shadersavailable) + stateChanges |= SHADER_CHANGED; + if (HWR_GetDrawCallTexture(current) != HWR_GetDrawCallTexture(next) + || HWR_GetDrawCallBrightmap(current) != HWR_GetDrawCallBrightmap(next)) + stateChanges |= TEXTURE_CHANGED; + if (current->polyFlags != next->polyFlags) + stateChanges |= POLYFLAGS_CHANGED; + if (cv_glshaders.value && gl_shadersavailable) + { + if (currentSI->PolyColor.rgba != nextSI->PolyColor.rgba || + currentSI->TintColor.rgba != nextSI->TintColor.rgba || + currentSI->FadeColor.rgba != nextSI->FadeColor.rgba || + currentSI->LightInfo.light_level != nextSI->LightInfo.light_level || + currentSI->LightInfo.fade_start != nextSI->LightInfo.fade_start || + currentSI->LightInfo.fade_end != nextSI->LightInfo.fade_end) + { + stateChanges |= SURFACEINFO_CHANGED; + } + } + else + { + if (currentSI->PolyColor.rgba != nextSI->PolyColor.rgba) + stateChanges |= SURFACEINFO_CHANGED; + } + + return stateChanges; +} + +static void HWR_ExecuteStateChanges(unsigned int stateChanges, DrawCallInfo *dc) +{ + if ((stateChanges & SHADER_CHANGED) && cv_glshaders.value && gl_shadersavailable) + { + GL_SetShader(dc->shader); + ps_hw_numshaders++; + } + + if (stateChanges & TEXTURE_CHANGED) + { + // for PF_NoTexture the texture is set in DrawIndexedTriangles + if (!(dc->polyFlags & PF_NoTexture)) + { + // texture should be already ready for use from calls to + // SetTexture during batch collection + GL_SetTexture(dc->texture); + if (dc->brightmap) + GL_SetTexture(dc->brightmap); + } + ps_hw_numtextures++; + } + + // these two are just parameters to DrawIndexedTriangles + // (changes to polyflags states are tracked in r_opengl.c though) + if (stateChanges & POLYFLAGS_CHANGED) + ps_hw_numpolyflags++; + if (stateChanges & SURFACEINFO_CHANGED) + ps_hw_numcolors++; +} + +static void HWR_InitBatchingStats(void) +{ + ps_hw_numpolys = drawCallsSize; + ps_hw_numcalls = ps_hw_numverts + = ps_hw_numshaders = ps_hw_numtextures + = ps_hw_numpolyflags = ps_hw_numcolors = 0; +} + +// This function organizes the geometry and draw calls collected by HWR_ProcessPolygon +// calls into batches and uses the rendering backend to draw them. void HWR_RenderBatches(void) { - int finalVertexWritePos = 0;// position in finalVertexArray - int finalIndexWritePos = 0;// position in finalVertexIndexArray - - int polygonReadPos = 0;// position in polygonIndexArray - - int currentShader; - int nextShader = 0; - GLMipmap_t *currentTexture = NULL; - GLMipmap_t *nextTexture = NULL; - GLMipmap_t *currentBrightmap = NULL; - GLMipmap_t *nextBrightmap = NULL; - FBITFIELD currentPolyFlags = 0; - FBITFIELD nextPolyFlags = 0; - FSurfaceInfo currentSurfaceInfo; - FSurfaceInfo nextSurfaceInfo; - + int drawCallReadPos = 0; // position in drawCallOrder int i; if (!currently_batching) I_Error("HWR_RenderBatches called without starting batching"); - nextSurfaceInfo.LightInfo.fade_end = 0; - nextSurfaceInfo.LightInfo.fade_start = 0; - nextSurfaceInfo.LightInfo.light_level = 0; - nextSurfaceInfo.LightInfo.directional = false; + currently_batching = false; // no longer collecting batches - currently_batching = false;// no longer collecting batches - if (!polygonArraySize) - { - ps_hw_numpolys = ps_hw_numcalls = ps_hw_numshaders = ps_hw_numtextures = ps_hw_numpolyflags = ps_hw_numcolors = 0; - return;// nothing to draw - } - // init stats vars - ps_hw_numpolys = polygonArraySize; - ps_hw_numcalls = ps_hw_numverts = 0; - ps_hw_numshaders = ps_hw_numtextures = ps_hw_numpolyflags = ps_hw_numcolors = 1; - // init polygonIndexArray - for (i = 0; i < polygonArraySize; i++) - { - polygonIndexArray[i] = i; - } + HWR_InitBatchingStats(); - // sort polygons + if (!drawCallsSize) + return; // nothing to draw + + // init drawCallOrder + for (i = 0; i < drawCallsSize; i++) + drawCallOrder[i] = i; + + // sort the draw calls ps_hw_batchsorttime = I_GetPreciseTime(); if (cv_glshaders.value && gl_shadersavailable) - qs22j(polygonIndexArray, polygonArraySize, sizeof(unsigned int), comparePolygons); + qs22j(drawCallOrder, drawCallsSize, sizeof(UINT32), compareDrawCalls); else - qs22j(polygonIndexArray, polygonArraySize, sizeof(unsigned int), comparePolygonsNoShaders); + qs22j(drawCallOrder, drawCallsSize, sizeof(UINT32), compareDrawCallsNoShaders); ps_hw_batchsorttime = I_GetPreciseTime() - ps_hw_batchsorttime; - // sort order + // sort grouping order // 1. shader // 2. texture // 3. brightmap @@ -308,43 +445,15 @@ void HWR_RenderBatches(void) ps_hw_batchdrawtime = I_GetPreciseTime(); - currentShader = polygonArray[polygonIndexArray[0]].shader; - currentTexture = polygonArray[polygonIndexArray[0]].texture; - currentBrightmap = polygonArray[polygonIndexArray[0]].brightmap; - currentPolyFlags = polygonArray[polygonIndexArray[0]].polyFlags; - currentSurfaceInfo = polygonArray[polygonIndexArray[0]].surf; - // For now, will sort and track the colors. Vertex attributes could be used instead of uniforms - // and a color array could replace the color calls. - // set state for first batch + HWR_ExecuteStateChanges(0xFFFF, &drawCalls[drawCallOrder[0]]); - if (cv_glshaders.value && gl_shadersavailable) + // - iterate through draw calls + // - accumulate converted vertices and indices into finalVertices and finalIndices + // and send them as a combined draw call when a state change occurs + while (1) { - GL_SetShader(currentShader); - } - - if (currentPolyFlags & PF_NoTexture) - { - currentTexture = currentBrightmap = NULL; - } - else - { - GL_SetTexture(currentTexture); - if (currentBrightmap) - GL_SetTexture(currentBrightmap); - } - - while (1)// note: remember handling notexture polyflag as having texture number 0 (also in comparePolygons) - { - int firstIndex; - int lastIndex; - boolean stopFlag = false; - boolean changeState = false; - boolean changeShader = false; - boolean changeTexture = false; - boolean changePolyFlags = false; - boolean changeSurfaceInfo = false; // steps: // write vertices @@ -357,152 +466,46 @@ void HWR_RenderBatches(void) // reset write pos // repeat loop - int index = polygonIndexArray[polygonReadPos++]; - int numVerts = polygonArray[index].numVerts; - // before writing, check if there is enough room - // using 'while' instead of 'if' here makes sure that there will *always* be enough room. - // probably never will this loop run more than once though - while (finalVertexWritePos + numVerts > finalVertexArrayAllocSize) - { - FOutVector* new_array; - unsigned int* new_index_array; - finalVertexArrayAllocSize *= 2; - new_array = malloc(finalVertexArrayAllocSize * sizeof(FOutVector)); - memcpy(new_array, finalVertexArray, finalVertexWritePos * sizeof(FOutVector)); - free(finalVertexArray); - finalVertexArray = new_array; - // also increase size of index array, 3x of vertex array since - // going from fans to triangles increases vertex count to 3x - new_index_array = malloc(finalVertexArrayAllocSize * 3 * sizeof(UINT32)); - memcpy(new_index_array, finalVertexIndexArray, finalIndexWritePos * sizeof(UINT32)); - free(finalVertexIndexArray); - finalVertexIndexArray = new_index_array; - } - // write the vertices of the polygon - memcpy(&finalVertexArray[finalVertexWritePos], &unsortedVertexArray[polygonArray[index].vertsIndex], - numVerts * sizeof(FOutVector)); - // write the indexes, pointing to the fan vertexes but in triangles format - firstIndex = finalVertexWritePos; - lastIndex = finalVertexWritePos + numVerts; - finalVertexWritePos += 2; - while (finalVertexWritePos < lastIndex) - { - finalVertexIndexArray[finalIndexWritePos++] = firstIndex; - finalVertexIndexArray[finalIndexWritePos++] = finalVertexWritePos - 1; - finalVertexIndexArray[finalIndexWritePos++] = finalVertexWritePos++; - } + unsigned int stateChanges = 0; // flags defined above HWR_MarkStateChanges + DrawCallInfo *currentDrawCall = &drawCalls[drawCallOrder[drawCallReadPos++]]; + DrawCallInfo *nextDrawCall = NULL; - if (polygonReadPos >= polygonArraySize) + HWR_CollectVerticesIntoBatch(currentDrawCall); + + if (drawCallReadPos >= drawCallsSize) // was that the last draw call? { stopFlag = true; } else { - // 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; - nextBrightmap = polygonArray[nextIndex].brightmap; - nextPolyFlags = polygonArray[nextIndex].polyFlags; - nextSurfaceInfo = polygonArray[nextIndex].surf; - if (nextPolyFlags & PF_NoTexture) - nextTexture = nextBrightmap = 0; - if (currentShader != nextShader && cv_glshaders.value && gl_shadersavailable) - { - changeState = true; - changeShader = true; - } - if (currentTexture != nextTexture || currentBrightmap != nextBrightmap) - { - changeState = true; - changeTexture = true; - } - if (currentPolyFlags != nextPolyFlags) - { - 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 || - currentSurfaceInfo.LightInfo.directional != nextSurfaceInfo.LightInfo.directional) - { - changeState = true; - changeSurfaceInfo = true; - } - } - else - { - if (currentSurfaceInfo.PolyColor.rgba != nextSurfaceInfo.PolyColor.rgba) - { - changeState = true; - changeSurfaceInfo = true; - } - } + nextDrawCall = &drawCalls[drawCallOrder[drawCallReadPos]]; + stateChanges = HWR_MarkStateChanges(currentDrawCall, nextDrawCall); } - if (changeState || stopFlag) + if (stateChanges || stopFlag) { - // execute draw call - GL_DrawIndexedTriangles(¤tSurfaceInfo, finalVertexArray, finalIndexWritePos, currentPolyFlags, finalVertexIndexArray); + // execute combined draw call + GL_DrawIndexedTriangles(¤tDrawCall->surf, finalVertices, + finalIndicesSize, currentDrawCall->polyFlags, finalIndices); // update stats ps_hw_numcalls++; - ps_hw_numverts += finalIndexWritePos; - // reset write positions - finalVertexWritePos = 0; - finalIndexWritePos = 0; + ps_hw_numverts += finalIndicesSize; + // reset final geometry collection arrays + finalVerticesSize = 0; + finalIndicesSize = 0; } - else continue; + else + continue; // if we're here then either its time to stop or time to change state - if (stopFlag) break; - - // change state according to change bools and next vars, update current vars and reset bools - if (changeShader) - { - GL_SetShader(nextShader); - currentShader = nextShader; - changeShader = false; - - ps_hw_numshaders++; - } - if (changeTexture) - { - // texture should be already ready for use from calls to SetTexture during batch collection - GL_SetTexture(nextTexture); - currentTexture = nextTexture; - - if (nextBrightmap) - GL_SetTexture(nextBrightmap); - currentBrightmap = nextBrightmap; - - changeTexture = false; - ps_hw_numtextures++; - } - if (changePolyFlags) - { - currentPolyFlags = nextPolyFlags; - changePolyFlags = false; - - ps_hw_numpolyflags++; - } - if (changeSurfaceInfo) - { - currentSurfaceInfo = nextSurfaceInfo; - changeSurfaceInfo = false; - - ps_hw_numcolors++; - } - // and that should be it? + if (stopFlag) + break; + else + HWR_ExecuteStateChanges(stateChanges, nextDrawCall); } // reset the arrays (set sizes to 0) - polygonArraySize = 0; - unsortedVertexArraySize = 0; + drawCallsSize = 0; + unsortedVerticesSize = 0; ps_hw_batchdrawtime = I_GetPreciseTime() - ps_hw_batchdrawtime; } diff --git a/src/hardware/hw_batching.h b/src/hardware/hw_batching.h index 58eddd25f..4906fb35f 100644 --- a/src/hardware/hw_batching.h +++ b/src/hardware/hw_batching.h @@ -20,19 +20,6 @@ extern "C" { #endif -typedef struct -{ - FSurfaceInfo surf;// surf also has its own polyflags for some reason, but it seems unused - unsigned int vertsIndex;// location of verts in unsortedVertexArray - FUINT numVerts; - FBITFIELD polyFlags; - GLMipmap_t *texture; - GLMipmap_t *brightmap; - 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; -} PolygonArrayEntry; - void HWR_StartBatching(void); void HWR_SetCurrentTexture(GLMipmap_t *texture); void HWR_ProcessPolygon(FSurfaceInfo *pSurf, FOutVector *pOutVerts, FUINT iNumPts, FBITFIELD PolyFlags, int shader, boolean horizonSpecial);