diff --git a/changelog.txt b/changelog.txt index 07022e6..9309a88 100644 --- a/changelog.txt +++ b/changelog.txt @@ -25,6 +25,8 @@ chg: with r_backend GL3, depth fade with MSAA now requires GLSL 4.00 at a minimu chg: with r_backend GL3, alpha to coverage now requires GLSL 4.00 at a minimum +fix: delayed shader loads could lead to incorrect rendering and crashes (mostly with dynamic lights) + fix: the nextdemo variable wasn't used to start the playback of a new demo when: - a drop error happened during demo playback - the engine failed to open the current demo file diff --git a/code/renderer/tr_local.h b/code/renderer/tr_local.h index 7a9dbdb..23578e9 100644 --- a/code/renderer/tr_local.h +++ b/code/renderer/tr_local.h @@ -508,6 +508,7 @@ struct drawSurf_t { qhandle_t model; // MD3 model handle int index; // transparent surface's registration order float shaderSort; // transparent surface's shader sort + int shaderNum; // unsorted shader index, for when we need to do fix-ups }; extern void (*rb_surfaceTable[SF_NUM_SURFACE_TYPES])( const void* ); @@ -515,6 +516,7 @@ extern void (*rb_surfaceTable[SF_NUM_SURFACE_TYPES])( const void* ); struct litSurf_t { unsigned sort; // bit combination for fast compares + int shaderNum; // unsorted shader index, for when we need to do fix-ups const surfaceType_t* surface; // any of surface*_t litSurf_t* next; }; diff --git a/code/renderer/tr_main.cpp b/code/renderer/tr_main.cpp index 8b2a841..29f97a9 100644 --- a/code/renderer/tr_main.cpp +++ b/code/renderer/tr_main.cpp @@ -1074,6 +1074,7 @@ void R_AddDrawSurf( const surfaceType_t* surface, const shader_t* shader, int fo drawSurf->sort = R_ComposeSort( tr.currentEntityNum, shader, fogIndex ); drawSurf->surface = surface; drawSurf->model = tr.currentModel != NULL ? tr.currentModel->index : 0; + drawSurf->shaderNum = shader->index; } @@ -1087,6 +1088,7 @@ void R_AddLitSurf( const surfaceType_t* surface, const shader_t* shader, int fog litSurf_t* const litSurf = &tr.refdef.litSurfs[tr.refdef.numLitSurfs++]; litSurf->sort = R_ComposeSort( tr.currentEntityNum, shader, fogIndex ); litSurf->surface = surface; + litSurf->shaderNum = shader->index; if (!tr.light->head) tr.light->head = litSurf; diff --git a/code/renderer/tr_shader.cpp b/code/renderer/tr_shader.cpp index adfe40b..e5424c6 100644 --- a/code/renderer/tr_shader.cpp +++ b/code/renderer/tr_shader.cpp @@ -1552,6 +1552,33 @@ static void SortNewShader() for ( i = 0; i < tr.numShaders; ++i ) { tr.sortedShaders[i]->sortedIndex = i; } + + // + // If we register a new shader when surfaces are already added, + // the decoded sorted shader index for the added surfaces will not always be correct anymore. + // This can lead to incorrect rendering (wrong shader used) + // and potentially crashes too (lit surfaces referencing shaders with no diffuse stage). + // We'll therefore update all surfaces that have already been added for this entire frame, + // not just the last view. Hence why we don't use firstDrawSurf / firstLitSurf. + // The extra CPU cost for the fix-up is nothing compared to loading new textures mid-frame. + // + + int entityNum, fogNum; + const shader_t* wrongShader; + + const int numDrawSurfs = tr.refdef.numDrawSurfs; + drawSurf_t* drawSurfs = tr.refdef.drawSurfs; + for( int i = 0; i < numDrawSurfs; ++i, ++drawSurfs ) { + R_DecomposeSort( drawSurfs->sort, &entityNum, &wrongShader, &fogNum ); + drawSurfs->sort = R_ComposeSort( entityNum, tr.shaders[drawSurfs->shaderNum], fogNum ); + } + + const int numLitSurfs = tr.refdef.numLitSurfs; + litSurf_t* litSurfs = tr.refdef.litSurfs; + for ( int i = 0; i < numLitSurfs; ++i, ++litSurfs ) { + R_DecomposeSort( litSurfs->sort, &entityNum, &wrongShader, &fogNum ); + litSurfs->sort = R_ComposeSort( entityNum, tr.shaders[litSurfs->shaderNum], fogNum ); + } }