Layers are off.
FPS measuring is correct, my measuring is identical to the NSIGHT measuring.
Everything is allocated and build on startup, except for particles.
The allocation is from particles, this doesn’t happen often and decreases over time as the game starts to have enough pooled particles. But even particle disabled it doesn’t make a difference.
The rendering code is huge and not centralized.
It is GPU limited, because the rendering algorithm is identical for my OpenGL implementation.
//Bind command to the pipeline
bool cmdBind(VkPipeline *lastVkPipeline, VkDescriptorSet *lastvkdescriptor){
VkPipeline vkp;
if(vkcurrentcmdbuf){
if(set->vkdescriptor != *lastvkdescriptor){
vkCmdBindDescriptorSets(vkcurrentcmdbuf, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline->vkpipelinelayout, 0, 1, &set->vkdescriptor, 0, NULL);
*lastvkdescriptor = set->vkdescriptor;
}
//vkp = pipeline->getPipeline(getDynLights());
vkp = pipeline->getPipeline(0);
if(vkp != *lastVkPipeline){
vkCmdBindPipeline(vkcurrentcmdbuf, VK_PIPELINE_BIND_POINT_GRAPHICS, vkp);
*lastVkPipeline = vkp;
}
return true;
}
return false;
}
struct RENDERQUEUE {
BATCH_TYPE bt;
bool swSorted;
vk_render_isless fn_sort;
LIST<BATCH_ELEM*> elems;
inline void reset(){
swSorted = false;
elems.reset(false);
}
};
//this is an implementation for an UBO update (the UBO VkBuffer is persistently mapped)
//it is called by be->berenderer->updateUBO()
void __fct_shader_TEX_LMAP_NRM(BERENDERER *br){
UBO_MVP_TEX_NRM *ubo = (UBO_MVP_TEX_NRM*)br->addressUBO();
render_matrix_stack_load(br->be->mStack);
//MVP Matrix
ubo->mvp = br->be->mEye ? *render_mat_P() * *br->be->mEye : *render_mat_Identity();
ubo->mModel = br->be->mObj ? *br->be->mObj : *render_mat_Identity();
//Texture matrix
if(br->be->mesh->mat->tex->mTex)
ubo->mtex = *br->be->mesh->mat->tex->mTex;
else
ubo->mtex = *render_mat_Identity();
//x = alphaFade, y = alphaMax
ubo->alphas.set(1, __render_alphaMax, 0);
}
// sort for opaque geom (there are more but they just sort differently)
bool __gl_qsort_batch_walls(BATCH_ELEM *a, BATCH_ELEM *b){
//per distance near to far, discard fragments in shaders
if(a->distFromCam < b->distFromCam) return true;
if(a->distFromCam > b->distFromCam) return false;
//per buffer, cache
VkBuffer va = a->berenderer->getBufferIBO(), vb = a->berenderer->getBufferIBO();
if(va < vb) return true;
if(va > vb) return false;
//per index, cache
unsigned int oa = a->berenderer->getRange()->idxFrom, ob = b->berenderer->getRange()->idxFrom;
if(oa < ob) return true;
if(oa > ob) return false;
//Quicksort is an unstable sort, therefore
return a < b;
}
// this renders a group of geometry (opaque, alpha, blends, etc. ...)
void render_batches_render(BATCH_TYPE bt){
RENDERQUEUE *prof;
VkDeviceSize start = 0;
VkBuffer *pvbo, ibo, *lastpvbo = 0, lastibo = 0;
int nIndices;
BATCH_ELEM *be;
BLEND_RECORD *br;
MRENDERER *mr;
RANGE *range;
VkPipeline lastVkPipeline = 0;
VkDescriptorSet lastvkdescriptor = 0;
render_alpha(0);
prof = &renderProfiles[bt];
if(!prof && !prof->elems.n) return;
if(bt == BATCH_BLEND){
//Update UBOs
if(!prof->swSorted){
__render_lstBatchTypes.add(bt);
if(prof->fn_sort) prof->elems.sort(prof->fn_sort);
prof->swSorted = true;
//update
for(int n = 0; n < prof->elems.n; n++){
be = LIST_AT(prof->elems, n);
__render_index_counter += be->berenderer->getRange()->range();
if(be->mesh->mrenderer->flagGetAlphaTestBlend()){
render_alpha(be->c.a);
} else {
render_alpha(0);
}
//Update the shader matrices
be->berenderer->updateUBO();
}
}
} else if(bt == BATCH_OPAQUE_DYNAMIC){
//Update UBOs
if(!prof->swSorted){
__render_lstBatchTypes.add(bt);
if(prof->fn_sort) prof->elems.sort(prof->fn_sort);
prof->swSorted = true;
}
for(int n = 0; n < prof->elems.n; n++){
be = LIST_AT(prof->elems, n);
__render_index_counter += be->berenderer->getRange()->range();
}
} else {
//Update UBOs
if(!prof->swSorted){
__render_lstBatchTypes.add(bt);
if(prof->fn_sort) prof->elems.sort(prof->fn_sort);
prof->swSorted = true;
for(int n = 0; n < prof->elems.n; n++){
be = LIST_AT(prof->elems, n);
__render_index_counter += be->berenderer->getRange()->range();
if(bt == BATCH_ALPHA && be->mesh->mat)
render_alpha(be->mesh->mat->tex->D.a);
be->berenderer->updateUBO();
}
}
}
//RENDER 3D-------------------------------------------------------------------------------------
for(int i = 0; i < __render_lstBatchTypes.n; i++){
#ifdef LOG_BATCHES
if(engine.swLogBatches) util_log(LL_MSG, "** RENDERING QUEUE %s ****************************************" , BATCH_TYPE_NAME[__render_lstBatchTypes.at(i)]);
#endif
prof = &renderProfiles[__render_lstBatchTypes.at(i)];
//render
for(int n = 0; n < prof->elems.n; n++){
be = LIST_AT(prof->elems, n);
mr = be->mesh->mrenderer;
range = be->berenderer->getRange();
//Count the tris that will be rendered
nIndices = range->range();
if(be->berenderer->cmdBind(&lastVkPipeline, &lastvkdescriptor)){
pvbo = be->berenderer->getBufferVBO();
ibo = be->berenderer->getBufferIBO();
//Render
if(lastpvbo != pvbo){
vkCmdBindVertexBuffers(vkcurrentcmdbuf, 0, 1, pvbo, &start);
lastpvbo = pvbo;
}
if(lastibo != ibo){
vkCmdBindIndexBuffer(vkcurrentcmdbuf, ibo, 0, VK_INDEX_TYPE_UINT32);
lastibo = ibo;
}
vkCmdDrawIndexed(vkcurrentcmdbuf, nIndices, 1, range->idxFrom, 0, 0);
}
#ifdef LOG_BATCHES
if(engine.swLogBatches) util_log(LL_MSG, "\t\tbatch elem: %s, dist %.3f, pipeline id %d, range %u - %u, tris %d, tex: %s", SHADERS[be->berenderer->pipeline->id].name, be->distFromCam, be->berenderer->pipeline->id, range->idxFrom, range->idxTill, nIndices / 3, (char*)(be->mesh->mat->tex ? stream::get_filename(be->mesh->mat->tex->path) : "no tex"));
#endif
}//... next batch element
}
}