From e8f9652e42c1af6769c3fe99055c1a3b0f955ffc Mon Sep 17 00:00:00 2001 From: Kearwood Gilbert Date: Fri, 11 Apr 2014 01:15:40 -0700 Subject: [PATCH] Implemented new texture streaming algorithm: MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Textures are assigned a “weight” by tuneable criteria: - Area of screen coverage taken by objects containing material (more accurate and generic than distance) - Type of texture (separate weight for normal, diffuse, spec maps) - Last used time (to keep textures loaded for recently seen objects that are outside of the view frustum) Those factors combine together to give a “weight”, which represents a proportion relative to all other textures weights Mipmap levels are stripped off of each texture until they occupy the amount of memory they should proportionally have This is in contrast to the global ceiling of texture resolution that slowly drops until the textures fit --HG-- branch : nfb extra : rebase_source : 0710cebf76f196f5fea20b6df51be539fafbd834 --- KREngine/kraken/KRCamera.cpp | 31 +++-- KREngine/kraken/KRLODSet.cpp | 6 +- KREngine/kraken/KRLODSet.h | 2 +- KREngine/kraken/KRLight.cpp | 2 +- KREngine/kraken/KRMaterial.cpp | 26 ++-- KREngine/kraken/KRMaterial.h | 4 +- KREngine/kraken/KRMesh.cpp | 8 +- KREngine/kraken/KRMesh.h | 4 +- KREngine/kraken/KRModel.cpp | 20 +++- KREngine/kraken/KRModel.h | 2 +- KREngine/kraken/KRNode.cpp | 4 +- KREngine/kraken/KRNode.h | 2 +- KREngine/kraken/KRParticleSystemNewtonian.cpp | 2 +- KREngine/kraken/KRScene.cpp | 5 +- KREngine/kraken/KRScene.h | 2 +- KREngine/kraken/KRShader.cpp | 6 +- KREngine/kraken/KRSprite.cpp | 2 +- KREngine/kraken/KRTexture.cpp | 56 +++++++-- KREngine/kraken/KRTexture.h | 27 ++++- KREngine/kraken/KRTextureAnimated.cpp | 9 +- KREngine/kraken/KRTextureAnimated.h | 2 +- KREngine/kraken/KRTextureCube.cpp | 6 +- KREngine/kraken/KRTextureCube.h | 2 +- KREngine/kraken/KRTextureManager.cpp | 112 ++++++++++++------ KREngine/kraken/KRTextureManager.h | 8 +- KREngine/kraken/KRViewport.cpp | 14 ++- 26 files changed, 241 insertions(+), 123 deletions(-) diff --git a/KREngine/kraken/KRCamera.cpp b/KREngine/kraken/KRCamera.cpp index dca0ea4..2ee541a 100644 --- a/KREngine/kraken/KRCamera.cpp +++ b/KREngine/kraken/KRCamera.cpp @@ -79,7 +79,7 @@ void KRCamera::loadXML(tinyxml2::XMLElement *e) void KRCamera::flushSkybox() { - m_pSkyBoxTexture = NULL; // NOTE: the streamer manages the loading and unloading of the skybox textures + m_pSkyBoxTexture = NULL; // NOTE: the texture manager manages the loading and unloading of the skybox textures } void KRCamera::renderFrame(float deltaTime, GLint renderBufferWidth, GLint renderBufferHeight) @@ -183,10 +183,10 @@ void KRCamera::renderFrame(float deltaTime, GLint renderBufferWidth, GLint rende GLDEBUG(glDepthMask(GL_FALSE)); // Set source to buffers from pass 1 - m_pContext->getTextureManager()->selectTexture(6, NULL); + m_pContext->getTextureManager()->selectTexture(6, NULL, 0.0f, KRTexture::TEXTURE_USAGE_NONE); m_pContext->getTextureManager()->_setActiveTexture(6); GLDEBUG(glBindTexture(GL_TEXTURE_2D, compositeColorTexture)); - m_pContext->getTextureManager()->selectTexture(7, NULL); + m_pContext->getTextureManager()->selectTexture(7, NULL, 0.0f, KRTexture::TEXTURE_USAGE_NONE); m_pContext->getTextureManager()->_setActiveTexture(7); GLDEBUG(glBindTexture(GL_TEXTURE_2D, compositeDepthTexture)); @@ -211,7 +211,7 @@ void KRCamera::renderFrame(float deltaTime, GLint renderBufferWidth, GLint rende GLDEBUG(glClear(GL_COLOR_BUFFER_BIT)); // Set source to buffers from pass 2 - m_pContext->getTextureManager()->selectTexture(6, NULL); + m_pContext->getTextureManager()->selectTexture(6, NULL, 0.0f, KRTexture::TEXTURE_USAGE_NONE); m_pContext->getTextureManager()->_setActiveTexture(6); GLDEBUG(glBindTexture(GL_TEXTURE_2D, lightAccumulationTexture)); @@ -232,10 +232,10 @@ void KRCamera::renderFrame(float deltaTime, GLint renderBufferWidth, GLint rende scene.render(this, m_viewport.getVisibleBounds(), m_viewport, KRNode::RENDER_PASS_DEFERRED_OPAQUE, false); // Deactivate source buffer texture units - m_pContext->getTextureManager()->selectTexture(6, NULL); + m_pContext->getTextureManager()->selectTexture(6, NULL, 0.0f, KRTexture::TEXTURE_USAGE_NONE); m_pContext->getTextureManager()->_setActiveTexture(6); GLDEBUG(glBindTexture(GL_TEXTURE_2D, 0)); - m_pContext->getTextureManager()->selectTexture(7, NULL); + m_pContext->getTextureManager()->selectTexture(7, NULL, 0.0f, KRTexture::TEXTURE_USAGE_NONE); m_pContext->getTextureManager()->_setActiveTexture(7); GLDEBUG(glBindTexture(GL_TEXTURE_2D, 0)); @@ -313,7 +313,7 @@ void KRCamera::renderFrame(float deltaTime, GLint renderBufferWidth, GLint rende KRVector3 rim_color; getContext().getShaderManager()->selectShader("sky_box", *this, std::vector(), std::vector(), std::vector(), 0, m_viewport, KRMat4(), false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, KRNode::RENDER_PASS_FORWARD_OPAQUE, rim_color, 0.0f); - getContext().getTextureManager()->selectTexture(0, m_pSkyBoxTexture); + getContext().getTextureManager()->selectTexture(0, m_pSkyBoxTexture, 0.0f, KRTexture::TEXTURE_USAGE_SKY_CUBE); // Render a full screen quad m_pContext->getModelManager()->bindVBO(getContext().getModelManager()->KRENGINE_VBO_2D_SQUARE_VERTICES, getContext().getModelManager()->KRENGINE_VBO_2D_SQUARE_INDEXES, getContext().getModelManager()->KRENGINE_VBO_2D_SQUARE_ATTRIBS, true); @@ -425,7 +425,7 @@ void KRCamera::renderFrame(float deltaTime, GLint renderBufferWidth, GLint rende // Disable z-buffer test GLDEBUG(glDisable(GL_DEPTH_TEST)); - m_pContext->getTextureManager()->selectTexture(0, NULL); + m_pContext->getTextureManager()->selectTexture(0, NULL, 0.0f, KRTexture::TEXTURE_USAGE_NONE); m_pContext->getTextureManager()->_setActiveTexture(0); GLDEBUG(glBindTexture(GL_TEXTURE_2D, compositeDepthTexture)); @@ -692,16 +692,16 @@ void KRCamera::renderPost() KRVector3 rim_color; getContext().getShaderManager()->selectShader(*this, postShader, m_viewport, KRMat4(), std::vector(), std::vector(), std::vector(), 0, KRNode::RENDER_PASS_FORWARD_TRANSPARENT, rim_color, 0.0f); - m_pContext->getTextureManager()->selectTexture(0, NULL); + m_pContext->getTextureManager()->selectTexture(0, NULL, 0.0f, KRTexture::TEXTURE_USAGE_NONE); m_pContext->getTextureManager()->_setActiveTexture(0); GLDEBUG(glBindTexture(GL_TEXTURE_2D, compositeDepthTexture)); - m_pContext->getTextureManager()->selectTexture(1, NULL); + m_pContext->getTextureManager()->selectTexture(1, NULL, 0.0f, KRTexture::TEXTURE_USAGE_NONE); m_pContext->getTextureManager()->_setActiveTexture(1); GLDEBUG(glBindTexture(GL_TEXTURE_2D, compositeColorTexture)); if(settings.volumetric_environment_enable) { - m_pContext->getTextureManager()->selectTexture(2, NULL); + m_pContext->getTextureManager()->selectTexture(2, NULL, 0.0f, KRTexture::TEXTURE_USAGE_NONE); m_pContext->getTextureManager()->_setActiveTexture(2); GLDEBUG(glBindTexture(GL_TEXTURE_2D, volumetricLightAccumulationTexture)); } @@ -711,11 +711,11 @@ void KRCamera::renderPost() GLDEBUG(glDrawArrays(GL_TRIANGLE_STRIP, 0, 4)); - m_pContext->getTextureManager()->selectTexture(0, NULL); + m_pContext->getTextureManager()->selectTexture(0, NULL, 0.0f, KRTexture::TEXTURE_USAGE_NONE); m_pContext->getTextureManager()->_setActiveTexture(0); GLDEBUG(glBindTexture(GL_TEXTURE_2D, 0)); - m_pContext->getTextureManager()->selectTexture(1, NULL); + m_pContext->getTextureManager()->selectTexture(1, NULL, 0.0f, KRTexture::TEXTURE_USAGE_NONE); m_pContext->getTextureManager()->_setActiveTexture(1); GLDEBUG(glBindTexture(GL_TEXTURE_2D, 0)); @@ -895,7 +895,7 @@ void KRCamera::renderPost() KRVector3 rim_color; getContext().getShaderManager()->selectShader(*this, fontShader, m_viewport, KRMat4(), std::vector(), std::vector(), std::vector(), 0, KRNode::RENDER_PASS_FORWARD_TRANSPARENT, rim_color, 0.0f); - m_pContext->getTextureManager()->selectTexture(0, m_pContext->getTextureManager()->getTexture("font")); + m_pContext->getTextureManager()->selectTexture(0, m_pContext->getTextureManager()->getTexture("font"), 0.0f, KRTexture::TEXTURE_USAGE_UI); KRDataBlock index_data; //m_pContext->getModelManager()->bindVBO((void *)m_debug_text_vertices, vertex_count * sizeof(DebugTextVertexData), NULL, 0, (1 << KRMesh::KRENGINE_ATTRIB_VERTEX) | (1 << KRMesh::KRENGINE_ATTRIB_TEXUVA), true); @@ -983,8 +983,7 @@ std::string KRCamera::getDebugText() // ---- GPU Memory ---- int texture_count_active = m_pContext->getTextureManager()->getActiveTextures().size(); - int texture_count_pooled = m_pContext->getTextureManager()->getPoolTextures().size(); - int texture_count = texture_count_active + texture_count_pooled; + int texture_count = texture_count_active; long texture_mem_active = m_pContext->getTextureManager()->getMemActive(); long texture_mem_used = m_pContext->getTextureManager()->getMemUsed(); long texture_mem_throughput = m_pContext->getTextureManager()->getMemoryTransferedThisFrame(); diff --git a/KREngine/kraken/KRLODSet.cpp b/KREngine/kraken/KRLODSet.cpp index 01a7cd0..80e288f 100644 --- a/KREngine/kraken/KRLODSet.cpp +++ b/KREngine/kraken/KRLODSet.cpp @@ -55,7 +55,7 @@ void KRLODSet::updateLODVisibility(const KRViewport &viewport) } else if(m_activeLODGroup == NULL) { m_activeLODGroup = new_active_lod_group; } else if(new_active_lod_group != m_activeLODGroup) { - if(true || new_active_lod_group->getStreamLevel(true) >= kraken_stream_level::STREAM_LEVEL_IN_LQ) { + if(new_active_lod_group->getStreamLevel(true, viewport) >= kraken_stream_level::STREAM_LEVEL_IN_LQ) { // fprintf(stderr, "LOD %s -> %s\n", m_activeLODGroup->getName().c_str(), new_active_lod_group->getName().c_str()); m_activeLODGroup = new_active_lod_group; } else { @@ -104,10 +104,10 @@ void KRLODSet::showLOD() } } -kraken_stream_level KRLODSet::getStreamLevel(bool prime) +kraken_stream_level KRLODSet::getStreamLevel(bool prime, const KRViewport &viewport) { if(m_activeLODGroup) { - return m_activeLODGroup->getStreamLevel(prime); + return m_activeLODGroup->getStreamLevel(prime, viewport); } else { return kraken_stream_level::STREAM_LEVEL_IN_HQ; } diff --git a/KREngine/kraken/KRLODSet.h b/KREngine/kraken/KRLODSet.h index a66544f..3e3c433 100644 --- a/KREngine/kraken/KRLODSet.h +++ b/KREngine/kraken/KRLODSet.h @@ -30,7 +30,7 @@ public: virtual void hideLOD(); virtual void childDeleted(KRNode *child_node); - virtual kraken_stream_level getStreamLevel(bool prime = true); + virtual kraken_stream_level getStreamLevel(bool prime, const KRViewport &viewport); private: KRLODGroup *m_activeLODGroup; diff --git a/KREngine/kraken/KRLight.cpp b/KREngine/kraken/KRLight.cpp index 79a303e..6f44976 100644 --- a/KREngine/kraken/KRLight.cpp +++ b/KREngine/kraken/KRLight.cpp @@ -338,7 +338,7 @@ void KRLight::render(KRCamera *pCamera, std::vector &point_light if(getContext().getShaderManager()->selectShader(*pCamera, pShader, viewport, getModelMatrix(), point_lights, directional_lights, spot_lights, 0, renderPass, rim_light, 0.0f)) { 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); + m_pContext->getTextureManager()->selectTexture(0, m_pFlareTexture, 0.0f, KRTexture::TEXTURE_USAGE_LIGHT_FLARE); m_pContext->getModelManager()->bindVBO(getContext().getModelManager()->KRENGINE_VBO_2D_SQUARE_VERTICES, getContext().getModelManager()->KRENGINE_VBO_2D_SQUARE_INDEXES, getContext().getModelManager()->KRENGINE_VBO_2D_SQUARE_ATTRIBS, true); GLDEBUG(glDrawArrays(GL_TRIANGLE_STRIP, 0, 4)); } diff --git a/KREngine/kraken/KRMaterial.cpp b/KREngine/kraken/KRMaterial.cpp index bbe4730..f938e02 100644 --- a/KREngine/kraken/KRMaterial.cpp +++ b/KREngine/kraken/KRMaterial.cpp @@ -217,34 +217,34 @@ bool KRMaterial::isTransparent() { return m_tr < 1.0 || m_alpha_mode == KRMATERIAL_ALPHA_MODE_BLENDONESIDE || m_alpha_mode == KRMATERIAL_ALPHA_MODE_BLENDTWOSIDE; } -kraken_stream_level KRMaterial::getStreamLevel(bool prime) +kraken_stream_level KRMaterial::getStreamLevel(bool prime, float lodCoverage) { kraken_stream_level stream_level = kraken_stream_level::STREAM_LEVEL_IN_HQ; getTextures(); if(m_pAmbientMap) { - stream_level = KRMIN(stream_level, m_pNormalMap->getStreamLevel(prime)); + stream_level = KRMIN(stream_level, m_pNormalMap->getStreamLevel(prime, lodCoverage, KRTexture::TEXTURE_USAGE_AMBIENT_MAP)); } if(m_pDiffuseMap) { - stream_level = KRMIN(stream_level, m_pDiffuseMap->getStreamLevel(prime)); + stream_level = KRMIN(stream_level, m_pDiffuseMap->getStreamLevel(prime, lodCoverage, KRTexture::TEXTURE_USAGE_DIFFUSE_MAP)); } if(m_pNormalMap) { - stream_level = KRMIN(stream_level, m_pNormalMap->getStreamLevel(prime)); + stream_level = KRMIN(stream_level, m_pNormalMap->getStreamLevel(prime, lodCoverage, KRTexture::TEXTURE_USAGE_NORMAL_MAP)); } if(m_pSpecularMap) { - stream_level = KRMIN(stream_level, m_pSpecularMap->getStreamLevel(prime)); + stream_level = KRMIN(stream_level, m_pSpecularMap->getStreamLevel(prime, lodCoverage, KRTexture::TEXTURE_USAGE_SPECULAR_MAP)); } if(m_pReflectionMap) { - stream_level = KRMIN(stream_level, m_pReflectionMap->getStreamLevel(prime)); + stream_level = KRMIN(stream_level, m_pReflectionMap->getStreamLevel(prime, lodCoverage, KRTexture::TEXTURE_USAGE_REFLECTION_MAP)); } if(m_pReflectionCube) { - stream_level = KRMIN(stream_level, m_pReflectionCube->getStreamLevel(prime)); + stream_level = KRMIN(stream_level, m_pReflectionCube->getStreamLevel(prime, lodCoverage, KRTexture::TEXTURE_USAGE_REFECTION_CUBE)); } return stream_level; @@ -272,7 +272,7 @@ void KRMaterial::getTextures() } } -bool KRMaterial::bind(KRCamera *pCamera, std::vector &point_lights, std::vector &directional_lights, std::vector&spot_lights, const std::vector &bones, const std::vector &bind_poses, const KRViewport &viewport, const KRMat4 &matModel, KRTexture *pLightMap, KRNode::RenderPass renderPass, const KRVector3 &rim_color, float rim_power) { +bool KRMaterial::bind(KRCamera *pCamera, std::vector &point_lights, std::vector &directional_lights, std::vector&spot_lights, const std::vector &bones, const std::vector &bind_poses, const KRViewport &viewport, const KRMat4 &matModel, KRTexture *pLightMap, KRNode::RenderPass renderPass, const KRVector3 &rim_color, float rim_power, float lod_coverage) { bool bLightMap = pLightMap && pCamera->settings.bEnableLightMap; getTextures(); @@ -359,24 +359,24 @@ bool KRMaterial::bind(KRCamera *pCamera, std::vector &point_ligh pShader->setUniform(KRShader::KRENGINE_UNIFORM_MATERIAL_ALPHA, m_tr); if(bDiffuseMap) { - m_pContext->getTextureManager()->selectTexture(0, m_pDiffuseMap); + m_pContext->getTextureManager()->selectTexture(0, m_pDiffuseMap, lod_coverage, KRTexture::TEXTURE_USAGE_DIFFUSE_MAP); } if(bSpecMap) { - m_pContext->getTextureManager()->selectTexture(1, m_pSpecularMap); + m_pContext->getTextureManager()->selectTexture(1, m_pSpecularMap, lod_coverage, KRTexture::TEXTURE_USAGE_SPECULAR_MAP); } if(bNormalMap) { - m_pContext->getTextureManager()->selectTexture(2, m_pNormalMap); + m_pContext->getTextureManager()->selectTexture(2, m_pNormalMap, lod_coverage, KRTexture::TEXTURE_USAGE_NORMAL_MAP); } if(bReflectionCubeMap && (renderPass == KRNode::RENDER_PASS_FORWARD_OPAQUE || renderPass == KRNode::RENDER_PASS_DEFERRED_OPAQUE)) { - m_pContext->getTextureManager()->selectTexture(4, m_pReflectionCube); + m_pContext->getTextureManager()->selectTexture(4, m_pReflectionCube, lod_coverage, KRTexture::TEXTURE_USAGE_REFECTION_CUBE); } if(bReflectionMap && (renderPass == KRNode::RENDER_PASS_FORWARD_OPAQUE || renderPass == KRNode::RENDER_PASS_DEFERRED_OPAQUE)) { // GL_TEXTURE7 is used for reading the depth buffer in gBuffer pass 2 and re-used for the reflection map in gBuffer Pass 3 and in forward rendering - m_pContext->getTextureManager()->selectTexture(7, m_pReflectionMap); + m_pContext->getTextureManager()->selectTexture(7, m_pReflectionMap, lod_coverage, KRTexture::TEXTURE_USAGE_REFLECTION_MAP); } diff --git a/KREngine/kraken/KRMaterial.h b/KREngine/kraken/KRMaterial.h index 503a045..31a09a5 100644 --- a/KREngine/kraken/KRMaterial.h +++ b/KREngine/kraken/KRMaterial.h @@ -84,11 +84,11 @@ public: bool isTransparent(); const std::string &getName() const; - bool bind(KRCamera *pCamera, std::vector &point_lights, std::vector &directional_lights, std::vector&spot_lights, const std::vector &bones, const std::vector &bind_poses, const KRViewport &viewport, const KRMat4 &matModel, KRTexture *pLightMap, KRNode::RenderPass renderPass, const KRVector3 &rim_color, float rim_power); + bool bind(KRCamera *pCamera, std::vector &point_lights, std::vector &directional_lights, std::vector&spot_lights, const std::vector &bones, const std::vector &bind_poses, const KRViewport &viewport, const KRMat4 &matModel, KRTexture *pLightMap, KRNode::RenderPass renderPass, const KRVector3 &rim_color, float rim_power, float lod_coverage = 0.0f); bool needsVertexTangents(); - kraken_stream_level getStreamLevel(bool prime = true); + kraken_stream_level getStreamLevel(bool prime, float lodCoverage); private: std::string m_name; diff --git a/KREngine/kraken/KRMesh.cpp b/KREngine/kraken/KRMesh.cpp index b6ba1b3..c180b3c 100644 --- a/KREngine/kraken/KRMesh.cpp +++ b/KREngine/kraken/KRMesh.cpp @@ -186,20 +186,20 @@ void KRMesh::getMaterials() } } -kraken_stream_level KRMesh::getStreamLevel(bool prime) +kraken_stream_level KRMesh::getStreamLevel(bool prime, float lodCoverage) { kraken_stream_level stream_level = kraken_stream_level::STREAM_LEVEL_IN_HQ; getSubmeshes(); getMaterials(); for(std::set::iterator mat_itr = m_uniqueMaterials.begin(); mat_itr != m_uniqueMaterials.end(); mat_itr++) { - stream_level = KRMIN(stream_level, (*mat_itr)->getStreamLevel(prime)); + stream_level = KRMIN(stream_level, (*mat_itr)->getStreamLevel(prime, lodCoverage)); } return stream_level; } -void KRMesh::render(const std::string &object_name, KRCamera *pCamera, std::vector &point_lights, std::vector &directional_lights, std::vector&spot_lights, const KRViewport &viewport, const KRMat4 &matModel, KRTexture *pLightMap, KRNode::RenderPass renderPass, const std::vector &bones, const KRVector3 &rim_color, float rim_power) { +void KRMesh::render(const std::string &object_name, KRCamera *pCamera, std::vector &point_lights, std::vector &directional_lights, std::vector&spot_lights, const KRViewport &viewport, const KRMat4 &matModel, KRTexture *pLightMap, KRNode::RenderPass renderPass, const std::vector &bones, const KRVector3 &rim_color, float rim_power, float lod_coverage) { //fprintf(stderr, "Rendering model: %s\n", m_name.c_str()); @@ -233,7 +233,7 @@ void KRMesh::render(const std::string &object_name, KRCamera *pCamera, std::vect 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)) { + 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 diff --git a/KREngine/kraken/KRMesh.h b/KREngine/kraken/KRMesh.h index 891ddeb..c2ab5ea 100644 --- a/KREngine/kraken/KRMesh.h +++ b/KREngine/kraken/KRMesh.h @@ -67,7 +67,7 @@ public: KRMesh(KRContext &context, std::string name); virtual ~KRMesh(); - kraken_stream_level getStreamLevel(bool prime = true); + kraken_stream_level getStreamLevel(bool prime, float lodCoverage); bool hasTransparency(); @@ -112,7 +112,7 @@ public: std::vector > bone_weights; } mesh_info; - void render(const std::string &object_name, KRCamera *pCamera, std::vector &point_lights, std::vector &directional_lights, std::vector&spot_lights, const KRViewport &viewport, const KRMat4 &matModel, KRTexture *pLightMap, KRNode::RenderPass renderPass, const std::vector &bones, const KRVector3 &rim_color, float rim_power); + void render(const std::string &object_name, KRCamera *pCamera, std::vector &point_lights, std::vector &directional_lights, std::vector&spot_lights, const KRViewport &viewport, const KRMat4 &matModel, KRTexture *pLightMap, KRNode::RenderPass renderPass, const std::vector &bones, const KRVector3 &rim_color, float rim_power, float lod_coverage = 0.0f); std::string m_lodBaseName; diff --git a/KREngine/kraken/KRModel.cpp b/KREngine/kraken/KRModel.cpp index eb01799..731baea 100644 --- a/KREngine/kraken/KRModel.cpp +++ b/KREngine/kraken/KRModel.cpp @@ -157,13 +157,17 @@ void KRModel::render(KRCamera *pCamera, std::vector &point_light if(m_models.size() > 0) { // Don't render meshes on second pass of the deferred lighting renderer, as only lights will be applied - + + /* float lod_coverage = 0.0f; if(m_models.size() > 1) { lod_coverage = viewport.coverage(getBounds()); // This also checks the view frustrum culling } else if(viewport.visible(getBounds())) { lod_coverage = 1.0f; } + */ + + float lod_coverage = viewport.coverage(getBounds()); // This also checks the view frustrum culling if(lod_coverage > m_min_lod_coverage) { @@ -185,7 +189,7 @@ void KRModel::render(KRCamera *pCamera, std::vector &point_light } if(m_pLightMap && pCamera->settings.bEnableLightMap && renderPass != RENDER_PASS_SHADOWMAP && renderPass != RENDER_PASS_GENERATE_SHADOWMAPS) { - m_pContext->getTextureManager()->selectTexture(5, m_pLightMap); + m_pContext->getTextureManager()->selectTexture(5, m_pLightMap, lod_coverage, KRTexture::TEXTURE_USAGE_LIGHT_MAP); } KRMat4 matModel = getModelMatrix(); @@ -195,21 +199,25 @@ void KRModel::render(KRCamera *pCamera, std::vector &point_light matModel = KRQuaternion(KRVector3::Forward(), KRVector3::Normalize(camera_pos - model_center)).rotationMatrix() * matModel; } - pModel->render(getName(), pCamera, point_lights, directional_lights, spot_lights, viewport, matModel, m_pLightMap, renderPass, m_bones[pModel], m_rim_color, m_rim_power); + pModel->render(getName(), pCamera, point_lights, directional_lights, spot_lights, viewport, matModel, m_pLightMap, renderPass, m_bones[pModel], m_rim_color, m_rim_power, lod_coverage); } } } } -kraken_stream_level KRModel::getStreamLevel(bool prime) +kraken_stream_level KRModel::getStreamLevel(bool prime, const KRViewport &viewport) { - kraken_stream_level stream_level = KRNode::getStreamLevel(prime); + kraken_stream_level stream_level = KRNode::getStreamLevel(prime, viewport); loadModel(); + float lod_coverage = 0.0f; + if(prime) { + lod_coverage = viewport.coverage(getBounds()); // This is only used when prime is true + } for(auto itr = m_models.begin(); itr != m_models.end(); itr++) { - stream_level = KRMIN(stream_level, (*itr)->getStreamLevel(prime)); + stream_level = KRMIN(stream_level, (*itr)->getStreamLevel(prime, lod_coverage)); } return stream_level; diff --git a/KREngine/kraken/KRModel.h b/KREngine/kraken/KRModel.h index a048071..f771a4b 100644 --- a/KREngine/kraken/KRModel.h +++ b/KREngine/kraken/KRModel.h @@ -69,7 +69,7 @@ public: void setLightMap(const std::string &name); std::string getLightMap(); - virtual kraken_stream_level getStreamLevel(bool prime = true); + virtual kraken_stream_level getStreamLevel(bool prime, const KRViewport &viewport); private: std::vector m_models; diff --git a/KREngine/kraken/KRNode.cpp b/KREngine/kraken/KRNode.cpp index 868cc87..4f5b07f 100644 --- a/KREngine/kraken/KRNode.cpp +++ b/KREngine/kraken/KRNode.cpp @@ -944,12 +944,12 @@ std::set &KRNode::getBehaviors() return m_behaviors; } -kraken_stream_level KRNode::getStreamLevel(bool prime) +kraken_stream_level KRNode::getStreamLevel(bool prime, const KRViewport &viewport) { kraken_stream_level stream_level = kraken_stream_level::STREAM_LEVEL_IN_HQ; for(std::set::iterator itr=m_childNodes.begin(); itr != m_childNodes.end(); ++itr) { - stream_level = KRMIN(stream_level, (*itr)->getStreamLevel(prime)); + stream_level = KRMIN(stream_level, (*itr)->getStreamLevel(prime, viewport)); } return stream_level; diff --git a/KREngine/kraken/KRNode.h b/KREngine/kraken/KRNode.h index f9503b6..f542d1a 100644 --- a/KREngine/kraken/KRNode.h +++ b/KREngine/kraken/KRNode.h @@ -167,7 +167,7 @@ public: bool getAnimationEnabled(node_attribute_type attrib) const; - virtual kraken_stream_level getStreamLevel(bool prime = true); + virtual kraken_stream_level getStreamLevel(bool prime, const KRViewport &viewport); virtual void hideLOD(); virtual void showLOD(); diff --git a/KREngine/kraken/KRParticleSystemNewtonian.cpp b/KREngine/kraken/KRParticleSystemNewtonian.cpp index 89e9dc5..7431e75 100644 --- a/KREngine/kraken/KRParticleSystemNewtonian.cpp +++ b/KREngine/kraken/KRParticleSystemNewtonian.cpp @@ -68,7 +68,7 @@ void KRParticleSystemNewtonian::render(KRCamera *pCamera, std::vectorgetTextureManager()->getTexture("flare"); - m_pContext->getTextureManager()->selectTexture(0, pParticleTexture); + m_pContext->getTextureManager()->selectTexture(0, pParticleTexture, 0.0f, KRTexture::TEXTURE_USAGE_PARTICLE); int particle_count = 10000; diff --git a/KREngine/kraken/KRScene.cpp b/KREngine/kraken/KRScene.cpp index 8cd20f4..576d8a8 100644 --- a/KREngine/kraken/KRScene.cpp +++ b/KREngine/kraken/KRScene.cpp @@ -599,12 +599,13 @@ bool KRScene::sphereCast(const KRVector3 &v0, const KRVector3 &v1, float radius, } -kraken_stream_level KRScene::getStreamLevel(bool prime) +kraken_stream_level KRScene::getStreamLevel() { kraken_stream_level stream_level = kraken_stream_level::STREAM_LEVEL_IN_HQ; if(m_pRootNode) { - stream_level = KRMIN(stream_level, m_pRootNode->getStreamLevel(prime)); + KRViewport viewport; // This isn't used when prime is false + stream_level = KRMIN(stream_level, m_pRootNode->getStreamLevel(false, viewport)); } return stream_level; diff --git a/KREngine/kraken/KRScene.h b/KREngine/kraken/KRScene.h index 799eab2..0ba470c 100644 --- a/KREngine/kraken/KRScene.h +++ b/KREngine/kraken/KRScene.h @@ -64,7 +64,7 @@ public: KRNode *getRootNode(); KRLight *getFirstLight(); - kraken_stream_level getStreamLevel(bool prime = true); + kraken_stream_level getStreamLevel(); bool lineCast(const KRVector3 &v0, const KRVector3 &v1, KRHitInfo &hitinfo, unsigned int layer_mask); bool rayCast(const KRVector3 &v0, const KRVector3 &dir, KRHitInfo &hitinfo, unsigned int layer_mask); diff --git a/KREngine/kraken/KRShader.cpp b/KREngine/kraken/KRShader.cpp index b1423e0..a2fd09a 100644 --- a/KREngine/kraken/KRShader.cpp +++ b/KREngine/kraken/KRShader.cpp @@ -372,7 +372,7 @@ bool KRShader::bind(KRCamera &camera, const KRViewport &viewport, const KRMat4 & if(light_directional_count == 0) { int cShadowBuffers = directional_light->getShadowBufferCount(); if(m_uniforms[KRENGINE_UNIFORM_SHADOWTEXTURE1] != -1 && cShadowBuffers > 0) { - m_pContext->getTextureManager()->selectTexture(3, NULL); + m_pContext->getTextureManager()->selectTexture(3, NULL, 0.0f, KRTexture::TEXTURE_USAGE_SHADOW_DEPTH); m_pContext->getTextureManager()->_setActiveTexture(3); GLDEBUG(glBindTexture(GL_TEXTURE_2D, directional_light->getShadowTextures()[0])); GLDEBUG(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR)); @@ -383,7 +383,7 @@ bool KRShader::bind(KRCamera &camera, const KRViewport &viewport, const KRMat4 & } if(m_uniforms[KRENGINE_UNIFORM_SHADOWTEXTURE2] != -1 && cShadowBuffers > 1 && camera.settings.m_cShadowBuffers > 1) { - m_pContext->getTextureManager()->selectTexture(4, NULL); + m_pContext->getTextureManager()->selectTexture(4, NULL, 0.0f, KRTexture::TEXTURE_USAGE_SHADOW_DEPTH); m_pContext->getTextureManager()->_setActiveTexture(4); GLDEBUG(glBindTexture(GL_TEXTURE_2D, directional_light->getShadowTextures()[1])); GLDEBUG(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR)); @@ -393,7 +393,7 @@ bool KRShader::bind(KRCamera &camera, const KRViewport &viewport, const KRMat4 & } if(m_uniforms[KRENGINE_UNIFORM_SHADOWTEXTURE3] != -1 && cShadowBuffers > 2 && camera.settings.m_cShadowBuffers > 2) { - m_pContext->getTextureManager()->selectTexture(5, NULL); + m_pContext->getTextureManager()->selectTexture(5, NULL, 0.0f, KRTexture::TEXTURE_USAGE_SHADOW_DEPTH); m_pContext->getTextureManager()->_setActiveTexture(5); GLDEBUG(glActiveTexture(GL_TEXTURE5)); GLDEBUG(glBindTexture(GL_TEXTURE_2D, directional_light->getShadowTextures()[2])); diff --git a/KREngine/kraken/KRSprite.cpp b/KREngine/kraken/KRSprite.cpp index c9f63c6..62fbe5f 100644 --- a/KREngine/kraken/KRSprite.cpp +++ b/KREngine/kraken/KRSprite.cpp @@ -118,7 +118,7 @@ void KRSprite::render(KRCamera *pCamera, std::vector &point_ligh KRVector3 rim_color; 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); + m_pContext->getTextureManager()->selectTexture(0, m_pSpriteTexture, 0.0f, KRTexture::TEXTURE_USAGE_SPRITE); m_pContext->getModelManager()->bindVBO(getContext().getModelManager()->KRENGINE_VBO_2D_SQUARE_VERTICES, getContext().getModelManager()->KRENGINE_VBO_2D_SQUARE_INDEXES, getContext().getModelManager()->KRENGINE_VBO_2D_SQUARE_ATTRIBS, true); GLDEBUG(glDrawArrays(GL_TRIANGLE_STRIP, 0, 4)); } diff --git a/KREngine/kraken/KRTexture.cpp b/KREngine/kraken/KRTexture.cpp index f0207aa..0789815 100644 --- a/KREngine/kraken/KRTexture.cpp +++ b/KREngine/kraken/KRTexture.cpp @@ -20,6 +20,8 @@ KRTexture::KRTexture(KRContext &context, std::string name) : KRResource(context, m_newTextureMemUsed = 0; m_last_frame_used = 0; m_last_frame_bound = 0; + m_last_frame_max_lod_coverage = 0.0f; + m_last_frame_usage = TEXTURE_USAGE_NONE; m_handle_lock.clear(); } @@ -90,31 +92,71 @@ void KRTexture::resize(int max_dim) } GLuint KRTexture::getHandle() { - resetPoolExpiry(); + resetPoolExpiry(0.0f, KRTexture::TEXTURE_USAGE_NONE); // TODO - Pass through getHandle() arguements to replace extraneous resetPoolExpiry calls? return m_iHandle; } -void KRTexture::resetPoolExpiry() +void KRTexture::resetPoolExpiry(float lodCoverage, KRTexture::texture_usage_t textureUsage) { - m_last_frame_used = getContext().getCurrentFrame(); + long current_frame = getContext().getCurrentFrame(); + if(current_frame != m_last_frame_used) { + m_last_frame_used = current_frame; + m_last_frame_max_lod_coverage = 0.0f; + m_last_frame_usage = TEXTURE_USAGE_NONE; + + getContext().getTextureManager()->primeTexture(this); + } + m_last_frame_max_lod_coverage = KRMAX(lodCoverage, m_last_frame_max_lod_coverage); + m_last_frame_usage = static_cast(static_cast(m_last_frame_usage) | static_cast(textureUsage)); } - -kraken_stream_level KRTexture::getStreamLevel(bool prime) +kraken_stream_level KRTexture::getStreamLevel(bool prime, float lodCoverage, KRTexture::texture_usage_t textureUsage) { if(prime) { - resetPoolExpiry(); + resetPoolExpiry(lodCoverage, textureUsage); } if(m_current_lod_max_dim == 0) { return kraken_stream_level::STREAM_LEVEL_OUT; - } else if(m_current_lod_max_dim == m_max_lod_max_dim) { + } else if(m_current_lod_max_dim == KRMIN(getContext().KRENGINE_MAX_TEXTURE_DIM, m_max_lod_max_dim)) { return kraken_stream_level::STREAM_LEVEL_IN_HQ; } else { return kraken_stream_level::STREAM_LEVEL_IN_LQ; } } +float KRTexture::getStreamPriority() +{ + long current_frame = 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 { + float priority = 100.0f; + if(m_last_frame_usage & (TEXTURE_USAGE_UI | TEXTURE_USAGE_SHADOW_DEPTH)) { + priority += 10000000.0f; + } + if(m_last_frame_usage & (TEXTURE_USAGE_SKY_CUBE | TEXTURE_USAGE_PARTICLE | TEXTURE_USAGE_SPRITE | TEXTURE_USAGE_LIGHT_FLARE)) { + priority += 1000000.0f; + } + if(m_last_frame_usage & (TEXTURE_USAGE_DIFFUSE_MAP | TEXTURE_USAGE_AMBIENT_MAP | TEXTURE_USAGE_SPECULAR_MAP | TEXTURE_USAGE_NORMAL_MAP | TEXTURE_USAGE_REFLECTION_MAP)) { + priority += 100000.0f; + } + if(m_last_frame_usage & (TEXTURE_USAGE_LIGHT_MAP)) { + priority += 100000.0f; + } + if(m_last_frame_usage & (TEXTURE_USAGE_REFECTION_CUBE)) { + priority += 1000.0f; + } + priority += m_last_frame_max_lod_coverage * 10.0f; + return priority; + } +} + +float KRTexture::getLastFrameLodCoverage() const +{ + return m_last_frame_max_lod_coverage; +} + long KRTexture::getLastFrameUsed() { return m_last_frame_used; diff --git a/KREngine/kraken/KRTexture.h b/KREngine/kraken/KRTexture.h index dde342f..cc741fb 100644 --- a/KREngine/kraken/KRTexture.h +++ b/KREngine/kraken/KRTexture.h @@ -56,7 +56,26 @@ public: long getLastFrameUsed(); - virtual void resetPoolExpiry(); + typedef enum { + TEXTURE_USAGE_NONE = 0x00, + TEXTURE_USAGE_UI = 0x01, + TEXTURE_USAGE_SKY_CUBE = 0x02, + TEXTURE_USAGE_LIGHT_MAP = 0x04, + TEXTURE_USAGE_DIFFUSE_MAP = 0x08, + TEXTURE_USAGE_AMBIENT_MAP = 0x10, + TEXTURE_USAGE_SPECULAR_MAP = 0x20, + TEXTURE_USAGE_NORMAL_MAP = 0x40, + TEXTURE_USAGE_REFLECTION_MAP = 0x80, + TEXTURE_USAGE_REFECTION_CUBE = 0x100, + TEXTURE_USAGE_LIGHT_FLARE = 0x200, + TEXTURE_USAGE_SHADOW_DEPTH = 0x400, + TEXTURE_USAGE_PARTICLE = 0x800, + TEXTURE_USAGE_SPRITE = 0x1000 + } texture_usage_t; + + float getStreamPriority(); + + virtual void resetPoolExpiry(float lodCoverage, texture_usage_t textureUsage); virtual bool isAnimated(); virtual KRTexture *compress(bool premultiply_alpha = false); @@ -66,9 +85,11 @@ public: bool hasMipmaps(); bool canStreamOut() const; - kraken_stream_level getStreamLevel(bool prime = true); + kraken_stream_level getStreamLevel(bool prime, float lodCoverage, KRTexture::texture_usage_t textureUsage); + float getLastFrameLodCoverage() const; void _swapHandles(); + protected: virtual bool createGLTexture(int lod_max_dim) = 0; GLuint getHandle(); @@ -85,6 +106,8 @@ protected: long m_last_frame_used; long m_last_frame_bound; + float m_last_frame_max_lod_coverage; + texture_usage_t m_last_frame_usage; private: std::atomic m_textureMemUsed; diff --git a/KREngine/kraken/KRTextureAnimated.cpp b/KREngine/kraken/KRTextureAnimated.cpp index c25028a..f3e80c8 100644 --- a/KREngine/kraken/KRTextureAnimated.cpp +++ b/KREngine/kraken/KRTextureAnimated.cpp @@ -91,21 +91,20 @@ long KRTextureAnimated::getMemRequiredForSize(int max_dim) } -void KRTextureAnimated::resetPoolExpiry() +void KRTextureAnimated::resetPoolExpiry(float lodCoverage, texture_usage_t textureUsage) { - KRTexture::resetPoolExpiry(); + KRTexture::resetPoolExpiry(lodCoverage, textureUsage); for(int i=0; iresetPoolExpiry(); // Ensure that frames of animated textures do not expire from the texture pool prematurely, as they are referenced indirectly - getContext().getTextureManager()->primeTexture(frame_texture); + frame_texture->resetPoolExpiry(lodCoverage, textureUsage); // Ensure that frames of animated textures do not expire from the texture pool prematurely, as they are referenced indirectly } } } void KRTextureAnimated::bind(GLuint texture_unit) { - resetPoolExpiry(); + resetPoolExpiry(0.0f, TEXTURE_USAGE_NONE); // TODO - Need to set parameters here for streaming priority? KRTexture::bind(texture_unit); int frame_number = (int)floor(fmodf(getContext().getAbsoluteTime() * m_frame_rate,m_frame_count)); KRTexture2D *frame_texture = textureForFrame(frame_number); diff --git a/KREngine/kraken/KRTextureAnimated.h b/KREngine/kraken/KRTextureAnimated.h index 9e685b6..94ae16c 100644 --- a/KREngine/kraken/KRTextureAnimated.h +++ b/KREngine/kraken/KRTextureAnimated.h @@ -45,7 +45,7 @@ public: virtual void bind(GLuint texture_unit); virtual long getMemRequiredForSize(int max_dim); - virtual void resetPoolExpiry(); + virtual void resetPoolExpiry(float lodCoverage, texture_usage_t textureUsage); virtual long getReferencedMemSize(); diff --git a/KREngine/kraken/KRTextureCube.cpp b/KREngine/kraken/KRTextureCube.cpp index 982e6bb..3021265 100644 --- a/KREngine/kraken/KRTextureCube.cpp +++ b/KREngine/kraken/KRTextureCube.cpp @@ -115,14 +115,14 @@ long KRTextureCube::getMemRequiredForSize(int max_dim) } -void KRTextureCube::resetPoolExpiry() +void KRTextureCube::resetPoolExpiry(float lodCoverage, texture_usage_t textureUsage) { - KRTexture::resetPoolExpiry(); + KRTexture::resetPoolExpiry(lodCoverage, textureUsage); for(int i=0; i<6; i++) { std::string faceName = getName() + SUFFIXES[i]; KRTexture2D *faceTexture = (KRTexture2D *)getContext().getTextureManager()->getTexture(faceName); if(faceTexture) { - faceTexture->resetPoolExpiry(); // Ensure that side of cube maps do not expire from the texture pool prematurely, as they are referenced indirectly + faceTexture->resetPoolExpiry(lodCoverage, textureUsage); // Ensure that side of cube maps do not expire from the texture pool prematurely, as they are referenced indirectly } } } diff --git a/KREngine/kraken/KRTextureCube.h b/KREngine/kraken/KRTextureCube.h index e242147..8a0edc1 100644 --- a/KREngine/kraken/KRTextureCube.h +++ b/KREngine/kraken/KRTextureCube.h @@ -44,7 +44,7 @@ public: virtual void bind(GLuint texture_unit); virtual long getMemRequiredForSize(int max_dim); - virtual void resetPoolExpiry(); + virtual void resetPoolExpiry(float lodCoverage, texture_usage_t textureUsage); private: virtual bool createGLTexture(int lod_max_dim); diff --git a/KREngine/kraken/KRTextureManager.cpp b/KREngine/kraken/KRTextureManager.cpp index 878d254..0b1df0f 100644 --- a/KREngine/kraken/KRTextureManager.cpp +++ b/KREngine/kraken/KRTextureManager.cpp @@ -64,7 +64,7 @@ void KRTextureManager::_clearGLState() m_wrapModeS[i] = 0; m_wrapModeT[i] = 0; m_maxAnisotropy[i] = -1.0f; - selectTexture(i, NULL); + selectTexture(i, NULL, 0.0f, KRTexture::TEXTURE_USAGE_NONE); } m_iActiveTexture = -1; @@ -179,19 +179,17 @@ KRTexture *KRTextureManager::getTexture(const std::string &name) { } } -void KRTextureManager::selectTexture(int iTextureUnit, KRTexture *pTexture) { +void KRTextureManager::selectTexture(int iTextureUnit, KRTexture *pTexture, float lod_coverage, KRTexture::texture_usage_t textureUsage) { bool is_animated = false; if(pTexture) { + pTexture->resetPoolExpiry(lod_coverage, textureUsage); if(pTexture->isAnimated()) is_animated = true; } if(m_boundTextures[iTextureUnit] != pTexture || is_animated) { _setActiveTexture(iTextureUnit); if(pTexture != NULL) { - primeTexture(pTexture); - pTexture->bind(iTextureUnit); - } else { GLDEBUG(glBindTexture(GL_TEXTURE_2D, 0)); } @@ -200,14 +198,6 @@ void KRTextureManager::selectTexture(int iTextureUnit, KRTexture *pTexture) { } -void KRTextureManager::primeTexture(KRTexture *pTexture) -{ - m_poolTextures.erase(pTexture); - if(m_activeTextures.find(pTexture) == m_activeTextures.end()) { - m_activeTextures.insert(pTexture); - } -} - long KRTextureManager::getMemUsed() { return m_textureMemUsed; } @@ -234,7 +224,6 @@ void KRTextureManager::startFrame(float deltaTime) // TODO - Implement proper double-buffering to reduce copy operations m_streamerFenceMutex.lock(); m_activeTextures_streamer_copy = m_activeTextures; - m_poolTextures_streamer_copy = m_poolTextures; m_streamerFenceMutex.unlock(); m_memoryTransferredThisFrame = 0; @@ -245,7 +234,7 @@ void KRTextureManager::endFrame(float deltaTime) { for(int iTexture=0; iTexture < KRENGINE_MAX_TEXTURE_UNITS; iTexture++) { if(m_boundTextures[iTexture]) { - m_boundTextures[iTexture]->resetPoolExpiry(); // Even if the same texture is bound, ensure that they don't expire from the texture pool while in use + m_boundTextures[iTexture]->resetPoolExpiry(0.0f, KRTexture::TEXTURE_USAGE_NONE); // Even if the same texture is bound, ensure that they don't expire from the texture pool while in use } } } @@ -255,7 +244,6 @@ void KRTextureManager::doStreaming() // TODO - Implement proper double-buffering to reduce copy operations m_streamerFenceMutex.lock(); m_activeTextures_streamer = m_activeTextures_streamer_copy; - m_poolTextures_streamer = m_poolTextures_streamer_copy; m_streamerFenceMutex.unlock(); balanceTextureMemory(); @@ -269,8 +257,7 @@ void KRTextureManager::balanceTextureMemory() /* NEW ALGORITHM: - The “fixed” textures will be assigned to the skybox and the animated character flares - The rest of the textures are assigned a “weight” by tuneable criteria: + Textures are assigned a “weight” by tuneable criteria: - Area of screen coverage taken by objects containing material (more accurate and generic than distance) - Type of texture (separate weight for normal, diffuse, spec maps) - Last used time (to keep textures loaded for recently seen objects that are outside of the view frustum) @@ -280,6 +267,69 @@ void KRTextureManager::balanceTextureMemory() */ + // --------------- + + // TODO - Would this be faster with int's for weights? + std::vector> sortedTextures; + for(auto itr=m_activeTextures_streamer.begin(); itr != m_activeTextures_streamer.end(); itr++) { + KRTexture *texture = *itr; + float priority = texture->getStreamPriority(); + sortedTextures.push_back(std::pair(priority, texture)); + } + + std::sort(sortedTextures.begin(), sortedTextures.end(), std::greater>()); + + long memoryRemaining = getContext().KRENGINE_TARGET_TEXTURE_MEM_MAX; + long memoryRemainingThisFrame = KRMIN(getContext().KRENGINE_TARGET_TEXTURE_MEM_MAX - getMemUsed(), getContext().KRENGINE_TARGET_TEXTURE_MEM_MAX); + + for(auto itr=sortedTextures.begin(); itr != sortedTextures.end(); itr++) { + KRTexture *texture = (*itr).second; + int min_mip_level = KRMAX(getContext().KRENGINE_MIN_TEXTURE_DIM, texture->getMinMipMap()); + long minLodMem = texture->getMemRequiredForSize(min_mip_level); + memoryRemaining -= minLodMem; + + if(memoryRemainingThisFrame > minLodMem && texture->getCurrentLodMaxDim() < min_mip_level) { + memoryRemainingThisFrame -= minLodMem; + texture->resize(min_mip_level); + } + } + + std::vector mipPercents = {75, 75, 50, 50, 50}; + int mip_drop = -1; + auto mip_itr = mipPercents.begin(); + long memoryRemainingThisMip = 0; + + for(auto itr=sortedTextures.begin(); itr != sortedTextures.end(); itr++) { + if(memoryRemainingThisMip <= 0) { + if(mip_itr == mipPercents.end()) { + break; + } else { + memoryRemainingThisMip = memoryRemaining * (*mip_itr) / 100; + mip_drop++; + mip_itr++; + } + } + + KRTexture *texture = (*itr).second; + int min_mip_level = KRMAX(getContext().KRENGINE_MIN_TEXTURE_DIM, texture->getMinMipMap()); + int max_mip_level = KRMIN(getContext().KRENGINE_MAX_TEXTURE_DIM, texture->getMaxMipMap()); + int target_mip_level = (max_mip_level >> mip_drop); + long targetMem = texture->getMemRequiredForSize(target_mip_level); + long additionalMemRequired = targetMem - texture->getMemRequiredForSize(min_mip_level); + memoryRemainingThisMip -= additionalMemRequired; + memoryRemaining -= additionalMemRequired; + if(memoryRemainingThisMip > 0 && memoryRemainingThisFrame > targetMem) { + if(texture->getCurrentLodMaxDim() != target_mip_level) { + memoryRemainingThisFrame -= targetMem; + texture->resize(target_mip_level); + } + } + } + + + + // --------------- + /* // Determine the additional amount of memory required in order to resize all active textures to the maximum size long wantedTextureMem = 0; @@ -356,8 +406,7 @@ void KRTextureManager::balanceTextureMemory() } } } - - //fprintf(stderr, "Active mipmap size: %i Inactive mapmap size: %i\n", (int)maxDimActive, (int)maxDimInactive); + */ } void KRTextureManager::rotateBuffers() @@ -366,21 +415,16 @@ void KRTextureManager::rotateBuffers() // ----====---- Expire textures that haven't been used in a long time ----====---- std::set expiredTextures; - for(std::set::iterator itr=m_poolTextures.begin(); itr != m_poolTextures.end(); itr++) { - KRTexture *poolTexture = *itr; - if(poolTexture->getLastFrameUsed() + KRENGINE_TEXTURE_EXPIRY_FRAMES < getContext().getCurrentFrame()) { - expiredTextures.insert(poolTexture); - poolTexture->releaseHandles(); + for(std::set::iterator itr=m_activeTextures.begin(); itr != m_activeTextures.end(); itr++) { + KRTexture *activeTexture = *itr; + if(activeTexture->getLastFrameUsed() + KRENGINE_TEXTURE_EXPIRY_FRAMES < getContext().getCurrentFrame()) { + expiredTextures.insert(activeTexture); + activeTexture->releaseHandles(); } } for(std::set::iterator itr=expiredTextures.begin(); itr != expiredTextures.end(); itr++) { - m_poolTextures.erase(*itr); + m_activeTextures.erase(*itr); } - - // ----====---- Swap the buffers ----====---- - - m_poolTextures.insert(m_activeTextures.begin(), m_activeTextures.end()); - m_activeTextures.clear(); } long KRTextureManager::getMemoryTransferedThisFrame() @@ -444,8 +488,10 @@ std::set &KRTextureManager::getActiveTextures() return m_activeTextures; } -std::set &KRTextureManager::getPoolTextures() +void KRTextureManager::primeTexture(KRTexture *texture) { - return m_poolTextures; + if(m_activeTextures.find(texture) == m_activeTextures.end()) { + m_activeTextures.insert(texture); + } } diff --git a/KREngine/kraken/KRTextureManager.h b/KREngine/kraken/KRTextureManager.h index 41b4b21..46ab085 100644 --- a/KREngine/kraken/KRTextureManager.h +++ b/KREngine/kraken/KRTextureManager.h @@ -46,8 +46,7 @@ public: KRTextureManager(KRContext &context); virtual ~KRTextureManager(); - void primeTexture(KRTexture *pTexture); - void selectTexture(int iTextureUnit, KRTexture *pTexture); + void selectTexture(int iTextureUnit, KRTexture *pTexture, float lod_coverage, KRTexture::texture_usage_t textureUsage); KRTexture *loadTexture(const char *szName, const char *szExtension, KRDataBlock *data); KRTexture *getTextureCube(const char *szName); @@ -69,7 +68,6 @@ public: void compress(bool premultiply_alpha = false); std::set &getActiveTextures(); - std::set &getPoolTextures(); void _setActiveTexture(int i); void _setWrapModeS(GLuint i, GLuint wrap_mode); @@ -80,6 +78,7 @@ public: void setMaxAnisotropy(float max_anisotropy); void doStreaming(); + void primeTexture(KRTexture *texture); private: int m_iActiveTexture; @@ -95,12 +94,9 @@ private: std::set m_activeTextures; - std::set m_poolTextures; std::set m_activeTextures_streamer; - std::set m_poolTextures_streamer; std::set m_activeTextures_streamer_copy; - std::set m_poolTextures_streamer_copy; std::atomic m_textureMemUsed; diff --git a/KREngine/kraken/KRViewport.cpp b/KREngine/kraken/KRViewport.cpp index 6dbd0e9..9feab68 100644 --- a/KREngine/kraken/KRViewport.cpp +++ b/KREngine/kraken/KRViewport.cpp @@ -182,10 +182,8 @@ float KRViewport::coverage(const KRAABB &b) const for(int i=0; i<8; i++) { KRVector3 screen_pos = KRMat4::DotWDiv(m_matViewProjection, KRVector3(i & 1 ? b.min.x : b.max.x, i & 2 ? b.min.y : b.max.y, i & 4 ? b.min.z : b.max.z)); if(i==0) { - screen_min.x = screen_pos.x; - screen_min.y = screen_pos.y; - screen_max.x = screen_pos.x; - screen_max.y = screen_pos.y; + screen_min = screen_pos.xy(); + screen_max = screen_pos.xy(); } else { if(screen_pos.x < screen_min.x) screen_min.x = screen_pos.x; if(screen_pos.y < screen_min.y) screen_min.y = screen_pos.y; @@ -194,7 +192,13 @@ float KRViewport::coverage(const KRAABB &b) const } } - return (screen_max.x - screen_min.x) * (screen_max.y - screen_min.y); + screen_min.x = KRCLAMP(screen_min.x, 0.0f, 1.0f); + screen_min.y = KRCLAMP(screen_min.y, 0.0f, 1.0f); + screen_max.x = KRCLAMP(screen_max.x, 0.0f, 1.0f); + screen_max.y = KRCLAMP(screen_max.y, 0.0f, 1.0f); + + float c = (screen_max.x - screen_min.x) * (screen_max.y - screen_min.y); + return KRCLAMP(c, 0.01f, 1.0f); } }