EDIT: IBL async

This commit is contained in:
2025-12-07 00:26:55 +09:00
parent ba89f5aa2c
commit f95520dcb1
7 changed files with 725 additions and 283 deletions

View File

@@ -250,7 +250,7 @@ void VulkanEngine::init()
// Publish to context for passes and pipeline layout assembly
_context->ibl = _iblManager.get();
// Try to load default IBL assets if present
// Try to load default IBL assets if present (async)
{
IBLPaths ibl{};
ibl.specularCube = _assetManager->assetPath("ibl/docklands.ktx2");
@@ -262,13 +262,21 @@ void VulkanEngine::init()
// Treat this as the global/fallback IBL used outside any local volume.
_globalIBLPaths = ibl;
_activeIBLVolume = -1;
bool ibl_ok = _iblManager->load(ibl);
_hasGlobalIBL = ibl_ok;
if (!ibl_ok)
_hasGlobalIBL = false;
if (_iblManager)
{
fmt::println("[Engine] Warning: failed to load default IBL (specular='{}', brdfLut='{}'). IBL lighting will be disabled until a valid IBL is loaded.",
ibl.specularCube,
ibl.brdfLut2D);
if (_iblManager->load_async(ibl))
{
_pendingIBLRequest.active = true;
_pendingIBLRequest.targetVolume = -1;
_pendingIBLRequest.paths = ibl;
}
else
{
fmt::println("[Engine] Warning: failed to enqueue default IBL load (specular='{}', brdfLut='{}'). IBL lighting will be disabled until a valid IBL is loaded.",
ibl.specularCube,
ibl.brdfLut2D);
}
}
}
@@ -436,6 +444,56 @@ bool VulkanEngine::addGLTFInstance(const std::string &instanceName,
return true;
}
bool VulkanEngine::addPrimitiveInstance(const std::string &instanceName,
AssetManager::MeshGeometryDesc::Type geomType,
const glm::mat4 &transform,
const AssetManager::MeshMaterialDesc &material,
std::optional<BoundsType> boundsTypeOverride)
{
if (!_assetManager || !_sceneManager)
{
return false;
}
// Build a cache key for the primitive mesh so multiple instances
// share the same GPU buffers.
std::string meshName;
switch (geomType)
{
case AssetManager::MeshGeometryDesc::Type::Cube:
meshName = "Primitive.Cube";
break;
case AssetManager::MeshGeometryDesc::Type::Sphere:
meshName = "Primitive.Sphere";
break;
case AssetManager::MeshGeometryDesc::Type::Plane:
meshName = "Primitive.Plane";
break;
case AssetManager::MeshGeometryDesc::Type::Capsule:
meshName = "Primitive.Capsule";
break;
case AssetManager::MeshGeometryDesc::Type::Provided:
default:
// Provided geometry requires explicit vertex/index data; not supported here.
return false;
}
AssetManager::MeshCreateInfo ci{};
ci.name = meshName;
ci.geometry.type = geomType;
ci.material = material;
ci.boundsType = boundsTypeOverride;
auto mesh = _assetManager->createMesh(ci);
if (!mesh)
{
return false;
}
_sceneManager->addMeshInstance(instanceName, mesh, transform, boundsTypeOverride);
return true;
}
uint32_t VulkanEngine::loadGLTFAsync(const std::string &sceneName,
const std::string &modelRelativePath,
const glm::mat4 &transform,
@@ -627,6 +685,7 @@ void VulkanEngine::draw()
break;
}
}
if (newVolume != _activeIBLVolume)
{
const IBLPaths *paths = nullptr;
@@ -639,17 +698,25 @@ void VulkanEngine::draw()
paths = &_globalIBLPaths;
}
if (paths)
// Avoid enqueueing duplicate jobs for the same target volume.
const bool alreadyPendingForTarget =
_pendingIBLRequest.active && _pendingIBLRequest.targetVolume == newVolume;
if (paths && !alreadyPendingForTarget)
{
bool ibl_ok = _iblManager->load(*paths);
if (!ibl_ok)
if (_iblManager->load_async(*paths))
{
fmt::println("[Engine] Warning: failed to load IBL for {} (specular='{}')",
_pendingIBLRequest.active = true;
_pendingIBLRequest.targetVolume = newVolume;
_pendingIBLRequest.paths = *paths;
}
else
{
fmt::println("[Engine] Warning: failed to enqueue IBL load for {} (specular='{}')",
(newVolume >= 0) ? "volume" : "global environment",
paths->specularCube);
}
}
_activeIBLVolume = newVolume;
}
}
@@ -1118,6 +1185,33 @@ void VulkanEngine::run()
// Safe to destroy any BLAS queued for deletion now that the previous frame is idle.
if (_rayManager) { _rayManager->flushPendingDeletes(); }
// Commit any completed async IBL load now that the GPU is idle.
if (_iblManager && _pendingIBLRequest.active)
{
IBLManager::AsyncResult iblRes = _iblManager->pump_async();
if (iblRes.completed)
{
if (iblRes.success)
{
if (_pendingIBLRequest.targetVolume >= 0)
{
_activeIBLVolume = _pendingIBLRequest.targetVolume;
}
else
{
_activeIBLVolume = -1;
_hasGlobalIBL = true;
}
}
else
{
fmt::println("[Engine] Warning: async IBL load failed (specular='{}')",
_pendingIBLRequest.paths.specularCube);
}
_pendingIBLRequest.active = false;
}
}
if (_pickResultPending && _pickReadbackBuffer.buffer && _sceneManager)
{
vmaInvalidateAllocation(_deviceManager->allocator(), _pickReadbackBuffer.allocation, 0, sizeof(uint32_t));