Changeset View
Changeset View
Standalone View
Standalone View
source/renderer/ModelRenderer.cpp
Show First 20 Lines • Show All 292 Lines • ▼ Show 20 Lines | bool operator()(CModel* a, CModel* b) | ||||
if (b->GetModelDef() < a->GetModelDef()) | if (b->GetModelDef() < a->GetModelDef()) | ||||
return false; | return false; | ||||
if (a->GetMaterial().GetDiffuseTexture() < b->GetMaterial().GetDiffuseTexture()) | if (a->GetMaterial().GetDiffuseTexture() < b->GetMaterial().GetDiffuseTexture()) | ||||
return true; | return true; | ||||
if (b->GetMaterial().GetDiffuseTexture() < a->GetMaterial().GetDiffuseTexture()) | if (b->GetMaterial().GetDiffuseTexture() < a->GetMaterial().GetDiffuseTexture()) | ||||
return false; | return false; | ||||
if (a->GetPlayerID() < b->GetPlayerID()) | |||||
return true; | |||||
if (b->GetPlayerID() < a->GetPlayerID()) | |||||
return false; | |||||
return a->GetMaterial().GetStaticUniforms() < b->GetMaterial().GetStaticUniforms(); | return a->GetMaterial().GetStaticUniforms() < b->GetMaterial().GetStaticUniforms(); | ||||
} | } | ||||
}; | }; | ||||
struct SMRCompareSortByDistItem | struct SMRCompareSortByDistItem | ||||
{ | { | ||||
bool operator()(const SMRSortByDistItem& a, const SMRSortByDistItem& b) | bool operator()(const SMRSortByDistItem& a, const SMRSortByDistItem& b) | ||||
{ | { | ||||
▲ Show 20 Lines • Show All 286 Lines • ▼ Show 20 Lines | if (!sortByDistItems.empty()) | ||||
// Add the tech bucket for the final run | // Add the tech bucket for the final run | ||||
SMRTechBucket techBucket = { sortByDistTechs[currentTechIdx], &sortByDistModels[start], sortByDistItems.size() - start }; | SMRTechBucket techBucket = { sortByDistTechs[currentTechIdx], &sortByDistModels[start], sortByDistItems.size() - start }; | ||||
techBuckets.push_back(techBucket); | techBuckets.push_back(techBucket); | ||||
} | } | ||||
} | } | ||||
{ | { | ||||
PROFILE3("rendering bucketed submissions"); | PROFILE3("rendering bucketed submissions"); | ||||
size_t idxTechStart = 0; | size_t idxTechStart = 0; | ||||
// This vector keeps track of texture changes during rendering. It is kept outside the | // This vector keeps track of texture changes during rendering. It is kept outside the | ||||
// loops to avoid excessive reallocations. The token allocation of 64 elements | // loops to avoid excessive reallocations. The token allocation of 64 elements | ||||
// should be plenty, though it is reallocated below (at a cost) if necessary. | // should be plenty, though it is reallocated below (at a cost) if necessary. | ||||
typedef ProxyAllocator<CTexture*, Allocators::DynamicArena> TextureListAllocator; | typedef ProxyAllocator<CTexture*, Allocators::DynamicArena> TextureListAllocator; | ||||
std::vector<CTexture*, TextureListAllocator> currentTexs((TextureListAllocator(arena))); | std::vector<CTexture*, TextureListAllocator> currentTexs((TextureListAllocator(arena))); | ||||
currentTexs.reserve(64); | currentTexs.reserve(64); | ||||
Show All 28 Lines | while (idxTechStart < techBuckets.size()) | ||||
const CShaderProgramPtr& shader = currentTech->GetShader(pass); | const CShaderProgramPtr& shader = currentTech->GetShader(pass); | ||||
int streamflags = shader->GetStreamFlags(); | int streamflags = shader->GetStreamFlags(); | ||||
modifier->BeginPass(shader); | modifier->BeginPass(shader); | ||||
m->vertexRenderer->BeginPass(streamflags); | m->vertexRenderer->BeginPass(streamflags); | ||||
// Uniforms remain valid for the duration of the shader linkage, | |||||
// So just assume someone will request them here. | |||||
{ | |||||
CShaderProgram::Binding binding = shader->GetUniformBinding(CStrIntern("sim_time")); | |||||
vladislavbelov: Put in statics if `sim_time` is used multiple times. Also might be expensive. | |||||
if (binding.Active()) | |||||
{ | |||||
double time = g_Renderer.GetTimeManager().GetGlobalTime(); | |||||
shader->Uniform(binding, time, 0.0f, 0.0f, 0.0f); | |||||
Done Inline ActionsWhy? It's not always needed. vladislavbelov: Why? It's not always needed. | |||||
Done Inline ActionsThe reasoning is that it won't change once needed, but it won't change once set once, so I can probably just activate it at some later point. wraitii: The reasoning is that it won't change once needed, but it won't change once set once, so I can… | |||||
} | |||||
} | |||||
// When the shader technique changes, textures need to be | // When the shader technique changes, textures need to be | ||||
// rebound, so ensure there are no remnants from the last pass. | // rebound, so ensure there are no remnants from the last pass. | ||||
// (the vector size is set to 0, but memory is not freed) | // (the vector size is set to 0, but memory is not freed) | ||||
currentTexs.clear(); | currentTexs.clear(); | ||||
texBindings.clear(); | texBindings.clear(); | ||||
texBindingNames.clear(); | texBindingNames.clear(); | ||||
CModelDef* currentModeldef = NULL; | CModelDef* currentModeldef = nullptr; | ||||
CShaderUniforms currentStaticUniforms; | CShaderUniforms currentStaticUniforms; | ||||
bool rq_water = false; | |||||
bool rq_skycube = false; | |||||
CSkeletonAnim* currentAnim = nullptr; | |||||
float currentAnimTime = 0.f; | |||||
CColor shadingcolor; | |||||
player_id_t playerid = INVALID_PLAYER; | |||||
std::vector<CModel*> keptModels; | |||||
Not Done Inline ActionsShould use allocator and be defined before the tech loop. vladislavbelov: Should use allocator and be defined before the tech loop. | |||||
Done Inline ActionsMoved before the loop. I'm not using an allocator because I need to pass the vector, and it's annoying having to pass the allocator alongside... With C++20 we could use std::span to fix that issue. wraitii: Moved before the loop.
I'm not using an allocator because I need to pass the vector, and it's… | |||||
keptModels.reserve(64); | |||||
// This must be called before changing state. | |||||
auto RenderKeptModels = [this, &shader, &keptModels, &modifier]() | |||||
{ | |||||
if (keptModels.empty()) | |||||
return; | |||||
#if 0 | |||||
printf("Rendered %i %s, anim %p\n", keptModels.size(), keptModels.front()->GetModelDef()->GetName().string8().c_str(), (void*)keptModels.front()->GetAnimation()); | |||||
Not Done Inline ActionsNuke. Stan: Nuke. | |||||
#endif | |||||
modifier->PrepareModel(shader, keptModels.front()); | |||||
m->vertexRenderer->RenderInstancedModel(shader, keptModels); | |||||
keptModels.clear(); | |||||
}; | |||||
for (size_t idx = idxTechStart; idx < idxTechEnd; ++idx) | for (size_t idx = idxTechStart; idx < idxTechEnd; ++idx) | ||||
{ | { | ||||
CModel** models = techBuckets[idx].models; | CModel** models = techBuckets[idx].models; | ||||
size_t numModels = techBuckets[idx].numModels; | size_t numModels = techBuckets[idx].numModels; | ||||
for (size_t i = 0; i < numModels; ++i) | for (size_t i = 0; i < numModels; ++i) | ||||
{ | { | ||||
CModel* model = models[i]; | CModel* model = models[i]; | ||||
Show All 30 Lines | #endif | ||||
texBindings[s] = shader->GetTextureBinding(samp.Name); | texBindings[s] = shader->GetTextureBinding(samp.Name); | ||||
texBindingNames[s] = samp.Name; | texBindingNames[s] = samp.Name; | ||||
} | } | ||||
// same with the actual sampler bindings | // same with the actual sampler bindings | ||||
CTexture* newTex = samp.Sampler.get(); | CTexture* newTex = samp.Sampler.get(); | ||||
if (texBindings[s].Active() && newTex != currentTexs[s]) | if (texBindings[s].Active() && newTex != currentTexs[s]) | ||||
{ | { | ||||
RenderKeptModels(); | |||||
shader->BindTexture(texBindings[s], newTex->GetHandle()); | shader->BindTexture(texBindings[s], newTex->GetHandle()); | ||||
currentTexs[s] = newTex; | currentTexs[s] = newTex; | ||||
} | } | ||||
} | } | ||||
// Bind modeldef when it changes | // Bind modeldef when it changes | ||||
CModelDef* newModeldef = model->GetModelDef().get(); | CModelDef* newModeldef = model->GetModelDef().get(); | ||||
if (newModeldef != currentModeldef) | if (newModeldef != currentModeldef) | ||||
{ | { | ||||
RenderKeptModels(); | |||||
currentModeldef = newModeldef; | currentModeldef = newModeldef; | ||||
m->vertexRenderer->PrepareModelDef(shader, streamflags, *currentModeldef); | m->vertexRenderer->PrepareModelDef(shader, streamflags, *currentModeldef); | ||||
} | } | ||||
// Bind all uniforms when any change | // Bind all uniforms when any change | ||||
CShaderUniforms newStaticUniforms = model->GetMaterial().GetStaticUniforms(); | CShaderUniforms newStaticUniforms = model->GetMaterial().GetStaticUniforms(); | ||||
if (newStaticUniforms != currentStaticUniforms) | if (newStaticUniforms != currentStaticUniforms) | ||||
{ | { | ||||
RenderKeptModels(); | |||||
currentStaticUniforms = newStaticUniforms; | currentStaticUniforms = newStaticUniforms; | ||||
currentStaticUniforms.BindUniforms(shader); | currentStaticUniforms.BindUniforms(shader); | ||||
} | } | ||||
const CShaderRenderQueries& renderQueries = model->GetMaterial().GetRenderQueries(); | const CShaderRenderQueries& renderQueries = model->GetMaterial().GetRenderQueries(); | ||||
// For render-queries, we technically don't need to render immediately | |||||
// (the state remains valid for pre-existing models) | |||||
// (though in all likelihood we'll have changed model and/or technique anyways). | |||||
for (size_t q = 0; q < renderQueries.GetSize(); ++q) | for (size_t q = 0; q < renderQueries.GetSize(); ++q) | ||||
{ | { | ||||
CShaderRenderQueries::RenderQuery rq = renderQueries.GetItem(q); | CShaderRenderQueries::RenderQuery rq = renderQueries.GetItem(q); | ||||
if (rq.first == RQUERY_TIME) | if (rq.first == RQUERY_WATER_TEX && !rq_water) | ||||
{ | |||||
CShaderProgram::Binding binding = shader->GetUniformBinding(rq.second); | |||||
if (binding.Active()) | |||||
{ | |||||
double time = g_Renderer.GetTimeManager().GetGlobalTime(); | |||||
shader->Uniform(binding, time, 0.0f, 0.0f, 0.0f); | |||||
} | |||||
} | |||||
else if (rq.first == RQUERY_WATER_TEX) | |||||
{ | { | ||||
rq_water = true; | |||||
WaterManager* WaterMgr = g_Renderer.GetWaterManager(); | WaterManager* WaterMgr = g_Renderer.GetWaterManager(); | ||||
double time = WaterMgr->m_WaterTexTimer; | double time = WaterMgr->m_WaterTexTimer; | ||||
double period = 1.6; | double period = 1.6; | ||||
int curTex = static_cast<int>(time * 60.0 / period) % 60; | int curTex = static_cast<int>(time * 60.0 / period) % 60; | ||||
if (WaterMgr->m_RenderWater && WaterMgr->WillRenderFancyWater()) | if (WaterMgr->m_RenderWater && WaterMgr->WillRenderFancyWater()) | ||||
shader->BindTexture(str_waterTex, WaterMgr->m_NormalMap[curTex]); | shader->BindTexture(str_waterTex, WaterMgr->m_NormalMap[curTex]); | ||||
else | else | ||||
shader->BindTexture(str_waterTex, g_Renderer.GetTextureManager().GetErrorTexture()); | shader->BindTexture(str_waterTex, g_Renderer.GetTextureManager().GetErrorTexture()); | ||||
} | } | ||||
else if (rq.first == RQUERY_SKY_CUBE) | else if (rq.first == RQUERY_SKY_CUBE && !rq_skycube) | ||||
{ | { | ||||
rq_skycube = true; | |||||
shader->BindTexture(str_skyCube, g_Renderer.GetSkyManager()->GetSkyCube()); | shader->BindTexture(str_skyCube, g_Renderer.GetSkyManager()->GetSkyCube()); | ||||
} | } | ||||
} | } | ||||
if (model->GetPlayerID() != playerid || model->GetShadingColor() != shadingcolor) | |||||
{ | |||||
RenderKeptModels(); | |||||
playerid = model->GetPlayerID(); | |||||
shadingcolor = model->GetShadingColor(); | |||||
modifier->PrepareModel(shader, model); | modifier->PrepareModel(shader, model); | ||||
} | |||||
if ((!model->GetAnimation() && currentAnim) || ( | |||||
model->GetAnimation() && (model->GetAnimation() != currentAnim || | |||||
model->GetAnimTime() != currentAnimTime))) | |||||
{ | |||||
RenderKeptModels(); | |||||
currentAnim = model->GetAnimation(); | |||||
currentAnimTime = model->GetAnimTime(); | |||||
} | |||||
if (m->vertexRenderer->CanInstance() && g_RenderingOptions.GetPreferGLSL()) | |||||
keptModels.push_back(model); | |||||
else | |||||
{ | |||||
CModelRData* rdata = static_cast<CModelRData*>(model->GetRenderData()); | CModelRData* rdata = static_cast<CModelRData*>(model->GetRenderData()); | ||||
ENSURE(rdata->GetKey() == m->vertexRenderer.get()); | ENSURE(rdata->GetKey() == m->vertexRenderer.get()); | ||||
m->vertexRenderer->RenderModel(shader, streamflags, model, rdata); | m->vertexRenderer->RenderModel(shader, streamflags, model, rdata); | ||||
} | } | ||||
} // numModels loop | |||||
RenderKeptModels(); | |||||
} | } | ||||
m->vertexRenderer->EndPass(streamflags); | m->vertexRenderer->EndPass(streamflags); | ||||
currentTech->EndPass(pass); | currentTech->EndPass(pass); | ||||
} | } | ||||
idxTechStart = idxTechEnd; | idxTechStart = idxTechEnd; | ||||
} | } | ||||
} | } | ||||
} | } |
Wildfire Games · Phabricator
Put in statics if sim_time is used multiple times. Also might be expensive.