From 9d5d269febffbece37f73029966323df3f12820a Mon Sep 17 00:00:00 2001 From: Kearwood Gilbert Date: Mon, 23 Mar 2026 22:45:51 -0700 Subject: [PATCH] Fixes for mipmap streaming system. Added KRNode::alwaysStreamResources() KRCamera now set to always stream its resources, so that the debug font texture and textures used for post-processing will always be loaded. --- kraken/nodes/KRCamera.cpp | 296 +++++++++--------- kraken/nodes/KRCamera.h | 1 + kraken/nodes/KRNode.cpp | 5 + kraken/nodes/KRNode.h | 1 + kraken/resources/scene/KRScene.cpp | 27 +- kraken/resources/scene/KRScene.h | 1 + kraken/resources/texture/KRTexture.cpp | 5 +- kraken/resources/texture/KRTexture2D.cpp | 13 +- kraken/resources/texture/KRTexture2D.h | 2 +- kraken/resources/texture/KRTextureManager.cpp | 2 +- 10 files changed, 194 insertions(+), 159 deletions(-) diff --git a/kraken/nodes/KRCamera.cpp b/kraken/nodes/KRCamera.cpp index ff1cba7..92b3822 100755 --- a/kraken/nodes/KRCamera.cpp +++ b/kraken/nodes/KRCamera.cpp @@ -479,6 +479,22 @@ void KRCamera::renderPost(RenderInfo& ri) void KRCamera::renderDebug(RenderInfo& ri) { const char* szText = settings.m_debug_text.c_str(); + if (*szText == '\0') { + if (m_debug_text_vertices.getSize() > 0) { + m_debug_text_vertices = Block(); + } + return; + } + + if (!m_fontTexture.isBound()) + { + return; + } + + KRTexture* fontTexture = m_fontTexture.get(); + if (fontTexture->getStreamLevel() == kraken_stream_level::STREAM_LEVEL_OUT) { + return; + } std::string debug_text; if (settings.debug_display != KRRenderSettings::KRENGINE_DEBUG_DISPLAY_NONE) { @@ -488,151 +504,140 @@ void KRCamera::renderDebug(RenderInfo& ri) } } - if (*szText) { - int row_count = 1; - const int MAX_TABS = 5; - const int TAB_EXTRA = 2; - int tab_cols[MAX_TABS] = { 0, 0, 0, 0, 0 }; - int iCol = 0; - int iTab = 0; - const char* pChar = szText; - while (*pChar) { - char c = *pChar++; - if (c == '\n') { - row_count++; - iCol = 0; - iTab = 0; - } else if (c == '\t') { - iCol = 0; - iTab++; - } else { - iCol++; - if (iCol > tab_cols[iTab]) tab_cols[iTab] = iCol; - } - } - - iCol = 0; - for (iTab = 0; iTab < MAX_TABS; iTab++) { - iCol += tab_cols[iTab] + TAB_EXTRA; - tab_cols[iTab] = iCol; - } - - const int DEBUG_TEXT_COLUMNS = 256; - const int DEBUG_TEXT_ROWS = 128; - - if (m_debug_text_vertices.getSize() == 0) { - m_debug_text_vertices.expand(sizeof(DebugTextVertexData) * DEBUG_TEXT_COLUMNS * DEBUG_TEXT_ROWS * 6); - } - int vertex_count = 0; - - m_debug_text_vertices.lock(); - DebugTextVertexData* vertex_data = (DebugTextVertexData*)m_debug_text_vertices.getStart(); - - pChar = szText; - float dScaleX = 2.0f / (1024.0f / 16.0f); - float dScaleY = 2.0f / (768.0f / 16.0f); - float dTexScale = 1.0f / 16.0f; - int iRow = row_count - 1; iCol = 0; iTab = 0; - while (*pChar) { - char c = *pChar++; - if (c == '\n') { - iCol = 0; - iTab = 0; - iRow--; - } else if (c == '\t') { - iCol = tab_cols[iTab++]; - } else { - if (iCol < DEBUG_TEXT_COLUMNS && iRow < DEBUG_TEXT_ROWS) { - int iChar = c - '\0'; - int iTexCol = iChar % 16; - int iTexRow = 15 - (iChar - iTexCol) / 16; - - Vector2 top_left_pos = Vector2::Create(-1.0f + dScaleX * iCol, dScaleY * iRow - 1.0f); - Vector2 bottom_right_pos = Vector2::Create(-1.0f + dScaleX * (iCol + 1), dScaleY * iRow + dScaleY - 1.0f); - top_left_pos += Vector2::Create(1.0f / 2048.0f * 0.5f, 1.0f / 1536.0f * 0.5f); - bottom_right_pos += Vector2::Create(1.0f / 2048.0f * 0.5f, 1.0f / 1536.0f * 0.5f); - Vector2 top_left_uv = Vector2::Create(dTexScale * iTexCol, dTexScale * iTexRow + dTexScale); - Vector2 bottom_right_uv = Vector2::Create(dTexScale * iTexCol + dTexScale, dTexScale * iTexRow); - - vertex_data[vertex_count].x = top_left_pos.x; - vertex_data[vertex_count].y = top_left_pos.y; - vertex_data[vertex_count].z = 0.0f; - vertex_data[vertex_count].u = top_left_uv.x; - vertex_data[vertex_count].v = top_left_uv.y; - vertex_count++; - - vertex_data[vertex_count].x = bottom_right_pos.x; - vertex_data[vertex_count].y = bottom_right_pos.y; - vertex_data[vertex_count].z = 0.0f; - vertex_data[vertex_count].u = bottom_right_uv.x; - vertex_data[vertex_count].v = bottom_right_uv.y; - vertex_count++; - - vertex_data[vertex_count].x = top_left_pos.x; - vertex_data[vertex_count].y = bottom_right_pos.y; - vertex_data[vertex_count].z = 0.0f; - vertex_data[vertex_count].u = top_left_uv.x; - vertex_data[vertex_count].v = bottom_right_uv.y; - vertex_count++; - - - vertex_data[vertex_count].x = top_left_pos.x; - vertex_data[vertex_count].y = top_left_pos.y; - vertex_data[vertex_count].z = 0.0f; - vertex_data[vertex_count].u = top_left_uv.x; - vertex_data[vertex_count].v = top_left_uv.y; - vertex_count++; - - vertex_data[vertex_count].x = bottom_right_pos.x; - vertex_data[vertex_count].y = top_left_pos.y; - vertex_data[vertex_count].z = 0.0f; - vertex_data[vertex_count].u = bottom_right_uv.x; - vertex_data[vertex_count].v = top_left_uv.y; - vertex_count++; - - vertex_data[vertex_count].x = bottom_right_pos.x; - vertex_data[vertex_count].y = bottom_right_pos.y; - vertex_data[vertex_count].z = 0.0f; - vertex_data[vertex_count].u = bottom_right_uv.x; - vertex_data[vertex_count].v = bottom_right_uv.y; - vertex_count++; - } - - iCol++; - } - } - - m_debug_text_vbo_data.load(ri.commandBuffer); - - KRTexture* fontTexture = m_fontTexture.get(); - if (fontTexture->getStreamLevel() != kraken_stream_level::STREAM_LEVEL_OUT) { - - PipelineInfo info{}; - std::string shader_name("debug_font"); - info.shader_name = &shader_name; - info.pCamera = this; - info.renderPass = ri.renderPass; - info.rasterMode = RasterMode::kAlphaBlendNoTest; - info.cullMode = CullMode::kCullNone; - info.vertexAttributes = (1 << KRMesh::KRENGINE_ATTRIB_VERTEX) | (1 << KRMesh::KRENGINE_ATTRIB_TEXUVA); - info.modelFormat = ModelFormat::KRENGINE_MODEL_FORMAT_TRIANGLES; - KRPipeline* fontShader = m_pContext->getPipelineManager()->getPipeline(*ri.surface, info); - - fontShader->setImageBinding("fontTexture", fontTexture, getContext().getSamplerManager()->DEFAULT_CLAMPED_SAMPLER); - fontShader->bind(ri, Matrix4()); - - m_debug_text_vbo_data.bind(ri.commandBuffer); - - vkCmdDraw(ri.commandBuffer, vertex_count, 1, 0, 0); - } - - m_debug_text_vertices.unlock(); - - } else { - if (m_debug_text_vertices.getSize() > 0) { - m_debug_text_vertices = Block(); + int row_count = 1; + const int MAX_TABS = 5; + const int TAB_EXTRA = 2; + int tab_cols[MAX_TABS] = { 0, 0, 0, 0, 0 }; + int iCol = 0; + int iTab = 0; + const char* pChar = szText; + while (*pChar) { + char c = *pChar++; + if (c == '\n') { + row_count++; + iCol = 0; + iTab = 0; + } else if (c == '\t') { + iCol = 0; + iTab++; + } else { + iCol++; + if (iCol > tab_cols[iTab]) tab_cols[iTab] = iCol; } } + + iCol = 0; + for (iTab = 0; iTab < MAX_TABS; iTab++) { + iCol += tab_cols[iTab] + TAB_EXTRA; + tab_cols[iTab] = iCol; + } + + const int DEBUG_TEXT_COLUMNS = 256; + const int DEBUG_TEXT_ROWS = 128; + + if (m_debug_text_vertices.getSize() == 0) { + m_debug_text_vertices.expand(sizeof(DebugTextVertexData) * DEBUG_TEXT_COLUMNS * DEBUG_TEXT_ROWS * 6); + } + int vertex_count = 0; + + m_debug_text_vertices.lock(); + DebugTextVertexData* vertex_data = (DebugTextVertexData*)m_debug_text_vertices.getStart(); + + pChar = szText; + float dScaleX = 2.0f / (1024.0f / 16.0f); + float dScaleY = 2.0f / (768.0f / 16.0f); + float dTexScale = 1.0f / 16.0f; + int iRow = row_count - 1; iCol = 0; iTab = 0; + while (*pChar) { + char c = *pChar++; + if (c == '\n') { + iCol = 0; + iTab = 0; + iRow--; + } else if (c == '\t') { + iCol = tab_cols[iTab++]; + } else { + if (iCol < DEBUG_TEXT_COLUMNS && iRow < DEBUG_TEXT_ROWS) { + int iChar = c - '\0'; + int iTexCol = iChar % 16; + int iTexRow = 15 - (iChar - iTexCol) / 16; + + Vector2 top_left_pos = Vector2::Create(-1.0f + dScaleX * iCol, dScaleY * iRow - 1.0f); + Vector2 bottom_right_pos = Vector2::Create(-1.0f + dScaleX * (iCol + 1), dScaleY * iRow + dScaleY - 1.0f); + top_left_pos += Vector2::Create(1.0f / 2048.0f * 0.5f, 1.0f / 1536.0f * 0.5f); + bottom_right_pos += Vector2::Create(1.0f / 2048.0f * 0.5f, 1.0f / 1536.0f * 0.5f); + Vector2 top_left_uv = Vector2::Create(dTexScale * iTexCol, dTexScale * iTexRow + dTexScale); + Vector2 bottom_right_uv = Vector2::Create(dTexScale * iTexCol + dTexScale, dTexScale * iTexRow); + + vertex_data[vertex_count].x = top_left_pos.x; + vertex_data[vertex_count].y = top_left_pos.y; + vertex_data[vertex_count].z = 0.0f; + vertex_data[vertex_count].u = top_left_uv.x; + vertex_data[vertex_count].v = top_left_uv.y; + vertex_count++; + + vertex_data[vertex_count].x = bottom_right_pos.x; + vertex_data[vertex_count].y = bottom_right_pos.y; + vertex_data[vertex_count].z = 0.0f; + vertex_data[vertex_count].u = bottom_right_uv.x; + vertex_data[vertex_count].v = bottom_right_uv.y; + vertex_count++; + + vertex_data[vertex_count].x = top_left_pos.x; + vertex_data[vertex_count].y = bottom_right_pos.y; + vertex_data[vertex_count].z = 0.0f; + vertex_data[vertex_count].u = top_left_uv.x; + vertex_data[vertex_count].v = bottom_right_uv.y; + vertex_count++; + + + vertex_data[vertex_count].x = top_left_pos.x; + vertex_data[vertex_count].y = top_left_pos.y; + vertex_data[vertex_count].z = 0.0f; + vertex_data[vertex_count].u = top_left_uv.x; + vertex_data[vertex_count].v = top_left_uv.y; + vertex_count++; + + vertex_data[vertex_count].x = bottom_right_pos.x; + vertex_data[vertex_count].y = top_left_pos.y; + vertex_data[vertex_count].z = 0.0f; + vertex_data[vertex_count].u = bottom_right_uv.x; + vertex_data[vertex_count].v = top_left_uv.y; + vertex_count++; + + vertex_data[vertex_count].x = bottom_right_pos.x; + vertex_data[vertex_count].y = bottom_right_pos.y; + vertex_data[vertex_count].z = 0.0f; + vertex_data[vertex_count].u = bottom_right_uv.x; + vertex_data[vertex_count].v = bottom_right_uv.y; + vertex_count++; + } + + iCol++; + } + } + + m_debug_text_vbo_data.load(ri.commandBuffer); + + PipelineInfo info{}; + std::string shader_name("debug_font"); + info.shader_name = &shader_name; + info.pCamera = this; + info.renderPass = ri.renderPass; + info.rasterMode = RasterMode::kAlphaBlendNoTest; + info.cullMode = CullMode::kCullNone; + info.vertexAttributes = (1 << KRMesh::KRENGINE_ATTRIB_VERTEX) | (1 << KRMesh::KRENGINE_ATTRIB_TEXUVA); + info.modelFormat = ModelFormat::KRENGINE_MODEL_FORMAT_TRIANGLES; + KRPipeline* fontShader = m_pContext->getPipelineManager()->getPipeline(*ri.surface, info); + + fontShader->setImageBinding("fontTexture", fontTexture, getContext().getSamplerManager()->DEFAULT_CLAMPED_SAMPLER); + fontShader->bind(ri, Matrix4()); + + m_debug_text_vbo_data.bind(ri.commandBuffer); + + vkCmdDraw(ri.commandBuffer, vertex_count, 1, 0, 0); + + m_debug_text_vertices.unlock(); } @@ -853,3 +858,8 @@ bool KRCamera::getShaderValue(ShaderValue value, hydra::Vector4* output) const return KRNode::getShaderValue(value, output); } + +bool KRCamera::alwaysStreamResources() +{ + return true; +} \ No newline at end of file diff --git a/kraken/nodes/KRCamera.h b/kraken/nodes/KRCamera.h index ecdf7e1..db6a5e9 100755 --- a/kraken/nodes/KRCamera.h +++ b/kraken/nodes/KRCamera.h @@ -63,6 +63,7 @@ public: void getResourceBindings(std::list& bindings) final; void render(KRNode::RenderInfo& ri) final; + bool alwaysStreamResources() override; KRRenderSettings settings; diff --git a/kraken/nodes/KRNode.cpp b/kraken/nodes/KRNode.cpp index 9060776..6826e85 100755 --- a/kraken/nodes/KRNode.cpp +++ b/kraken/nodes/KRNode.cpp @@ -671,6 +671,11 @@ void KRNode::getResourceBindings(std::list& bindings) } +bool KRNode::alwaysStreamResources() +{ + return false; +} + void KRNode::render(RenderInfo& ri) { m_lastRenderFrame = getContext().getCurrentFrame(); diff --git a/kraken/nodes/KRNode.h b/kraken/nodes/KRNode.h index 5d2f96f..3ecaa66 100755 --- a/kraken/nodes/KRNode.h +++ b/kraken/nodes/KRNode.h @@ -240,6 +240,7 @@ public: virtual void preStream(const KRViewport& viewport, std::list& resourceRequests); virtual void getResourceBindings(std::list& bindings); + virtual bool alwaysStreamResources(); virtual void render(RenderInfo& ri); virtual void physicsUpdate(float deltaTime); diff --git a/kraken/resources/scene/KRScene.cpp b/kraken/resources/scene/KRScene.cpp index e674cc1..8f98058 100755 --- a/kraken/resources/scene/KRScene.cpp +++ b/kraken/resources/scene/KRScene.cpp @@ -145,6 +145,12 @@ void KRScene::render(KRNode::RenderInfo& ri) } } + // Stream assets for nodes that request having their assets always streamed in. + for (std::set::iterator itr = m_alwaysStreamedNodes.begin(); itr != m_alwaysStreamedNodes.end(); itr++) { + KRNode* node = (*itr); + node->preStream(*ri.viewport, resourceRequests); + } + std::vector remainingOctrees; if (m_nodeTree.getRootNode() != NULL) { remainingOctrees.push_back(m_nodeTree.getRootNode()); @@ -204,16 +210,17 @@ void KRScene::render(KRNode::RenderInfo& ri, std::list& resou // Render objects that are at this octree level for (std::set::iterator itr = pOctreeNode->getSceneNodes().begin(); itr != pOctreeNode->getSceneNodes().end(); itr++) { + KRNode* node = (*itr); //assert(pOctreeNode->getBounds().contains((*itr)->getBounds())); // Sanity check if (ri.renderPass->getType() == RenderPassType::RENDER_PASS_PRESTREAM) { - if ((*itr)->getLODVisibility() >= KRNode::LOD_VISIBILITY_PRESTREAM) { - (*itr)->preStream(*ri.viewport, resourceRequests); + if (node->getLODVisibility() >= KRNode::LOD_VISIBILITY_PRESTREAM) { + node->preStream(*ri.viewport, resourceRequests); } } else { - if ((*itr)->getLODVisibility() > KRNode::LOD_VISIBILITY_PRESTREAM) + if (node->getLODVisibility() > KRNode::LOD_VISIBILITY_PRESTREAM) { ri.reflectedObjects.push_back(*itr); - (*itr)->render(ri); + node->render(ri); ri.reflectedObjects.pop_back(); } } @@ -313,6 +320,9 @@ void KRScene::notify_sceneGraphDelete(KRNode* pNode) { m_nodeTree.remove(pNode); m_physicsNodes.erase(pNode); + if (pNode->alwaysStreamResources()) { + m_alwaysStreamedNodes.erase(pNode); + } KRAmbientZone* AmbientZoneNode = dynamic_cast(pNode); if (AmbientZoneNode) { m_ambientZoneNodes.erase(AmbientZoneNode); @@ -351,6 +361,9 @@ void KRScene::updateOctree(const KRViewport& viewport) if (node->hasPhysics()) { m_physicsNodes.insert(node); } + if (node->alwaysStreamResources()) { + m_alwaysStreamedNodes.insert(node); + } KRAmbientZone* ambientZoneNode = dynamic_cast(node); if (ambientZoneNode) { m_ambientZoneNodes.insert(ambientZoneNode); @@ -378,6 +391,12 @@ void KRScene::updateOctree(const KRViewport& viewport) } else if (!node->hasPhysics()) { m_physicsNodes.erase(node); } + + if (node->alwaysStreamResources()) { + m_alwaysStreamedNodes.insert(node); + } else { + m_alwaysStreamedNodes.erase(node); + } } } diff --git a/kraken/resources/scene/KRScene.h b/kraken/resources/scene/KRScene.h index fccb867..e3c6d72 100755 --- a/kraken/resources/scene/KRScene.h +++ b/kraken/resources/scene/KRScene.h @@ -108,6 +108,7 @@ private: std::set m_reverbZoneNodes; std::set m_locatorNodes; std::set m_lights; + std::set m_alwaysStreamedNodes; KROctree m_nodeTree; diff --git a/kraken/resources/texture/KRTexture.cpp b/kraken/resources/texture/KRTexture.cpp index 994f10a..21fc0a0 100755 --- a/kraken/resources/texture/KRTexture.cpp +++ b/kraken/resources/texture/KRTexture.cpp @@ -122,7 +122,7 @@ void KRTexture::resize(int lod) if (!m_haveNewHandles) { if (lod != -1) { - int target_lod = KRMIN(lod, m_lod_count); + int target_lod = KRMIN(lod, m_lod_count - 1); if (m_new_lod != target_lod || m_handles.empty()) { assert(m_newTextureMemUsed == 0); @@ -340,8 +340,7 @@ long KRTexture::getMemRequiredForLodRange(int min_lod, int max_lod /* = 0xff */) long memRequired = 0; for (int lod = target_min_lod; lod <= target_max_lod; lod++) { - memRequired += - (lod); + memRequired += getMemRequiredForLod(lod); } return memRequired; } diff --git a/kraken/resources/texture/KRTexture2D.cpp b/kraken/resources/texture/KRTexture2D.cpp index 9ab169d..f66cf5f 100755 --- a/kraken/resources/texture/KRTexture2D.cpp +++ b/kraken/resources/texture/KRTexture2D.cpp @@ -46,23 +46,22 @@ KRTexture2D::~KRTexture2D() delete m_pData; } -bool KRTexture2D::createGPUTexture(int lod) +bool KRTexture2D::createGPUTexture(int targetLod) { if (m_haveNewHandles) { return true; } Vector3i dimensions = getDimensions(); - size_t bufferSize = getMemRequiredForLodRange(lod); + size_t bufferSize = getMemRequiredForLodRange(targetLod); void* buffer = malloc(bufferSize); - if (!getLodData(buffer, lod)) { + if (!getLodData(buffer, targetLod)) { delete buffer; return false; } bool success = true; - int target_lod = m_new_lod; m_new_lod = -1; KRDeviceManager* deviceManager = getContext().getDeviceManager(); @@ -76,7 +75,7 @@ bool KRTexture2D::createGPUTexture(int lod) texture.allocation = VK_NULL_HANDLE; texture.image = VK_NULL_HANDLE; - if (!allocate(device, target_lod, 0, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, &texture.image, &texture.allocation + if (!allocate(device, targetLod, 0, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, &texture.image, &texture.allocation #if KRENGINE_DEBUG_GPU_LABELS , getName().c_str() #endif @@ -85,7 +84,7 @@ bool KRTexture2D::createGPUTexture(int lod) break; } - int min_mip = KRMIN(target_lod, m_lod_count - 1); + int min_mip = KRMIN(targetLod, m_lod_count - 1); int mip_count = m_lod_count - min_mip; VkImageViewCreateInfo viewInfo{}; @@ -135,7 +134,7 @@ bool KRTexture2D::createGPUTexture(int lod) delete buffer; if (success) { - m_new_lod = target_lod; + m_new_lod = targetLod; m_haveNewHandles = true; } else { destroyNewHandles(); diff --git a/kraken/resources/texture/KRTexture2D.h b/kraken/resources/texture/KRTexture2D.h index cd77184..7751d99 100755 --- a/kraken/resources/texture/KRTexture2D.h +++ b/kraken/resources/texture/KRTexture2D.h @@ -53,5 +53,5 @@ public: protected: mimir::Block* m_pData; - bool createGPUTexture(int lod) override; + bool createGPUTexture(int targetLod) override; }; diff --git a/kraken/resources/texture/KRTextureManager.cpp b/kraken/resources/texture/KRTextureManager.cpp index db67086..34dba82 100755 --- a/kraken/resources/texture/KRTextureManager.cpp +++ b/kraken/resources/texture/KRTextureManager.cpp @@ -302,7 +302,7 @@ void KRTextureManager::balanceTextureMemory(long& memoryRemaining, long& memoryR for (auto itr = m_activeTextures_streamer.begin(); itr != m_activeTextures_streamer.end(); itr++) { KRTexture* texture = (*itr).second; - int min_lod_level = KRMIN(getContext().KRENGINE_TEXTURE_LQ_LOD, texture->getLodCount()); + int min_lod_level = KRMIN(getContext().KRENGINE_TEXTURE_LQ_LOD, texture->getLodCount() - 1); long minLodMem = texture->getMemRequiredForLodRange(min_lod_level); memoryRemaining -= minLodMem;