From 37ba588b58f5b65ba9af77c89ec9dfc578f2d44f Mon Sep 17 00:00:00 2001 From: Kearwood Gilbert Date: Tue, 27 May 2014 22:51:52 -0700 Subject: [PATCH] Refactoring of streamer code to integrate texture and vbo memory management in progress. --- KREngine/kraken/KRAmbientZone.cpp | 2 +- KREngine/kraken/KRAudioSource.cpp | 2 +- KREngine/kraken/KRBone.cpp | 2 +- KREngine/kraken/KRCamera.cpp | 17 +- KREngine/kraken/KRCollider.cpp | 2 +- KREngine/kraken/KRContext.cpp | 10 +- KREngine/kraken/KRContext.h | 2 - KREngine/kraken/KRDirectionalLight.cpp | 2 +- KREngine/kraken/KRLight.cpp | 8 +- KREngine/kraken/KRMesh.cpp | 259 ++++++++++----- KREngine/kraken/KRMesh.h | 13 +- KREngine/kraken/KRMeshCube.cpp | 3 +- KREngine/kraken/KRMeshManager.cpp | 296 ++++++++++++------ KREngine/kraken/KRMeshManager.h | 47 ++- KREngine/kraken/KRMeshQuad.cpp | 3 +- KREngine/kraken/KRMeshSphere.cpp | 2 + KREngine/kraken/KRParticleSystemNewtonian.cpp | 2 +- KREngine/kraken/KRPointLight.cpp | 2 +- KREngine/kraken/KRReverbZone.cpp | 2 +- KREngine/kraken/KRScene.cpp | 2 +- KREngine/kraken/KRSprite.cpp | 2 +- KREngine/kraken/KRTextureManager.cpp | 7 - KREngine/kraken/KRTextureManager.h | 1 - 23 files changed, 438 insertions(+), 250 deletions(-) diff --git a/KREngine/kraken/KRAmbientZone.cpp b/KREngine/kraken/KRAmbientZone.cpp index cc7675a..cf75e02 100644 --- a/KREngine/kraken/KRAmbientZone.cpp +++ b/KREngine/kraken/KRAmbientZone.cpp @@ -116,7 +116,7 @@ void KRAmbientZone::render(KRCamera *pCamera, std::vector &point std::vector sphereModels = getContext().getMeshManager()->getModel("__sphere"); if(sphereModels.size()) { for(int i=0; i < sphereModels[0]->getSubmeshCount(); i++) { - sphereModels[0]->renderSubmesh(i, renderPass, getName(), "visualize_overlay"); + sphereModels[0]->renderSubmesh(i, renderPass, getName(), "visualize_overlay", 1.0f); } } diff --git a/KREngine/kraken/KRAudioSource.cpp b/KREngine/kraken/KRAudioSource.cpp index 874ad22..832f926 100644 --- a/KREngine/kraken/KRAudioSource.cpp +++ b/KREngine/kraken/KRAudioSource.cpp @@ -229,7 +229,7 @@ void KRAudioSource::render(KRCamera *pCamera, std::vector &point std::vector sphereModels = getContext().getMeshManager()->getModel("__sphere"); if(sphereModels.size()) { for(int i=0; i < sphereModels[0]->getSubmeshCount(); i++) { - sphereModels[0]->renderSubmesh(i, renderPass, getName(), "visualize_overlay"); + sphereModels[0]->renderSubmesh(i, renderPass, getName(), "visualize_overlay", 1.0f); } } diff --git a/KREngine/kraken/KRBone.cpp b/KREngine/kraken/KRBone.cpp index 1fdbb62..3d11b0f 100644 --- a/KREngine/kraken/KRBone.cpp +++ b/KREngine/kraken/KRBone.cpp @@ -68,7 +68,7 @@ void KRBone::render(KRCamera *pCamera, std::vector &point_lights std::vector sphereModels = getContext().getMeshManager()->getModel("__sphere"); if(sphereModels.size()) { for(int i=0; i < sphereModels[0]->getSubmeshCount(); i++) { - sphereModels[0]->renderSubmesh(i, renderPass, getName(), "visualize_overlay"); + sphereModels[0]->renderSubmesh(i, renderPass, getName(), "visualize_overlay", 1.0f); } } diff --git a/KREngine/kraken/KRCamera.cpp b/KREngine/kraken/KRCamera.cpp index d7d5cc6..f3f8006 100644 --- a/KREngine/kraken/KRCamera.cpp +++ b/KREngine/kraken/KRCamera.cpp @@ -321,7 +321,7 @@ void KRCamera::renderFrame(float deltaTime, GLint renderBufferWidth, GLint rende getContext().getTextureManager()->selectTexture(0, m_pSkyBoxTexture, 0.0f, KRTexture::TEXTURE_USAGE_SKY_CUBE); // Render a full screen quad - m_pContext->getMeshManager()->bindVBO(&getContext().getMeshManager()->KRENGINE_VBO_DATA_2D_SQUARE_VERTICES); + m_pContext->getMeshManager()->bindVBO(&getContext().getMeshManager()->KRENGINE_VBO_DATA_2D_SQUARE_VERTICES, 1.0f); GLDEBUG(glDrawArrays(GL_TRIANGLE_STRIP, 0, 4)); } @@ -482,7 +482,7 @@ void KRCamera::renderFrame(float deltaTime, GLint renderBufferWidth, GLint rende KRShader *pVisShader = getContext().getShaderManager()->getShader("visualize_overlay", this, std::vector(), std::vector(), std::vector(), 0, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, KRNode::RENDER_PASS_FORWARD_TRANSPARENT); - m_pContext->getMeshManager()->bindVBO(&getContext().getMeshManager()->KRENGINE_VBO_DATA_3D_CUBE_VERTICES); + m_pContext->getMeshManager()->bindVBO(&getContext().getMeshManager()->KRENGINE_VBO_DATA_3D_CUBE_VERTICES, 1.0f); for(unordered_map::iterator itr=m_viewport.getVisibleBounds().begin(); itr != m_viewport.getVisibleBounds().end(); itr++) { KRMat4 matModel = KRMat4(); matModel.scale((*itr).first.size() * 0.5f); @@ -716,7 +716,7 @@ void KRCamera::renderPost() } // Update attribute values. - m_pContext->getMeshManager()->bindVBO(&getContext().getMeshManager()->KRENGINE_VBO_DATA_2D_SQUARE_VERTICES); + m_pContext->getMeshManager()->bindVBO(&getContext().getMeshManager()->KRENGINE_VBO_DATA_2D_SQUARE_VERTICES, 1.0f); GLDEBUG(glDrawArrays(GL_TRIANGLE_STRIP, 0, 4)); @@ -755,12 +755,6 @@ void KRCamera::renderPost() // GLDEBUG(glBindTexture(GL_TEXTURE_2D, 0)); // } - - - if(m_debug_text_vertices.getSize()) { - m_pContext->getMeshManager()->releaseVBO(m_debug_text_vertices); - } - const char *szText = settings.m_debug_text.c_str(); std::string debug_text; @@ -907,7 +901,7 @@ void KRCamera::renderPost() m_pContext->getTextureManager()->selectTexture(0, m_pContext->getTextureManager()->getTexture("font"), 0.0f, KRTexture::TEXTURE_USAGE_UI); KRDataBlock index_data; - m_pContext->getMeshManager()->bindVBO(m_debug_text_vertices, index_data, (1 << KRMesh::KRENGINE_ATTRIB_VERTEX) | (1 << KRMesh::KRENGINE_ATTRIB_TEXUVA), true); + m_pContext->getMeshManager()->bindVBO(m_debug_text_vertices, index_data, (1 << KRMesh::KRENGINE_ATTRIB_VERTEX) | (1 << KRMesh::KRENGINE_ATTRIB_TEXUVA), true, 1.0f); GLDEBUG(glDrawArrays(GL_TRIANGLES, 0, vertex_count)); @@ -997,7 +991,6 @@ std::string KRCamera::getDebugText() long texture_mem_throughput = m_pContext->getTextureManager()->getMemoryTransferedThisFrame(); int vbo_count_active = m_pContext->getMeshManager()->getActiveVBOCount(); - int vbo_count_pooled = m_pContext->getMeshManager()->getPoolVBOCount(); long vbo_mem_active = m_pContext->getMeshManager()->getMemActive(); long vbo_mem_used = m_pContext->getMeshManager()->getMemUsed(); long vbo_mem_throughput = m_pContext->getMeshManager()->getMemoryTransferedThisFrame(); @@ -1009,7 +1002,7 @@ std::string KRCamera::getDebugText() stream << "\n\n\n\t# Active\t# Used\tActive\tUsed\tThroughput\n"; stream << "Textures\t" << texture_count_active << "\t" << texture_count << "\t" << (texture_mem_active / 1024) << " KB\t" << (texture_mem_used / 1024) << " KB\t" << (texture_mem_throughput / 1024) << " KB / frame\n"; - stream << "VBO's\t" << vbo_count_active << "\t" << vbo_count_active + vbo_count_pooled << "\t" << (vbo_mem_active / 1024) <<" KB\t" << (vbo_mem_used / 1024) << " KB\t" << (vbo_mem_throughput / 1024) << " KB / frame\n"; + stream << "VBO's\t" << vbo_count_active << "\t" << vbo_count_active << "\t" << (vbo_mem_active / 1024) <<" KB\t" << (vbo_mem_used / 1024) << " KB\t" << (vbo_mem_throughput / 1024) << " KB / frame\n"; stream << "\nGPU Total\t\t\t" << (total_mem_active / 1024) << " KB\t" << (total_mem_used / 1024) << " KB\t" << (total_mem_throughput / 1024) << " KB / frame"; } break; diff --git a/KREngine/kraken/KRCollider.cpp b/KREngine/kraken/KRCollider.cpp index 3367423..47e5e21 100644 --- a/KREngine/kraken/KRCollider.cpp +++ b/KREngine/kraken/KRCollider.cpp @@ -217,7 +217,7 @@ void KRCollider::render(KRCamera *pCamera, std::vector &point_li for(int i=0; i < m_models[0]->getSubmeshCount(); i++) { - m_models[0]->renderSubmesh(i, renderPass, getName(), "visualize_overlay"); + m_models[0]->renderSubmesh(i, renderPass, getName(), "visualize_overlay", 1.0f); } // Enable alpha blending diff --git a/KREngine/kraken/KRContext.cpp b/KREngine/kraken/KRContext.cpp index db735b8..9954329 100644 --- a/KREngine/kraken/KRContext.cpp +++ b/KREngine/kraken/KRContext.cpp @@ -259,13 +259,6 @@ void KRContext::loadResource(std::string path) { } } -void KRContext::rotateBuffers(bool new_frame) { - //fprintf(stderr, "Rotating Buffers...\n"); - if(!new_frame) GLDEBUG(glFinish()); - - m_pMeshManager->rotateBuffers(new_frame); -} - void KRContext::detectExtensions() { m_bDetectedExtensions = true; @@ -285,7 +278,6 @@ void KRContext::endFrame(float deltaTime) m_pTextureManager->endFrame(deltaTime); m_pAnimationManager->endFrame(deltaTime); m_pMeshManager->endFrame(deltaTime); - rotateBuffers(true); m_current_frame++; m_absolute_time += deltaTime; } @@ -343,7 +335,7 @@ void KRContext::doStreaming() { if(m_streamingEnabled) { long memoryRemaining = KRENGINE_TARGET_TEXTURE_MEM_MAX; - long memoryRemainingThisFrame = KRENGINE_MAX_TEXTURE_MEM - m_pTextureManager->getMemUsed(); + long memoryRemainingThisFrame = KRENGINE_MAX_TEXTURE_MEM - m_pTextureManager->getMemUsed() - m_pMeshManager->getMemUsed(); m_pMeshManager->doStreaming(memoryRemaining, memoryRemainingThisFrame); m_pTextureManager->doStreaming(memoryRemaining, memoryRemainingThisFrame); } diff --git a/KREngine/kraken/KRContext.h b/KREngine/kraken/KRContext.h index 147df98..a4e7041 100644 --- a/KREngine/kraken/KRContext.h +++ b/KREngine/kraken/KRContext.h @@ -54,8 +54,6 @@ public: KRCamera *createCamera(int width, int height); - void rotateBuffers(bool new_frame); - enum { KRENGINE_GL_EXT_texture_storage, KRENGINE_NUM_EXTENSIONS diff --git a/KREngine/kraken/KRDirectionalLight.cpp b/KREngine/kraken/KRDirectionalLight.cpp index 94b86b9..06e2908 100644 --- a/KREngine/kraken/KRDirectionalLight.cpp +++ b/KREngine/kraken/KRDirectionalLight.cpp @@ -123,7 +123,7 @@ void KRDirectionalLight::render(KRCamera *pCamera, std::vector & GLDEBUG(glDisable(GL_DEPTH_TEST)); // Render a full screen quad - m_pContext->getMeshManager()->bindVBO(&getContext().getMeshManager()->KRENGINE_VBO_DATA_2D_SQUARE_VERTICES); + m_pContext->getMeshManager()->bindVBO(&getContext().getMeshManager()->KRENGINE_VBO_DATA_2D_SQUARE_VERTICES, 1.0f); GLDEBUG(glDrawArrays(GL_TRIANGLE_STRIP, 0, 4)); } } diff --git a/KREngine/kraken/KRLight.cpp b/KREngine/kraken/KRLight.cpp index 5f4b026..9aa1092 100644 --- a/KREngine/kraken/KRLight.cpp +++ b/KREngine/kraken/KRLight.cpp @@ -230,7 +230,7 @@ void KRLight::render(KRCamera *pCamera, std::vector &point_light pParticleShader->setUniform(KRShader::KRENGINE_UNIFORM_FLARE_SIZE, m_dust_particle_size); KRDataBlock particle_index_data; - m_pContext->getMeshManager()->bindVBO(m_pContext->getMeshManager()->getRandomParticles(), particle_index_data, (1 << KRMesh::KRENGINE_ATTRIB_VERTEX) | (1 << KRMesh::KRENGINE_ATTRIB_TEXUVA), true); + m_pContext->getMeshManager()->bindVBO(m_pContext->getMeshManager()->getRandomParticles(), particle_index_data, (1 << KRMesh::KRENGINE_ATTRIB_VERTEX) | (1 << KRMesh::KRENGINE_ATTRIB_TEXUVA), true, 1.0f); GLDEBUG(glDrawArrays(GL_TRIANGLES, 0, particle_count*3)); } } @@ -271,7 +271,7 @@ void KRLight::render(KRCamera *pCamera, std::vector &point_light pFogShader->setUniform(KRShader::KRENGINE_UNIFORM_LIGHT_COLOR, (m_color * pCamera->settings.volumetric_environment_intensity * m_intensity * -slice_spacing / 1000.0f)); KRDataBlock index_data; - m_pContext->getMeshManager()->bindVBO(m_pContext->getMeshManager()->getVolumetricLightingVertexes(), index_data, (1 << KRMesh::KRENGINE_ATTRIB_VERTEX), true); + m_pContext->getMeshManager()->bindVBO(m_pContext->getMeshManager()->getVolumetricLightingVertexes(), index_data, (1 << KRMesh::KRENGINE_ATTRIB_VERTEX), true, 1.0f); GLDEBUG(glDrawArrays(GL_TRIANGLES, 0, slice_count*6)); } @@ -301,7 +301,7 @@ void KRLight::render(KRCamera *pCamera, std::vector &point_light std::vector sphereModels = getContext().getMeshManager()->getModel("__sphere"); if(sphereModels.size()) { for(int i=0; i < sphereModels[0]->getSubmeshCount(); i++) { - sphereModels[0]->renderSubmesh(i, renderPass, getName(), "occlusion_test"); + sphereModels[0]->renderSubmesh(i, renderPass, getName(), "occlusion_test", 1.0f); } } @@ -341,7 +341,7 @@ void KRLight::render(KRCamera *pCamera, std::vector &point_light pShader->setUniform(KRShader::KRENGINE_UNIFORM_MATERIAL_ALPHA, 1.0f); pShader->setUniform(KRShader::KRENGINE_UNIFORM_FLARE_SIZE, m_flareSize); m_pContext->getTextureManager()->selectTexture(0, m_pFlareTexture, 0.0f, KRTexture::TEXTURE_USAGE_LIGHT_FLARE); - m_pContext->getMeshManager()->bindVBO(&getContext().getMeshManager()->KRENGINE_VBO_DATA_2D_SQUARE_VERTICES); + m_pContext->getMeshManager()->bindVBO(&getContext().getMeshManager()->KRENGINE_VBO_DATA_2D_SQUARE_VERTICES, 1.0f); GLDEBUG(glDrawArrays(GL_TRIANGLE_STRIP, 0, 4)); } } diff --git a/KREngine/kraken/KRMesh.cpp b/KREngine/kraken/KRMesh.cpp index e7c34d1..2cbea58 100644 --- a/KREngine/kraken/KRMesh.cpp +++ b/KREngine/kraken/KRMesh.cpp @@ -49,6 +49,7 @@ KRMesh::KRMesh(KRContext &context, std::string name) : KRResource(context, name) m_pData = NULL; m_pMetaData = NULL; m_pIndexBaseData = NULL; + m_constant = false; } @@ -59,6 +60,7 @@ KRMesh::KRMesh(KRContext &context, std::string name, KRDataBlock *data) : KRReso m_pData = NULL; m_pMetaData = NULL; m_pIndexBaseData = NULL; + m_constant = false; loadPack(data); } @@ -194,6 +196,28 @@ void KRMesh::preStream(float lodCoverage) for(std::set::iterator mat_itr = m_uniqueMaterials.begin(); mat_itr != m_uniqueMaterials.end(); mat_itr++) { (*mat_itr)->preStream(lodCoverage); } + + int cSubmeshes = m_submeshes.size(); + for(int iSubmesh=0; iSubmeshvbo_data_blocks.begin(); vbo_data_itr != m_submeshes[iSubmesh]->vbo_data_blocks.end(); vbo_data_itr++) { + (*vbo_data_itr)->resetPoolExpiry(lodCoverage); + } + } +} + +void KRMesh::load() +{ + // Load immediately into the GPU rather than passing through the streamer + getSubmeshes(); + getMaterials(); + + int cSubmeshes = m_submeshes.size(); + for(int iSubmesh=0; iSubmeshvbo_data_blocks.begin(); vbo_data_itr != m_submeshes[iSubmesh]->vbo_data_blocks.end(); vbo_data_itr++) { + (*vbo_data_itr)->resetPoolExpiry(1.0f); + (*vbo_data_itr)->load(); + } + } } kraken_stream_level KRMesh::getStreamLevel() @@ -205,6 +229,22 @@ kraken_stream_level KRMesh::getStreamLevel() for(std::set::iterator mat_itr = m_uniqueMaterials.begin(); mat_itr != m_uniqueMaterials.end(); mat_itr++) { stream_level = KRMIN(stream_level, (*mat_itr)->getStreamLevel()); } + bool all_vbo_data_loaded = true; + bool vbo_data_loaded = false; + int cSubmeshes = m_submeshes.size(); + for(int iSubmesh=0; iSubmeshvbo_data_blocks.begin(); vbo_data_itr != m_submeshes[iSubmesh]->vbo_data_blocks.end(); vbo_data_itr++) { + if((*vbo_data_itr)->isVBOReady()) { + vbo_data_loaded = true; + } else { + all_vbo_data_loaded = false; + } + } + } + + if(!vbo_data_loaded || !all_vbo_data_loaded) { + stream_level = kraken_stream_level::STREAM_LEVEL_OUT; + } return stream_level; } @@ -213,58 +253,61 @@ void KRMesh::render(const std::string &object_name, KRCamera *pCamera, std::vect //fprintf(stderr, "Rendering model: %s\n", m_name.c_str()); if(renderPass != KRNode::RENDER_PASS_ADDITIVE_PARTICLES && renderPass != KRNode::RENDER_PASS_PARTICLE_OCCLUSION && renderPass != KRNode::RENDER_PASS_VOLUMETRIC_EFFECTS_ADDITIVE) { - getSubmeshes(); - getMaterials(); - - int cSubmeshes = m_submeshes.size(); - if(renderPass == KRNode::RENDER_PASS_SHADOWMAP) { - for(int iSubmesh=0; iSubmeshisTransparent()) { - // Exclude transparent and semi-transparent meshes from shadow maps - renderSubmesh(iSubmesh, renderPass, object_name, pMaterial->getName()); - } - } - - } + if(getStreamLevel() == kraken_stream_level::STREAM_LEVEL_OUT) { + preStream(lod_coverage); } else { - // Apply submeshes in per-material batches to reduce number of state changes - for(std::set::iterator mat_itr = m_uniqueMaterials.begin(); mat_itr != m_uniqueMaterials.end(); mat_itr++) { + + getSubmeshes(); + getMaterials(); + + int cSubmeshes = m_submeshes.size(); + if(renderPass == KRNode::RENDER_PASS_SHADOWMAP) { for(int iSubmesh=0; iSubmeshisTransparent() && renderPass != KRNode::RENDER_PASS_FORWARD_TRANSPARENT) || (pMaterial->isTransparent() && renderPass == KRNode::RENDER_PASS_FORWARD_TRANSPARENT)) { - std::vector bone_bind_poses; - for(int i=0; i < bones.size(); i++) { - bone_bind_poses.push_back(getBoneBindPose(i)); - } - if(pMaterial->bind(pCamera, point_lights, directional_lights, spot_lights, bones, bone_bind_poses, viewport, matModel, pLightMap, renderPass, rim_color, rim_power, lod_coverage)) { - - switch(pMaterial->getAlphaMode()) { - case KRMaterial::KRMATERIAL_ALPHA_MODE_OPAQUE: // Non-transparent materials - case KRMaterial::KRMATERIAL_ALPHA_MODE_TEST: // Alpha in diffuse texture is interpreted as punch-through when < 0.5 - renderSubmesh(iSubmesh, renderPass, object_name, pMaterial->getName()); - break; - case KRMaterial::KRMATERIAL_ALPHA_MODE_BLENDONESIDE: // Blended alpha with backface culling - renderSubmesh(iSubmesh, renderPass, object_name, pMaterial->getName()); - break; - case KRMaterial::KRMATERIAL_ALPHA_MODE_BLENDTWOSIDE: // Blended alpha rendered in two passes. First pass renders backfaces; second pass renders frontfaces. - // Render back faces first - GLDEBUG(glCullFace(GL_FRONT)); - renderSubmesh(iSubmesh, renderPass, object_name, pMaterial->getName()); + if(pMaterial != NULL) { - // Render front faces second - GLDEBUG(glCullFace(GL_BACK)); - renderSubmesh(iSubmesh, renderPass, object_name, pMaterial->getName()); - break; + if(!pMaterial->isTransparent()) { + // Exclude transparent and semi-transparent meshes from shadow maps + renderSubmesh(iSubmesh, renderPass, object_name, pMaterial->getName(), lod_coverage); + } + } + + } + } else { + // Apply submeshes in per-material batches to reduce number of state changes + for(std::set::iterator mat_itr = m_uniqueMaterials.begin(); mat_itr != m_uniqueMaterials.end(); mat_itr++) { + for(int iSubmesh=0; iSubmeshisTransparent() && renderPass != KRNode::RENDER_PASS_FORWARD_TRANSPARENT) || (pMaterial->isTransparent() && renderPass == KRNode::RENDER_PASS_FORWARD_TRANSPARENT)) { + std::vector bone_bind_poses; + for(int i=0; i < bones.size(); i++) { + bone_bind_poses.push_back(getBoneBindPose(i)); + } + if(pMaterial->bind(pCamera, point_lights, directional_lights, spot_lights, bones, bone_bind_poses, viewport, matModel, pLightMap, renderPass, rim_color, rim_power, lod_coverage)) { + + switch(pMaterial->getAlphaMode()) { + case KRMaterial::KRMATERIAL_ALPHA_MODE_OPAQUE: // Non-transparent materials + case KRMaterial::KRMATERIAL_ALPHA_MODE_TEST: // Alpha in diffuse texture is interpreted as punch-through when < 0.5 + renderSubmesh(iSubmesh, renderPass, object_name, pMaterial->getName(), lod_coverage); + break; + case KRMaterial::KRMATERIAL_ALPHA_MODE_BLENDONESIDE: // Blended alpha with backface culling + renderSubmesh(iSubmesh, renderPass, object_name, pMaterial->getName(), lod_coverage); + break; + case KRMaterial::KRMATERIAL_ALPHA_MODE_BLENDTWOSIDE: // Blended alpha rendered in two passes. First pass renders backfaces; second pass renders frontfaces. + // Render back faces first + GLDEBUG(glCullFace(GL_FRONT)); + renderSubmesh(iSubmesh, renderPass, object_name, pMaterial->getName(), lod_coverage); + + // Render front faces second + GLDEBUG(glCullFace(GL_BACK)); + renderSubmesh(iSubmesh, renderPass, object_name, pMaterial->getName(), lod_coverage); + break; + } } } - - } } } @@ -303,21 +346,90 @@ void KRMesh::getSubmeshes() { //fprintf(stderr, "Submesh material: \"%s\"\n", pSubmesh->szMaterialName); m_submeshes.push_back(pSubmesh); } + createDataBlocks(m_constant ? KRMeshManager::KRVBOData::CONSTANT : KRMeshManager::KRVBOData::STREAMING); } } -void KRMesh::renderSubmesh(int iSubmesh, KRNode::RenderPass renderPass, const std::string &object_name, const std::string &material_name) { - //m_pData->lock(); +void KRMesh::createDataBlocks(KRMeshManager::KRVBOData::vbo_type t) +{ + int cSubmeshes = m_submeshes.size(); + for(int iSubmesh=0; iSubmesh < cSubmeshes; iSubmesh++) { + + Submesh *pSubmesh = m_submeshes[iSubmesh]; + int cVertexes = pSubmesh->vertex_count; + int vertex_data_offset = getVertexDataOffset(); + int index_data_offset = getIndexDataOffset(); + pack_header *pHeader = getHeader(); + int32_t vertex_attrib_flags = pHeader->vertex_attrib_flags; + int32_t vertex_count = pHeader->vertex_count; + + int vbo_index=0; + if(getModelFormat() == KRENGINE_MODEL_FORMAT_INDEXED_TRIANGLES) { + + int index_group = getSubmesh(iSubmesh)->index_group; + int index_group_offset = getSubmesh(iSubmesh)->index_group_offset; + while(cVertexes > 0) { + + int start_index_offset, start_vertex_offset, index_count, vertex_count; + getIndexedRange(index_group++, start_index_offset, start_vertex_offset, index_count, vertex_count); + + if(m_submeshes[iSubmesh]->vertex_data_blocks.size() <= vbo_index) { + KRDataBlock *vertex_data_block = m_pData->getSubBlock(vertex_data_offset + start_vertex_offset * m_vertex_size, vertex_count * m_vertex_size); + KRDataBlock *index_data_block = m_pData->getSubBlock(index_data_offset + start_index_offset * 2, index_count * 2); + KRMeshManager::KRVBOData *vbo_data_block = new KRMeshManager::KRVBOData(getContext().getMeshManager(), *vertex_data_block, *index_data_block, vertex_attrib_flags, true, t); + m_submeshes[iSubmesh]->vertex_data_blocks.push_back(vertex_data_block); + m_submeshes[iSubmesh]->index_data_blocks.push_back(index_data_block); + m_submeshes[iSubmesh]->vbo_data_blocks.push_back(vbo_data_block); + } + vbo_index++; + + int vertex_draw_count = cVertexes; + if(vertex_draw_count > index_count - index_group_offset) vertex_draw_count = index_count - index_group_offset; + + cVertexes -= vertex_draw_count; + index_group_offset = 0; + } + + } else { + int cBuffers = (vertex_count + MAX_VBO_SIZE - 1) / MAX_VBO_SIZE; + int iVertex = pSubmesh->start_vertex; + int iBuffer = iVertex / MAX_VBO_SIZE; + iVertex = iVertex % MAX_VBO_SIZE; + while(cVertexes > 0) { + GLsizei cBufferVertexes = iBuffer < cBuffers - 1 ? MAX_VBO_SIZE : vertex_count % MAX_VBO_SIZE; + int vertex_size = m_vertex_size; + + if(m_submeshes[iSubmesh]->vertex_data_blocks.size() <= vbo_index) { + KRDataBlock *index_data_block = NULL; + KRDataBlock *vertex_data_block = m_pData->getSubBlock(vertex_data_offset + iBuffer * MAX_VBO_SIZE * vertex_size, vertex_size * cBufferVertexes); + KRMeshManager::KRVBOData *vbo_data_block = new KRMeshManager::KRVBOData(getContext().getMeshManager(), *vertex_data_block, *index_data_block, vertex_attrib_flags, true, t); + m_submeshes[iSubmesh]->vertex_data_blocks.push_back(vertex_data_block); + m_submeshes[iSubmesh]->vbo_data_blocks.push_back(vbo_data_block); + } + vbo_index++; + + if(iVertex + cVertexes >= MAX_VBO_SIZE) { + assert(iVertex + (MAX_VBO_SIZE - iVertex) <= cBufferVertexes); + + cVertexes -= (MAX_VBO_SIZE - iVertex); + iVertex = 0; + iBuffer++; + } else { + assert(iVertex + cVertexes <= cBufferVertexes); + + cVertexes = 0; + } + + } + } + } +} + +void KRMesh::renderSubmesh(int iSubmesh, KRNode::RenderPass renderPass, const std::string &object_name, const std::string &material_name, float lodCoverage) { getSubmeshes(); + Submesh *pSubmesh = m_submeshes[iSubmesh]; int cVertexes = pSubmesh->vertex_count; - // fprintf(stderr, "start - object: %s material: %s vertices: %i\n", object_name.c_str(), material_name.c_str(), cVertexes); - int vertex_data_offset = getVertexDataOffset(); - int index_data_offset = getIndexDataOffset(); - pack_header *pHeader = getHeader(); - int32_t vertex_attrib_flags = pHeader->vertex_attrib_flags; - int32_t vertex_count = pHeader->vertex_count; - int vbo_index=0; if(getModelFormat() == KRENGINE_MODEL_FORMAT_INDEXED_TRIANGLES) { @@ -329,20 +441,10 @@ void KRMesh::renderSubmesh(int iSubmesh, KRNode::RenderPass renderPass, const st int start_index_offset, start_vertex_offset, index_count, vertex_count; getIndexedRange(index_group++, start_index_offset, start_vertex_offset, index_count, vertex_count); - KRMeshManager::KRVBOData *vbo_data_block = NULL; - if(m_submeshes[iSubmesh]->vertex_data_blocks.size() <= vbo_index) { - KRDataBlock *vertex_data_block = m_pData->getSubBlock(vertex_data_offset + start_vertex_offset * m_vertex_size, vertex_count * m_vertex_size); - KRDataBlock *index_data_block = m_pData->getSubBlock(index_data_offset + start_index_offset * 2, index_count * 2); - vbo_data_block = new KRMeshManager::KRVBOData(getContext().getMeshManager(), *vertex_data_block, *index_data_block, vertex_attrib_flags, true, false); - m_submeshes[iSubmesh]->vertex_data_blocks.push_back(vertex_data_block); - m_submeshes[iSubmesh]->index_data_blocks.push_back(index_data_block); - m_submeshes[iSubmesh]->vbo_data_blocks.push_back(vbo_data_block); - } else { - vbo_data_block = m_submeshes[iSubmesh]->vbo_data_blocks[vbo_index]; - } - vbo_index++; + KRMeshManager::KRVBOData *vbo_data_block = m_submeshes[iSubmesh]->vbo_data_blocks[vbo_index++]; + assert(vbo_data_block->isVBOReady()); - m_pContext->getMeshManager()->bindVBO(vbo_data_block); + m_pContext->getMeshManager()->bindVBO(vbo_data_block, lodCoverage); int vertex_draw_count = cVertexes; @@ -355,28 +457,16 @@ void KRMesh::renderSubmesh(int iSubmesh, KRNode::RenderPass renderPass, const st } } else { - int cBuffers = (vertex_count + MAX_VBO_SIZE - 1) / MAX_VBO_SIZE; + int cBuffers = (cVertexes + MAX_VBO_SIZE - 1) / MAX_VBO_SIZE; int iVertex = pSubmesh->start_vertex; int iBuffer = iVertex / MAX_VBO_SIZE; iVertex = iVertex % MAX_VBO_SIZE; while(cVertexes > 0) { - GLsizei cBufferVertexes = iBuffer < cBuffers - 1 ? MAX_VBO_SIZE : vertex_count % MAX_VBO_SIZE; - int vertex_size = m_vertex_size; + GLsizei cBufferVertexes = iBuffer < cBuffers - 1 ? MAX_VBO_SIZE : cVertexes % MAX_VBO_SIZE; - - KRMeshManager::KRVBOData *vbo_data_block = NULL; - if(m_submeshes[iSubmesh]->vertex_data_blocks.size() <= vbo_index) { - KRDataBlock *index_data_block = NULL; - KRDataBlock *vertex_data_block = m_pData->getSubBlock(vertex_data_offset + iBuffer * MAX_VBO_SIZE * vertex_size, vertex_size * cBufferVertexes); - vbo_data_block = new KRMeshManager::KRVBOData(getContext().getMeshManager(), *vertex_data_block, *index_data_block, vertex_attrib_flags, true, false); - m_submeshes[iSubmesh]->vertex_data_blocks.push_back(vertex_data_block); - m_submeshes[iSubmesh]->vbo_data_blocks.push_back(vbo_data_block); - } else { - vbo_data_block = m_submeshes[iSubmesh]->vbo_data_blocks[vbo_index]; - } - vbo_index++; - - m_pContext->getMeshManager()->bindVBO(vbo_data_block); + KRMeshManager::KRVBOData *vbo_data_block = m_submeshes[iSubmesh]->vbo_data_blocks[vbo_index++]; + assert(vbo_data_block->isVBOReady()); + m_pContext->getMeshManager()->bindVBO(vbo_data_block, lodCoverage); if(iVertex + cVertexes >= MAX_VBO_SIZE) { @@ -422,7 +512,6 @@ void KRMesh::renderSubmesh(int iSubmesh, KRNode::RenderPass renderPass, const st } } - //m_pData->unlock(); } void KRMesh::LoadData(const KRMesh::mesh_info &mi, bool calculate_normals, bool calculate_tangents) { diff --git a/KREngine/kraken/KRMesh.h b/KREngine/kraken/KRMesh.h index d62b215..eb4b58a 100644 --- a/KREngine/kraken/KRMesh.h +++ b/KREngine/kraken/KRMesh.h @@ -129,15 +129,13 @@ public: void optimize(); void optimizeIndexes(); - void renderSubmesh(int iSubmesh, KRNode::RenderPass renderPass, const std::string &object_name, const std::string &material_name); + void renderSubmesh(int iSubmesh, KRNode::RenderPass renderPass, const std::string &object_name, const std::string &material_name, float lodCoverage); GLfloat getMaxDimension(); KRVector3 getMinPoint() const; KRVector3 getMaxPoint() const; - - class Submesh { public: Submesh() {}; @@ -220,6 +218,12 @@ public: bool sphereCast(const KRMat4 &model_to_world, const KRVector3 &v0, const KRVector3 &v1, float radius, KRHitInfo &hitinfo) const; static int GetLODCoverage(const std::string &name); + + void load(); // Load immediately into the GPU rather than passing through the streamer + +protected: + bool m_constant; // TRUE if this should be always loaded and should not be passed through the streamer + private: KRDataBlock *m_pData; KRDataBlock *m_pMetaData; @@ -280,6 +284,9 @@ private: void releaseData(); + void createDataBlocks(KRMeshManager::KRVBOData::vbo_type t); + + }; diff --git a/KREngine/kraken/KRMeshCube.cpp b/KREngine/kraken/KRMeshCube.cpp index 1d48c44..e4f433d 100644 --- a/KREngine/kraken/KRMeshCube.cpp +++ b/KREngine/kraken/KRMeshCube.cpp @@ -34,8 +34,9 @@ KRMeshCube::KRMeshCube(KRContext &context) : KRMesh(context, "__cube") { - KRMesh::mesh_info mi; + m_constant = true; + KRMesh::mesh_info mi; mi.vertices.push_back(KRVector3(1.0, 1.0, 1.0)); mi.vertices.push_back(KRVector3(-1.0, 1.0, 1.0)); diff --git a/KREngine/kraken/KRMeshManager.cpp b/KREngine/kraken/KRMeshManager.cpp index 5b07b02..9a43c3c 100644 --- a/KREngine/kraken/KRMeshManager.cpp +++ b/KREngine/kraken/KRMeshManager.cpp @@ -42,6 +42,8 @@ KRMeshManager::KRMeshManager(KRContext &context) : KRContextObject(context) { m_currentVBO = NULL; m_vboMemUsed = 0; m_memoryTransferredThisFrame = 0; + m_first_frame = true; + m_streamerComplete = true; addModel(new KRMeshCube(context)); // FINDME - HACK! This needs to be fixed, as it currently segfaults addModel(new KRMeshQuad(context)); // FINDME - HACK! This needs to be fixed, as it currently segfaults @@ -76,7 +78,7 @@ KRMeshManager::KRMeshManager(KRContext &context) : KRContextObject(context) { memcpy(KRENGINE_VBO_3D_CUBE_VERTICES.getStart(), _KRENGINE_VBO_3D_CUBE_VERTEX_DATA, sizeof(GLfloat) * 3 * 14); KRENGINE_VBO_3D_CUBE_VERTICES.unlock(); - KRENGINE_VBO_DATA_3D_CUBE_VERTICES.init(this, KRENGINE_VBO_3D_CUBE_VERTICES, KRENGINE_VBO_3D_CUBE_INDEXES, KRENGINE_VBO_3D_CUBE_ATTRIBS, false, false); + KRENGINE_VBO_DATA_3D_CUBE_VERTICES.init(this, KRENGINE_VBO_3D_CUBE_VERTICES, KRENGINE_VBO_3D_CUBE_INDEXES, KRENGINE_VBO_3D_CUBE_ATTRIBS, false, KRVBOData::CONSTANT); @@ -92,7 +94,7 @@ KRMeshManager::KRMeshManager(KRContext &context) : KRContextObject(context) { memcpy(KRENGINE_VBO_2D_SQUARE_VERTICES.getStart(), _KRENGINE_VBO_2D_SQUARE_VERTEX_DATA, sizeof(GLfloat) * 5 * 4); KRENGINE_VBO_2D_SQUARE_VERTICES.unlock(); - KRENGINE_VBO_DATA_2D_SQUARE_VERTICES.init(this, KRENGINE_VBO_2D_SQUARE_VERTICES, KRENGINE_VBO_2D_SQUARE_INDEXES, KRENGINE_VBO_2D_SQUARE_ATTRIBS, false, false); + KRENGINE_VBO_DATA_2D_SQUARE_VERTICES.init(this, KRENGINE_VBO_2D_SQUARE_VERTICES, KRENGINE_VBO_2D_SQUARE_INDEXES, KRENGINE_VBO_2D_SQUARE_ATTRIBS, false, KRVBOData::CONSTANT); } @@ -151,6 +153,7 @@ void KRMeshManager::unbindVBO() { } } +/* void KRMeshManager::releaseVBO(KRDataBlock &data) { if(m_currentVBO) { @@ -159,32 +162,34 @@ void KRMeshManager::releaseVBO(KRDataBlock &data) } } - KRVBOData *vbo_to_release = NULL; if(m_vbosActive.find(&data) != m_vbosActive.end()) { KRContext::Log(KRContext::LOG_LEVEL_WARNING, "glFinish called due to releasing a VBO that is active in the current frame."); GLDEBUG(glFinish()); // The VBO is active - vbo_to_release = m_vbosActive[&data]; + KRVBOData *vbo_to_release = m_vbosActive[&data]; m_vbosActive.erase(&data); - } else { - // The VBO is inactive - vbo_to_release = m_vbosPool[&data]; - m_vbosPool.erase(&data); - } - - if(vbo_to_release) { + m_vboMemUsed -= vbo_to_release->getSize(); - - vbo_to_release->unload(); - if(vbo_to_release->isTemporary()) { - delete vbo_to_release; + switch(vbo_to_release->getType()) { + case KRVBOData::STREAMING: + vbo_to_release->unload(); + break; + case KRVBOData::TEMPORARY: + delete vbo_to_release; + break; + case KRVBOData::CONSTANT: + // CONSTANT VBO's are not unloaded + break; } } } +*/ -void KRMeshManager::bindVBO(KRVBOData *vbo_data) +void KRMeshManager::bindVBO(KRVBOData *vbo_data, float lodCoverage) { + vbo_data->resetPoolExpiry(lodCoverage); + bool vbo_changed = false; if(m_currentVBO == NULL) { vbo_changed = true; @@ -198,57 +203,148 @@ void KRMeshManager::bindVBO(KRVBOData *vbo_data) if(m_vbosActive.find(vbo_data->m_data) != m_vbosActive.end()) { m_currentVBO = m_vbosActive[vbo_data->m_data]; - - m_currentVBO->bind(); - - } else if(m_vbosPool.find(vbo_data->m_data) != m_vbosPool.end()) { - m_currentVBO = m_vbosPool[vbo_data->m_data]; - m_vbosPool.erase(vbo_data->m_data); - m_vbosActive[vbo_data->m_data] = m_currentVBO; - - m_currentVBO->bind(); - - } else { - - - while(m_vbosPool.size() + m_vbosActive.size() + 1 >= KRContext::KRENGINE_MAX_VBO_HANDLES || m_vboMemUsed + vbo_data->getSize() >= KRContext::KRENGINE_MAX_VBO_MEM) { - if(m_vbosPool.empty()) { - KRContext::Log(KRContext::LOG_LEVEL_WARNING, "flushBuffers due to VBO exhaustion..."); - m_pContext->rotateBuffers(false); - } - unordered_map::iterator first_itr = m_vbosPool.begin(); - KRVBOData *firstVBO = first_itr->second; - m_vbosPool.erase(first_itr); - - m_vboMemUsed -= firstVBO->getSize(); - firstVBO->unload(); - if(firstVBO->isTemporary()) { - delete firstVBO; - } - // fprintf(stderr, "VBO Swapping...\n"); - } - used_vbo_data = true; m_currentVBO = vbo_data; - m_currentVBO->load(); - m_memoryTransferredThisFrame += m_currentVBO->getSize(); - m_vboMemUsed += m_currentVBO->getSize(); - m_vbosActive[vbo_data->m_data] = m_currentVBO; } + + m_currentVBO->bind(); } - if(!used_vbo_data && vbo_data->isTemporary()) { + if(!used_vbo_data && vbo_data->getType() == KRVBOData::TEMPORARY) { delete vbo_data; } } -void KRMeshManager::bindVBO(KRDataBlock &data, KRDataBlock &index_data, int vertex_attrib_flags, bool static_vbo) +void KRMeshManager::startFrame(float deltaTime) { - KRVBOData *vbo_data = new KRVBOData(this, data, index_data, vertex_attrib_flags, static_vbo, true); - bindVBO(vbo_data); + m_memoryTransferredThisFrame = 0; + if(m_draw_call_log_used) { + // Only log draw calls on the next frame if the draw call log was used on last frame + m_draw_call_log_used = false; + m_draw_call_logging_enabled = true; + } + m_draw_calls.clear(); + + if(m_first_frame) { + m_first_frame = false; + firstFrame(); + } + + // TODO - Implement proper double-buffering to reduce copy operations + m_streamerFenceMutex.lock(); + + if(m_streamerComplete) { + assert(m_activeVBOs_streamer_copy.size() == 0); // The streamer should have emptied this if it really did complete + + const long KRENGINE_VBO_EXPIRY_FRAMES = 30; + + std::set expiredVBOs; + for(auto itr=m_vbosActive.begin(); itr != m_vbosActive.end(); itr++) { + KRVBOData *activeVBO = (*itr).second; + activeVBO->_swapHandles(); + if(activeVBO->getLastFrameUsed() + KRENGINE_VBO_EXPIRY_FRAMES < getContext().getCurrentFrame()) { + // Expire VBO's that haven't been used in a long time + + switch(activeVBO->getType()) { + case KRVBOData::STREAMING: + // TODO - Move to KRVBOData::unload() + if(activeVBO->isVBOLoaded()) { + m_vboMemUsed -= activeVBO->getSize(); + } + activeVBO->unload(); + break; + case KRVBOData::TEMPORARY: + // TODO - Move to KRVBOData::unload() + if(activeVBO->isVBOLoaded()) { + m_vboMemUsed -= activeVBO->getSize(); + } + delete activeVBO; + break; + case KRVBOData::CONSTANT: + // CONSTANT VBO's are not unloaded + break; + } + + expiredVBOs.insert(activeVBO); + } else { + if(activeVBO->getType() == KRVBOData::STREAMING) { + float priority = activeVBO->getStreamPriority(); + m_activeVBOs_streamer_copy.push_back(std::pair(priority, activeVBO)); + } + } + } + for(std::set::iterator itr=expiredVBOs.begin(); itr != expiredVBOs.end(); itr++) { + m_vbosActive.erase((*itr)->m_data); + } + + if(m_activeVBOs_streamer_copy.size() > 0) { + m_streamerComplete = false; + } + } + m_streamerFenceMutex.unlock(); + +} + +void KRMeshManager::endFrame(float deltaTime) +{ + +} + +void KRMeshManager::firstFrame() +{ + KRENGINE_VBO_DATA_3D_CUBE_VERTICES.load(); + KRENGINE_VBO_DATA_2D_SQUARE_VERTICES.load(); + + getModel("__sphere")[0]->load(); + getModel("__cube")[0]->load(); + getModel("__quad")[0]->load(); +} + +void KRMeshManager::doStreaming(long &memoryRemaining, long &memoryRemainingThisFrame) +{ + + // TODO - Implement proper double-buffering to reduce copy operations + m_streamerFenceMutex.lock(); + m_activeVBOs_streamer = std::move(m_activeVBOs_streamer_copy); + m_streamerFenceMutex.unlock(); + + if(m_activeVBOs_streamer.size() > 0) { + balanceVBOMemory(memoryRemaining, memoryRemainingThisFrame); + + m_streamerFenceMutex.lock(); + m_streamerComplete = true; + m_streamerFenceMutex.unlock(); + } +} + +void KRMeshManager::balanceVBOMemory(long &memoryRemaining, long &memoryRemainingThisFrame) +{ + std::sort(m_activeVBOs_streamer.begin(), m_activeVBOs_streamer.end(), std::greater>()); + + + for(auto vbo_itr = m_activeVBOs_streamer.begin(); memoryRemainingThisFrame > 0 && vbo_itr != m_activeVBOs_streamer.end(); vbo_itr++) { + KRVBOData *vbo_data = (*vbo_itr).second; + if(!vbo_data->isVBOLoaded()) { + long vbo_size = vbo_data->getSize(); + if(memoryRemainingThisFrame > vbo_size) { + vbo_data->load(); + memoryRemainingThisFrame -= vbo_size; + memoryRemaining -= vbo_size; + } + } + } + + glFinish(); +} + +void KRMeshManager::bindVBO(KRDataBlock &data, KRDataBlock &index_data, int vertex_attrib_flags, bool static_vbo, float lodCoverage) +{ + KRVBOData *vbo_data = new KRVBOData(this, data, index_data, vertex_attrib_flags, static_vbo, KRVBOData::TEMPORARY); + vbo_data->load(); + bindVBO(vbo_data, lodCoverage); } void KRMeshManager::configureAttribs(__int32_t attributes) @@ -334,17 +430,6 @@ long KRMeshManager::getMemActive() return mem_active; } -void KRMeshManager::rotateBuffers(bool new_frame) -{ - m_vbosPool.insert(m_vbosActive.begin(), m_vbosActive.end()); - m_vbosActive.clear(); - if(m_currentVBO != NULL) { - // Ensure that the currently active VBO does not get flushed to free memory - m_vbosPool.erase(m_currentVBO->m_data); - m_vbosActive[m_currentVBO->m_data] = m_currentVBO; - } -} - KRDataBlock &KRMeshManager::getVolumetricLightingVertexes() { if(m_volumetricLightingVertexData.getSize() == 0) { @@ -429,23 +514,6 @@ KRDataBlock &KRMeshManager::getRandomParticles() return m_randomParticleVertexData; } -void KRMeshManager::startFrame(float deltaTime) -{ - m_memoryTransferredThisFrame = 0; - if(m_draw_call_log_used) { - // Only log draw calls on the next frame if the draw call log was used on last frame - m_draw_call_log_used = false; - m_draw_call_logging_enabled = true; - } - m_draw_calls.clear(); - -} - -void KRMeshManager::endFrame(float deltaTime) -{ - -} - long KRMeshManager::getMemoryTransferedThisFrame() { return m_memoryTransferredThisFrame; @@ -457,11 +525,6 @@ int KRMeshManager::getActiveVBOCount() return m_vbosActive.size(); } -int KRMeshManager::getPoolVBOCount() -{ - return m_vbosPool.size(); -} - void KRMeshManager::log_draw_call(KRNode::RenderPass pass, const std::string &object_name, const std::string &material_name, int vertex_count) { if(m_draw_call_logging_enabled) { @@ -480,16 +543,12 @@ std::vector KRMeshManager::getDrawCalls() return m_draw_calls; } -void KRMeshManager::doStreaming(long &memoryRemaining, long &memoryRemainingThisFrame) -{ - -} - KRMeshManager::KRVBOData::KRVBOData() { + m_is_vbo_loaded = false; + m_is_vbo_ready = false; m_manager = NULL; - m_temp_vbo = false; - m_static_vbo = false; + m_type = STREAMING; m_data = NULL; m_index_data = NULL; m_vertex_attrib_flags = 0; @@ -502,15 +561,15 @@ KRMeshManager::KRVBOData::KRVBOData() m_last_frame_max_lod_coverage = 0.0f; } -KRMeshManager::KRVBOData::KRVBOData(KRMeshManager *manager, KRDataBlock &data, KRDataBlock &index_data, int vertex_attrib_flags, bool static_vbo, bool temp_vbo) +KRMeshManager::KRVBOData::KRVBOData(KRMeshManager *manager, KRDataBlock &data, KRDataBlock &index_data, int vertex_attrib_flags, bool static_vbo, vbo_type t) { - init(manager, data,index_data,vertex_attrib_flags, static_vbo, temp_vbo); + init(manager, data,index_data,vertex_attrib_flags, static_vbo, t); } -void KRMeshManager::KRVBOData::init(KRMeshManager *manager, KRDataBlock &data, KRDataBlock &index_data, int vertex_attrib_flags, bool static_vbo, bool temp_vbo) +void KRMeshManager::KRVBOData::init(KRMeshManager *manager, KRDataBlock &data, KRDataBlock &index_data, int vertex_attrib_flags, bool static_vbo, vbo_type t) { m_manager = manager; - m_temp_vbo = temp_vbo; + m_type = t; m_static_vbo = static_vbo; m_data = &data; m_index_data = &index_data; @@ -528,14 +587,12 @@ void KRMeshManager::KRVBOData::init(KRMeshManager *manager, KRDataBlock &data, K KRMeshManager::KRVBOData::~KRVBOData() { - + unload(); } - - void KRMeshManager::KRVBOData::load() { - if(isLoaded()) { + if(isVBOLoaded()) { return; } m_vao_handle = -1; @@ -586,6 +643,11 @@ void KRMeshManager::KRVBOData::load() m_index_data->unlock(); #endif } + + m_is_vbo_loaded = true; + if(m_type == CONSTANT) { + m_is_vbo_ready = true; + } } void KRMeshManager::KRVBOData::unload() @@ -605,6 +667,9 @@ void KRMeshManager::KRVBOData::unload() GLDEBUG(glDeleteBuffers(1, &m_vbo_handle_indexes)); m_vbo_handle_indexes = -1; } + + m_is_vbo_loaded = false; + m_is_vbo_ready = false; } void KRMeshManager::KRVBOData::bind() @@ -628,6 +693,31 @@ void KRMeshManager::KRVBOData::resetPoolExpiry(float lodCoverage) if(current_frame != m_last_frame_used) { m_last_frame_used = current_frame; m_last_frame_max_lod_coverage = 0.0f; + + m_manager->primeVBO(this); } m_last_frame_max_lod_coverage = KRMAX(lodCoverage, m_last_frame_max_lod_coverage); -} \ No newline at end of file +} + + +float KRMeshManager::KRVBOData::getStreamPriority() +{ + long current_frame = m_manager->getContext().getCurrentFrame(); + if(current_frame > m_last_frame_used + 5) { + return 1.0f - KRCLAMP((float)(current_frame - m_last_frame_used) / 60.0f, 0.0f, 1.0f); + } else { + return 10000.0f + m_last_frame_max_lod_coverage * 10.0f; + } +} + +void KRMeshManager::KRVBOData::_swapHandles() +{ + m_is_vbo_ready = m_is_vbo_loaded; +} + +void KRMeshManager::primeVBO(KRVBOData *vbo_data) +{ + if(m_vbosActive.find(vbo_data->m_data) == m_vbosActive.end()) { + m_vbosActive[vbo_data->m_data] = vbo_data; + } +} diff --git a/KREngine/kraken/KRMeshManager.h b/KREngine/kraken/KRMeshManager.h index 693136b..676914c 100644 --- a/KREngine/kraken/KRMeshManager.h +++ b/KREngine/kraken/KRMeshManager.h @@ -48,9 +48,9 @@ public: KRMeshManager(KRContext &context); virtual ~KRMeshManager(); - void rotateBuffers(bool new_frame); void startFrame(float deltaTime); void endFrame(float deltaTime); + void firstFrame(); KRMesh *loadModel(const char *szName, KRDataBlock *pData); std::vector getModel(const char *szName); @@ -63,16 +63,23 @@ public: public: + typedef enum { + STREAMING, + CONSTANT, + TEMPORARY + } vbo_type; + KRVBOData(); - KRVBOData(KRMeshManager *manager, KRDataBlock &data, KRDataBlock &index_data, int vertex_attrib_flags, bool static_vbo, bool temp_vbo); - void init(KRMeshManager *manager, KRDataBlock &data, KRDataBlock &index_data, int vertex_attrib_flags, bool static_vbo, bool temp_vbo); + KRVBOData(KRMeshManager *manager, KRDataBlock &data, KRDataBlock &index_data, int vertex_attrib_flags, bool static_vbo, vbo_type t); + void init(KRMeshManager *manager, KRDataBlock &data, KRDataBlock &index_data, int vertex_attrib_flags, bool static_vbo, vbo_type t); ~KRVBOData(); KRDataBlock *m_data; KRDataBlock *m_index_data; - bool isLoaded() { return m_vbo_handle != -1; } + bool isVBOLoaded() { return m_is_vbo_loaded; } + bool isVBOReady() { return m_is_vbo_ready; } void load(); void unload(); void bind(); @@ -81,10 +88,16 @@ public: KRVBOData(const KRVBOData& o) = delete; KRVBOData(KRVBOData& o) = delete; - bool isTemporary() { return m_temp_vbo; } bool getSize() { return m_size; } void resetPoolExpiry(float lodCoverage); + long getLastFrameUsed() { return m_last_frame_used; } + + vbo_type getType() { return m_type; } + + float getStreamPriority(); + + void _swapHandles(); private: KRMeshManager *m_manager; @@ -92,17 +105,18 @@ public: GLuint m_vbo_handle; GLuint m_vbo_handle_indexes; GLuint m_vao_handle; - bool m_static_vbo; - bool m_temp_vbo; GLsizeiptr m_size; long m_last_frame_used; float m_last_frame_max_lod_coverage; + vbo_type m_type; + bool m_static_vbo; + bool m_is_vbo_loaded; + bool m_is_vbo_ready; }; - void bindVBO(KRVBOData *vbo_data); - void bindVBO(KRDataBlock &data, KRDataBlock &index_data, int vertex_attrib_flags, bool static_vbo); - void releaseVBO(KRDataBlock &data); + void bindVBO(KRVBOData *vbo_data, float lodCoverage); + void bindVBO(KRDataBlock &data, KRDataBlock &index_data, int vertex_attrib_flags, bool static_vbo, float lodCoverage); void unbindVBO(); long getMemUsed(); long getMemActive(); @@ -137,7 +151,6 @@ public: long getMemoryTransferedThisFrame(); int getActiveVBOCount(); - int getPoolVBOCount(); struct draw_call_info { KRNode::RenderPass pass; @@ -168,7 +181,8 @@ private: KRVBOData *m_currentVBO; unordered_map m_vbosActive; - unordered_map m_vbosPool; + std::vector > m_activeVBOs_streamer; + std::vector > m_activeVBOs_streamer_copy; KRDataBlock m_randomParticleVertexData; KRDataBlock m_volumetricLightingVertexData; @@ -178,6 +192,15 @@ private: std::vector m_draw_calls; bool m_draw_call_logging_enabled; bool m_draw_call_log_used; + + bool m_first_frame; + + std::mutex m_streamerFenceMutex; + bool m_streamerComplete; + + void balanceVBOMemory(long &memoryRemaining, long &memoryRemainingThisFrame); + + void primeVBO(KRVBOData *vbo_data); }; diff --git a/KREngine/kraken/KRMeshQuad.cpp b/KREngine/kraken/KRMeshQuad.cpp index 875f8a7..930db33 100644 --- a/KREngine/kraken/KRMeshQuad.cpp +++ b/KREngine/kraken/KRMeshQuad.cpp @@ -34,6 +34,8 @@ KRMeshQuad::KRMeshQuad(KRContext &context) : KRMesh(context, "__quad") { + m_constant = true; + KRMesh::mesh_info mi; mi.vertices.push_back(KRVector3(-1.0f, -1.0f, 0.0f)); @@ -52,7 +54,6 @@ KRMeshQuad::KRMeshQuad(KRContext &context) : KRMesh(context, "__quad") mi.material_names.push_back(""); mi.format = KRENGINE_MODEL_FORMAT_STRIP; - LoadData(mi, true, true); } diff --git a/KREngine/kraken/KRMeshSphere.cpp b/KREngine/kraken/KRMeshSphere.cpp index cb581a7..9278154 100644 --- a/KREngine/kraken/KRMeshSphere.cpp +++ b/KREngine/kraken/KRMeshSphere.cpp @@ -34,6 +34,8 @@ KRMeshSphere::KRMeshSphere(KRContext &context) : KRMesh(context, "__sphere") { + m_constant = true; + KRMesh::mesh_info mi; // Create a triangular facet approximation to a sphere diff --git a/KREngine/kraken/KRParticleSystemNewtonian.cpp b/KREngine/kraken/KRParticleSystemNewtonian.cpp index 4df6832..3b5e4d4 100644 --- a/KREngine/kraken/KRParticleSystemNewtonian.cpp +++ b/KREngine/kraken/KRParticleSystemNewtonian.cpp @@ -80,7 +80,7 @@ void KRParticleSystemNewtonian::render(KRCamera *pCamera, std::vectorsetUniform(KRShader::KRENGINE_UNIFORM_FLARE_SIZE, 1.0f); KRDataBlock index_data; - m_pContext->getMeshManager()->bindVBO(m_pContext->getMeshManager()->getRandomParticles(), index_data, (1 << KRMesh::KRENGINE_ATTRIB_VERTEX) | (1 << KRMesh::KRENGINE_ATTRIB_TEXUVA), false); + m_pContext->getMeshManager()->bindVBO(m_pContext->getMeshManager()->getRandomParticles(), index_data, (1 << KRMesh::KRENGINE_ATTRIB_VERTEX) | (1 << KRMesh::KRENGINE_ATTRIB_TEXUVA), false, 1.0f); GLDEBUG(glDrawArrays(GL_TRIANGLES, 0, particle_count*3)); } } diff --git a/KREngine/kraken/KRPointLight.cpp b/KREngine/kraken/KRPointLight.cpp index 21883a8..46a58a1 100644 --- a/KREngine/kraken/KRPointLight.cpp +++ b/KREngine/kraken/KRPointLight.cpp @@ -97,7 +97,7 @@ void KRPointLight::render(KRCamera *pCamera, std::vector &point_ GLDEBUG(glDisable(GL_DEPTH_TEST)); // Render a full screen quad - m_pContext->getMeshManager()->bindVBO(&m_pContext->getMeshManager()->KRENGINE_VBO_DATA_2D_SQUARE_VERTICES); + m_pContext->getMeshManager()->bindVBO(&m_pContext->getMeshManager()->KRENGINE_VBO_DATA_2D_SQUARE_VERTICES, 1.0f); GLDEBUG(glDrawArrays(GL_TRIANGLE_STRIP, 0, 4)); } else { #if GL_OES_vertex_array_object diff --git a/KREngine/kraken/KRReverbZone.cpp b/KREngine/kraken/KRReverbZone.cpp index 2a64ee6..57fbad7 100644 --- a/KREngine/kraken/KRReverbZone.cpp +++ b/KREngine/kraken/KRReverbZone.cpp @@ -115,7 +115,7 @@ void KRReverbZone::render(KRCamera *pCamera, std::vector &point_ std::vector sphereModels = getContext().getMeshManager()->getModel("__sphere"); if(sphereModels.size()) { for(int i=0; i < sphereModels[0]->getSubmeshCount(); i++) { - sphereModels[0]->renderSubmesh(i, renderPass, getName(), "visualize_overlay"); + sphereModels[0]->renderSubmesh(i, renderPass, getName(), "visualize_overlay", 1.0f); } } diff --git a/KREngine/kraken/KRScene.cpp b/KREngine/kraken/KRScene.cpp index 5c7a199..76e6f5b 100644 --- a/KREngine/kraken/KRScene.cpp +++ b/KREngine/kraken/KRScene.cpp @@ -281,7 +281,7 @@ void KRScene::render(KROctreeNode *pOctreeNode, unordered_map &visi KRMat4 mvpmatrix = matModel * viewport.getViewProjectionMatrix(); - getContext().getMeshManager()->bindVBO(&getContext().getMeshManager()->KRENGINE_VBO_DATA_3D_CUBE_VERTICES); + getContext().getMeshManager()->bindVBO(&getContext().getMeshManager()->KRENGINE_VBO_DATA_3D_CUBE_VERTICES, 1.0f); // Enable additive blending if(renderPass != KRNode::RENDER_PASS_FORWARD_TRANSPARENT && renderPass != KRNode::RENDER_PASS_ADDITIVE_PARTICLES && renderPass != KRNode::RENDER_PASS_VOLUMETRIC_EFFECTS_ADDITIVE) { diff --git a/KREngine/kraken/KRSprite.cpp b/KREngine/kraken/KRSprite.cpp index b35d028..83c3062 100644 --- a/KREngine/kraken/KRSprite.cpp +++ b/KREngine/kraken/KRSprite.cpp @@ -121,7 +121,7 @@ void KRSprite::render(KRCamera *pCamera, std::vector &point_ligh if(getContext().getShaderManager()->selectShader(*pCamera, pShader, viewport, getModelMatrix(), point_lights, directional_lights, spot_lights, 0, renderPass, rim_color, 0.0f)) { pShader->setUniform(KRShader::KRENGINE_UNIFORM_MATERIAL_ALPHA, m_spriteAlpha); m_pContext->getTextureManager()->selectTexture(0, m_pSpriteTexture, 0.0f, KRTexture::TEXTURE_USAGE_SPRITE); - m_pContext->getMeshManager()->bindVBO(&m_pContext->getMeshManager()->KRENGINE_VBO_DATA_2D_SQUARE_VERTICES); + m_pContext->getMeshManager()->bindVBO(&m_pContext->getMeshManager()->KRENGINE_VBO_DATA_2D_SQUARE_VERTICES, 1.0f); GLDEBUG(glDrawArrays(GL_TRIANGLE_STRIP, 0, 4)); } } diff --git a/KREngine/kraken/KRTextureManager.cpp b/KREngine/kraken/KRTextureManager.cpp index c9fdcc7..4707ad8 100644 --- a/KREngine/kraken/KRTextureManager.cpp +++ b/KREngine/kraken/KRTextureManager.cpp @@ -256,7 +256,6 @@ void KRTextureManager::startFrame(float deltaTime) const long KRENGINE_TEXTURE_EXPIRY_FRAMES = 10; - std::set expiredTextures; for(std::set::iterator itr=m_activeTextures.begin(); itr != m_activeTextures.end(); itr++) { KRTexture *activeTexture = *itr; @@ -282,7 +281,6 @@ void KRTextureManager::startFrame(float deltaTime) m_streamerFenceMutex.unlock(); m_memoryTransferredThisFrame = 0; - rotateBuffers(); } void KRTextureManager::endFrame(float deltaTime) @@ -400,11 +398,6 @@ void KRTextureManager::balanceTextureMemory(long &memoryRemaining, long &memoryR } -void KRTextureManager::rotateBuffers() -{ - -} - long KRTextureManager::getMemoryTransferedThisFrame() { return m_memoryTransferredThisFrame; diff --git a/KREngine/kraken/KRTextureManager.h b/KREngine/kraken/KRTextureManager.h index fdc81db..06e187c 100644 --- a/KREngine/kraken/KRTextureManager.h +++ b/KREngine/kraken/KRTextureManager.h @@ -101,7 +101,6 @@ private: std::atomic m_textureMemUsed; - void rotateBuffers(); void balanceTextureMemory(long &memoryRemaining, long &memoryRemainingThisFrame); std::mutex m_streamerFenceMutex;