ADD: Bounding, Some error
This commit is contained in:
@@ -131,20 +131,20 @@ std::shared_ptr<MeshAsset> AssetManager::createMesh(const MeshCreateInfo &info)
|
||||
|
||||
switch (info.geometry.type)
|
||||
{
|
||||
case MeshGeometryDesc::Type::Provided:
|
||||
vertsSpan = info.geometry.vertices;
|
||||
indsSpan = info.geometry.indices;
|
||||
break;
|
||||
case MeshGeometryDesc::Type::Cube:
|
||||
primitives::buildCube(tmpVerts, tmpInds);
|
||||
vertsSpan = tmpVerts;
|
||||
indsSpan = tmpInds;
|
||||
break;
|
||||
case MeshGeometryDesc::Type::Sphere:
|
||||
primitives::buildSphere(tmpVerts, tmpInds, info.geometry.sectors, info.geometry.stacks);
|
||||
vertsSpan = tmpVerts;
|
||||
indsSpan = tmpInds;
|
||||
break;
|
||||
case MeshGeometryDesc::Type::Provided:
|
||||
vertsSpan = info.geometry.vertices;
|
||||
indsSpan = info.geometry.indices;
|
||||
break;
|
||||
case MeshGeometryDesc::Type::Cube:
|
||||
primitives::buildCube(tmpVerts, tmpInds);
|
||||
vertsSpan = tmpVerts;
|
||||
indsSpan = tmpInds;
|
||||
break;
|
||||
case MeshGeometryDesc::Type::Sphere:
|
||||
primitives::buildSphere(tmpVerts, tmpInds, info.geometry.sectors, info.geometry.stacks);
|
||||
vertsSpan = tmpVerts;
|
||||
indsSpan = tmpInds;
|
||||
break;
|
||||
}
|
||||
|
||||
// Ensure tangents exist for primitives (and provided geometry if needed)
|
||||
@@ -153,80 +153,112 @@ std::shared_ptr<MeshAsset> AssetManager::createMesh(const MeshCreateInfo &info)
|
||||
geom::generate_tangents(tmpVerts, tmpInds);
|
||||
}
|
||||
|
||||
std::shared_ptr<MeshAsset> mesh;
|
||||
|
||||
if (info.material.kind == MeshMaterialDesc::Kind::Default)
|
||||
{
|
||||
return createMesh(info.name, vertsSpan, indsSpan, {});
|
||||
mesh = createMesh(info.name, vertsSpan, indsSpan, {});
|
||||
}
|
||||
|
||||
const auto &opt = info.material.options;
|
||||
|
||||
// Fallbacks are bound now; real textures will patch in via TextureCache
|
||||
AllocatedBuffer matBuffer = createMaterialBufferWithConstants(opt.constants);
|
||||
|
||||
GLTFMetallic_Roughness::MaterialResources res{};
|
||||
res.colorImage = _engine->_errorCheckerboardImage; // visible fallback for albedo
|
||||
res.colorSampler = _engine->_samplerManager->defaultLinear();
|
||||
res.metalRoughImage = _engine->_whiteImage;
|
||||
res.metalRoughSampler = _engine->_samplerManager->defaultLinear();
|
||||
res.normalImage = _engine->_flatNormalImage;
|
||||
res.normalSampler = _engine->_samplerManager->defaultLinear();
|
||||
res.dataBuffer = matBuffer.buffer;
|
||||
res.dataBufferOffset = 0;
|
||||
|
||||
auto mat = createMaterial(opt.pass, res);
|
||||
|
||||
// Register dynamic texture bindings using the central TextureCache
|
||||
if (_engine && _engine->_context && _engine->_context->textures)
|
||||
else
|
||||
{
|
||||
TextureCache *cache = _engine->_context->textures;
|
||||
auto buildKey = [&](std::string_view path, bool srgb) -> TextureCache::TextureKey {
|
||||
TextureCache::TextureKey k{};
|
||||
if (!path.empty())
|
||||
{
|
||||
k.kind = TextureCache::TextureKey::SourceKind::FilePath;
|
||||
k.path = assetPath(path);
|
||||
k.srgb = srgb;
|
||||
k.mipmapped = true;
|
||||
std::string id = std::string("PRIM:") + k.path + (srgb ? "#sRGB" : "#UNORM");
|
||||
k.hash = texcache::fnv1a64(id);
|
||||
}
|
||||
return k;
|
||||
};
|
||||
const auto &opt = info.material.options;
|
||||
|
||||
if (!opt.albedoPath.empty())
|
||||
// Fallbacks are bound now; real textures will patch in via TextureCache
|
||||
AllocatedBuffer matBuffer = createMaterialBufferWithConstants(opt.constants);
|
||||
|
||||
GLTFMetallic_Roughness::MaterialResources res{};
|
||||
res.colorImage = _engine->_errorCheckerboardImage; // visible fallback for albedo
|
||||
res.colorSampler = _engine->_samplerManager->defaultLinear();
|
||||
res.metalRoughImage = _engine->_whiteImage;
|
||||
res.metalRoughSampler = _engine->_samplerManager->defaultLinear();
|
||||
res.normalImage = _engine->_flatNormalImage;
|
||||
res.normalSampler = _engine->_samplerManager->defaultLinear();
|
||||
res.dataBuffer = matBuffer.buffer;
|
||||
res.dataBufferOffset = 0;
|
||||
|
||||
auto mat = createMaterial(opt.pass, res);
|
||||
|
||||
// Register dynamic texture bindings using the central TextureCache
|
||||
if (_engine && _engine->_context && _engine->_context->textures)
|
||||
{
|
||||
auto key = buildKey(opt.albedoPath, opt.albedoSRGB);
|
||||
if (key.hash != 0)
|
||||
TextureCache *cache = _engine->_context->textures;
|
||||
auto buildKey = [&](std::string_view path, bool srgb) -> TextureCache::TextureKey {
|
||||
TextureCache::TextureKey k{};
|
||||
if (!path.empty())
|
||||
{
|
||||
k.kind = TextureCache::TextureKey::SourceKind::FilePath;
|
||||
k.path = assetPath(path);
|
||||
k.srgb = srgb;
|
||||
k.mipmapped = true;
|
||||
std::string id = std::string("PRIM:") + k.path + (srgb ? "#sRGB" : "#UNORM");
|
||||
k.hash = texcache::fnv1a64(id);
|
||||
}
|
||||
return k;
|
||||
};
|
||||
|
||||
if (!opt.albedoPath.empty())
|
||||
{
|
||||
VkSampler samp = _engine->_samplerManager->defaultLinear();
|
||||
auto handle = cache->request(key, samp);
|
||||
cache->watchBinding(handle, mat->data.materialSet, 1u, samp, _engine->_errorCheckerboardImage.imageView);
|
||||
auto key = buildKey(opt.albedoPath, opt.albedoSRGB);
|
||||
if (key.hash != 0)
|
||||
{
|
||||
VkSampler samp = _engine->_samplerManager->defaultLinear();
|
||||
auto handle = cache->request(key, samp);
|
||||
cache->watchBinding(handle, mat->data.materialSet, 1u, samp, _engine->_errorCheckerboardImage.imageView);
|
||||
}
|
||||
}
|
||||
if (!opt.metalRoughPath.empty())
|
||||
{
|
||||
auto key = buildKey(opt.metalRoughPath, opt.metalRoughSRGB);
|
||||
if (key.hash != 0)
|
||||
{
|
||||
VkSampler samp = _engine->_samplerManager->defaultLinear();
|
||||
auto handle = cache->request(key, samp);
|
||||
cache->watchBinding(handle, mat->data.materialSet, 2u, samp, _engine->_whiteImage.imageView);
|
||||
}
|
||||
}
|
||||
if (!opt.normalPath.empty())
|
||||
{
|
||||
auto key = buildKey(opt.normalPath, opt.normalSRGB);
|
||||
if (key.hash != 0)
|
||||
{
|
||||
VkSampler samp = _engine->_samplerManager->defaultLinear();
|
||||
auto handle = cache->request(key, samp);
|
||||
cache->watchBinding(handle, mat->data.materialSet, 3u, samp, _engine->_flatNormalImage.imageView);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!opt.metalRoughPath.empty())
|
||||
|
||||
mesh = createMesh(info.name, vertsSpan, indsSpan, mat);
|
||||
_meshMaterialBuffers.emplace(info.name, matBuffer);
|
||||
}
|
||||
|
||||
if (!mesh)
|
||||
{
|
||||
return {};
|
||||
}
|
||||
|
||||
// Tag primitive meshes with more appropriate default bounds types for picking,
|
||||
// then apply any explicit override from MeshCreateInfo.
|
||||
for (auto &surf : mesh->surfaces)
|
||||
{
|
||||
switch (info.geometry.type)
|
||||
{
|
||||
auto key = buildKey(opt.metalRoughPath, opt.metalRoughSRGB);
|
||||
if (key.hash != 0)
|
||||
{
|
||||
VkSampler samp = _engine->_samplerManager->defaultLinear();
|
||||
auto handle = cache->request(key, samp);
|
||||
cache->watchBinding(handle, mat->data.materialSet, 2u, samp, _engine->_whiteImage.imageView);
|
||||
}
|
||||
case MeshGeometryDesc::Type::Sphere:
|
||||
surf.bounds.type = BoundsType::Sphere;
|
||||
break;
|
||||
case MeshGeometryDesc::Type::Cube:
|
||||
case MeshGeometryDesc::Type::Provided:
|
||||
default:
|
||||
surf.bounds.type = BoundsType::Box;
|
||||
break;
|
||||
}
|
||||
if (!opt.normalPath.empty())
|
||||
|
||||
if (info.boundsType.has_value())
|
||||
{
|
||||
auto key = buildKey(opt.normalPath, opt.normalSRGB);
|
||||
if (key.hash != 0)
|
||||
{
|
||||
VkSampler samp = _engine->_samplerManager->defaultLinear();
|
||||
auto handle = cache->request(key, samp);
|
||||
cache->watchBinding(handle, mat->data.materialSet, 3u, samp, _engine->_flatNormalImage.imageView);
|
||||
}
|
||||
surf.bounds.type = *info.boundsType;
|
||||
}
|
||||
}
|
||||
|
||||
auto mesh = createMesh(info.name, vertsSpan, indsSpan, mat);
|
||||
_meshMaterialBuffers.emplace(info.name, matBuffer);
|
||||
return mesh;
|
||||
}
|
||||
|
||||
@@ -348,6 +380,7 @@ static Bounds compute_bounds(std::span<Vertex> vertices)
|
||||
b.origin = glm::vec3(0.0f);
|
||||
b.extents = glm::vec3(0.5f);
|
||||
b.sphereRadius = glm::length(b.extents);
|
||||
b.type = BoundsType::Box;
|
||||
return b;
|
||||
}
|
||||
glm::vec3 minpos = vertices[0].position;
|
||||
@@ -360,6 +393,7 @@ static Bounds compute_bounds(std::span<Vertex> vertices)
|
||||
b.origin = (maxpos + minpos) / 2.f;
|
||||
b.extents = (maxpos - minpos) / 2.f;
|
||||
b.sphereRadius = glm::length(b.extents);
|
||||
b.type = BoundsType::Box;
|
||||
return b;
|
||||
}
|
||||
|
||||
|
||||
@@ -62,6 +62,9 @@ public:
|
||||
std::string name;
|
||||
MeshGeometryDesc geometry;
|
||||
MeshMaterialDesc material;
|
||||
// Optional override for collision / picking bounds type for this mesh.
|
||||
// When unset, a reasonable default is chosen based on geometry.type.
|
||||
std::optional<BoundsType> boundsType;
|
||||
};
|
||||
|
||||
void init(VulkanEngine *engine);
|
||||
|
||||
@@ -49,8 +49,6 @@
|
||||
#include "core/texture_cache.h"
|
||||
#include "core/ibl_manager.h"
|
||||
|
||||
// Query a conservative streaming texture budget based on VMA-reported
|
||||
// device-local heap budgets. Uses ~35% of total device-local budget.
|
||||
static size_t query_texture_budget_bytes(DeviceManager* dev)
|
||||
{
|
||||
if (!dev) return 512ull * 1024ull * 1024ull; // fallback
|
||||
@@ -90,6 +88,7 @@ static size_t query_texture_budget_bytes(DeviceManager* dev)
|
||||
//
|
||||
// ImGui helpers: keep UI code tidy and grouped in small functions.
|
||||
// These render inside a single consolidated Debug window using tab items.
|
||||
// (Original definitions are now compiled out; see core/vk_engine_ui.cpp.)
|
||||
//
|
||||
namespace {
|
||||
// Background / compute playground
|
||||
@@ -142,7 +141,7 @@ namespace {
|
||||
|
||||
const glm::vec3 pos = origin + glm::vec3(ix*spacing, 0.5f, iy*spacing);
|
||||
glm::mat4 M = glm::translate(glm::mat4(1.0f), pos);
|
||||
eng->_sceneManager->addMeshInstance(base+".inst", mesh, M);
|
||||
eng->_sceneManager->addMeshInstance(base+".inst", mesh, M, BoundsType::Sphere);
|
||||
eng->_iblTestNames.push_back(base+".inst");
|
||||
eng->_iblTestNames.push_back(base+".mesh");
|
||||
eng->_iblTestNames.push_back(base+".mat");
|
||||
@@ -156,7 +155,7 @@ namespace {
|
||||
auto mesh = eng->_assetManager->createMesh("ibltest.chrome.mesh", std::span<Vertex>(verts.data(), verts.size()),
|
||||
std::span<uint32_t>(inds.data(), inds.size()), mat);
|
||||
glm::mat4 M = glm::translate(glm::mat4(1.0f), origin + glm::vec3(5.5f, 0.5f, 0.0f));
|
||||
eng->_sceneManager->addMeshInstance("ibltest.chrome.inst", mesh, M);
|
||||
eng->_sceneManager->addMeshInstance("ibltest.chrome.inst", mesh, M, BoundsType::Sphere);
|
||||
eng->_iblTestNames.insert(eng->_iblTestNames.end(), {"ibltest.chrome.inst","ibltest.chrome.mesh","ibltest.chrome.mat"});
|
||||
}
|
||||
{
|
||||
@@ -165,7 +164,7 @@ namespace {
|
||||
auto mesh = eng->_assetManager->createMesh("ibltest.glass.mesh", std::span<Vertex>(verts.data(), verts.size()),
|
||||
std::span<uint32_t>(inds.data(), inds.size()), mat);
|
||||
glm::mat4 M = glm::translate(glm::mat4(1.0f), origin + glm::vec3(5.5f, 0.5f, 2.0f));
|
||||
eng->_sceneManager->addMeshInstance("ibltest.glass.inst", mesh, M);
|
||||
eng->_sceneManager->addMeshInstance("ibltest.glass.inst", mesh, M, BoundsType::Sphere);
|
||||
eng->_iblTestNames.insert(eng->_iblTestNames.end(), {"ibltest.glass.inst","ibltest.glass.mesh","ibltest.glass.mat"});
|
||||
}
|
||||
}
|
||||
@@ -619,6 +618,43 @@ static void dump_vma_json(DeviceManager* dev, const char* tag)
|
||||
}
|
||||
}
|
||||
|
||||
size_t VulkanEngine::query_texture_budget_bytes() const
|
||||
{
|
||||
DeviceManager *dev = _deviceManager.get();
|
||||
if (!dev) return 512ull * 1024ull * 1024ull; // fallback
|
||||
VmaAllocator alloc = dev->allocator();
|
||||
if (!alloc) return 512ull * 1024ull * 1024ull;
|
||||
|
||||
const VkPhysicalDeviceMemoryProperties *memProps = nullptr;
|
||||
vmaGetMemoryProperties(alloc, &memProps);
|
||||
if (!memProps) return 512ull * 1024ull * 1024ull;
|
||||
|
||||
VmaBudget budgets[VK_MAX_MEMORY_HEAPS] = {};
|
||||
vmaGetHeapBudgets(alloc, budgets);
|
||||
|
||||
unsigned long long totalBudget = 0;
|
||||
unsigned long long totalUsage = 0;
|
||||
for (uint32_t i = 0; i < memProps->memoryHeapCount; ++i)
|
||||
{
|
||||
if (memProps->memoryHeaps[i].flags & VK_MEMORY_HEAP_DEVICE_LOCAL_BIT)
|
||||
{
|
||||
totalBudget += budgets[i].budget;
|
||||
totalUsage += budgets[i].usage;
|
||||
}
|
||||
}
|
||||
if (totalBudget == 0) return 512ull * 1024ull * 1024ull;
|
||||
|
||||
// Reserve ~65% of VRAM for attachments, swapchain, meshes, AS, etc.
|
||||
unsigned long long cap = static_cast<unsigned long long>(double(totalBudget) * 0.35);
|
||||
|
||||
// If usage is already near the cap, still allow current textures to live; eviction will trim.
|
||||
// Clamp to at least 128 MB, at most totalBudget.
|
||||
unsigned long long minCap = 128ull * 1024ull * 1024ull;
|
||||
if (cap < minCap) cap = minCap;
|
||||
if (cap > totalBudget) cap = totalBudget;
|
||||
return static_cast<size_t>(cap);
|
||||
}
|
||||
|
||||
void VulkanEngine::init()
|
||||
{
|
||||
// We initialize SDL and create a window with it.
|
||||
@@ -814,7 +850,8 @@ void VulkanEngine::init_default_data()
|
||||
_sceneManager->addMeshInstance("default.cube", cubeMesh,
|
||||
glm::translate(glm::mat4(1.f), glm::vec3(-2.f, 0.f, -2.f)));
|
||||
_sceneManager->addMeshInstance("default.sphere", sphereMesh,
|
||||
glm::translate(glm::mat4(1.f), glm::vec3(2.f, 0.f, -2.f)));
|
||||
glm::translate(glm::mat4(1.f), glm::vec3(2.f, 0.f, -2.f)),
|
||||
BoundsType::Sphere);
|
||||
}
|
||||
|
||||
_mainDeletionQueue.push_function([&]() {
|
||||
@@ -1069,7 +1106,7 @@ void VulkanEngine::draw()
|
||||
// Prior to building passes, pump texture loads for this frame.
|
||||
if (_textureCache)
|
||||
{
|
||||
size_t budget = query_texture_budget_bytes(_deviceManager.get());
|
||||
size_t budget = query_texture_budget_bytes();
|
||||
_textureCache->set_gpu_budget_bytes(budget);
|
||||
_textureCache->evictToBudget(budget);
|
||||
_textureCache->pumpLoads(*_resourceManager, get_current_frame());
|
||||
@@ -1375,8 +1412,8 @@ void VulkanEngine::run()
|
||||
if (ImGui::Begin("Debug"))
|
||||
{
|
||||
const ImGuiTabBarFlags tf = ImGuiTabBarFlags_Reorderable | ImGuiTabBarFlags_AutoSelectNewTabs;
|
||||
if (ImGui::BeginTabBar("DebugTabs", tf))
|
||||
{
|
||||
if (ImGui::BeginTabBar("DebugTabs", tf))
|
||||
{
|
||||
if (ImGui::BeginTabItem("Overview"))
|
||||
{
|
||||
ui_overview(this);
|
||||
@@ -1412,20 +1449,21 @@ void VulkanEngine::run()
|
||||
ui_postfx(this);
|
||||
ImGui::EndTabItem();
|
||||
}
|
||||
if (ImGui::BeginTabItem("Scene"))
|
||||
{
|
||||
ui_scene(this);
|
||||
ImGui::EndTabItem();
|
||||
if (ImGui::BeginTabItem("Scene"))
|
||||
{
|
||||
ui_scene(this);
|
||||
ImGui::EndTabItem();
|
||||
}
|
||||
if (ImGui::BeginTabItem("Textures"))
|
||||
{
|
||||
ui_textures(this);
|
||||
ImGui::EndTabItem();
|
||||
}
|
||||
ImGui::EndTabBar();
|
||||
}
|
||||
if (ImGui::BeginTabItem("Textures"))
|
||||
{
|
||||
ui_textures(this);
|
||||
ImGui::EndTabItem();
|
||||
}
|
||||
ImGui::EndTabBar();
|
||||
}
|
||||
ImGui::End();
|
||||
}
|
||||
|
||||
ImGui::Render();
|
||||
draw();
|
||||
|
||||
|
||||
@@ -167,6 +167,9 @@ public:
|
||||
//run main loop
|
||||
void run();
|
||||
|
||||
// Query a conservative streaming texture budget for the texture cache.
|
||||
size_t query_texture_budget_bytes() const;
|
||||
|
||||
bool resize_requested{false};
|
||||
bool freeze_rendering{false};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user