fix shutdown

This commit is contained in:
2026-06-20 01:20:14 +02:00
parent 1479ad468d
commit b1dad89214
8 changed files with 209 additions and 158 deletions

View File

@@ -23,3 +23,20 @@ add_dependencies(CookAssets
_internal_cook_game_assets _internal_cook_game_assets
_internal_cook_engine_assets _internal_cook_engine_assets
) )
option(ENABLE_SANITIZERS "Enable Address/Undefined sanitizers" OFF)
if (ENABLE_SANITIZERS AND CMAKE_CXX_COMPILER_ID MATCHES "Clang|GNU")
foreach(target destrum lightkeeper)
target_compile_options(${target} PRIVATE
-fsanitize=address,undefined
-fno-omit-frame-pointer
-fno-stack-protector
-g3
)
target_link_options(${target} PRIVATE
-fsanitize=address,undefined
)
endforeach()
endif()

View File

@@ -33,7 +33,7 @@ public:
void endDrawing(); void endDrawing();
void draw(VkCommandBuffer cmd, GfxDevice& gfxDevice, const Camera& camera, const SceneData& sceneData); void draw(VkCommandBuffer cmd, GfxDevice& gfxDevice, const Camera& camera, const SceneData& sceneData);
void cleanup(VkDevice device); void cleanup(GfxDevice& gfxDevice);
void drawMesh(MeshID id, const glm::mat4& transform, MaterialID materialId); void drawMesh(MeshID id, const glm::mat4& transform, MaterialID materialId);
void drawSkinnedMesh(MeshID id, void drawSkinnedMesh(MeshID id,

View File

@@ -126,5 +126,6 @@ void App::run() {
} }
void App::cleanup() { void App::cleanup() {
spdlog::info("Cleaning up");
customCleanup(); customCleanup();
} }

View File

@@ -104,18 +104,7 @@ void GfxDevice::init(SDL_Window* window, const std::string& appName, bool vSync)
VkPhysicalDeviceProperties props{}; VkPhysicalDeviceProperties props{};
vkGetPhysicalDeviceProperties(physicalDevice, &props); vkGetPhysicalDeviceProperties(physicalDevice, &props);
imageCache.bindlessSetManager.init(device, props.limits.maxSamplerAnisotropy); { imageCache.bindlessSetManager.init(device, props.limits.maxSamplerAnisotropy);
// create white texture
std::uint32_t pixel = 0xFFFFFFFF;
whiteImageId = createImage(
{
.format = VK_FORMAT_R8G8B8A8_UNORM,
.usage = VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT,
.extent = VkExtent3D{1, 1, 1},
},
"white texture",
&pixel);
}
swapchain.initSync(device); swapchain.initSync(device);

View File

@@ -38,12 +38,20 @@ ImageID ImageCache::addImage(GPUImage image) {
ImageID ImageCache::addImage(ImageID id, GPUImage image) { ImageID ImageCache::addImage(ImageID id, GPUImage image) {
image.setBindlessId(static_cast<std::uint32_t>(id)); image.setBindlessId(static_cast<std::uint32_t>(id));
if (id != images.size()) {
images[id] = std::move(image); // replacing existing image if (id < images.size()) {
gfxDevice.destroyImage(images[id]);
images[id] = std::move(image);
} else { } else {
assert(id == images.size());
images.push_back(std::move(image)); images.push_back(std::move(image));
} }
bindlessSetManager.addImage(gfxDevice.getDevice(), id, image.imageView);
bindlessSetManager.addImage(
gfxDevice.getDevice(),
id,
images[id].imageView
);
return id; return id;
} }

View File

@@ -112,8 +112,30 @@ void GameRenderer::draw(VkCommandBuffer cmd, GfxDevice& gfxDevice, const Camera&
} }
void GameRenderer::cleanup(VkDevice device) { void GameRenderer::cleanup(GfxDevice& gfxDevice) {
VkDevice device = gfxDevice.getDevice().device;
vkDeviceWaitIdle(device);
if (skinningPipeline)
skinningPipeline->cleanup(gfxDevice);
if (skyboxPipeline)
skyboxPipeline->cleanup(device);
if (meshPipeline)
meshPipeline->cleanup(device); meshPipeline->cleanup(device);
sceneDataBuffer.cleanup(gfxDevice);
// if (drawImageId != NULL_IMAGE_ID)
// gfxDevice.destroyImage();
// if (depthImageId != NULL_IMAGE_ID)
// gfxDevice.destroyImage(depthImageId);
drawImageId = NULL_IMAGE_ID;
depthImageId = NULL_IMAGE_ID;
} }
void GameRenderer::drawMesh(MeshID id, const glm::mat4& transform, MaterialID materialId) { void GameRenderer::drawMesh(MeshID id, const glm::mat4& transform, MaterialID materialId) {

View File

@@ -25,138 +25,138 @@ void LightKeeper::customInit() {
const float aspectRatio = static_cast<float>(m_params.renderSize.x) / static_cast<float>(m_params.renderSize.y); const float aspectRatio = static_cast<float>(m_params.renderSize.x) / static_cast<float>(m_params.renderSize.y);
camera.setAspectRatio(aspectRatio); camera.setAspectRatio(aspectRatio);
//
testMesh.name = "Test Mesh"; // testMesh.name = "Test Mesh";
auto list_of_models = ModelLoader::LoadGLTF_CPUMeshes_MergedPerMesh(AssetFS::GetInstance().GetFullPath("game://kitty.glb").generic_string()); // auto list_of_models = ModelLoader::LoadGLTF_CPUMeshes_MergedPerMesh(AssetFS::GetInstance().GetFullPath("game://kitty.glb").generic_string());
testMesh = list_of_models[0]; // testMesh = list_of_models[0];
testMeshID = meshCache.addMesh(gfxDevice, testMesh); // testMeshID = meshCache.addMesh(gfxDevice, testMesh);
spdlog::info("TestMesh uploaded with id: {}", testMeshID); // spdlog::info("TestMesh uploaded with id: {}", testMeshID);
//
auto testimgID = gfxDevice.loadImageFromFile(AssetFS::GetInstance().GetFullPath("game://kitty.png")); // auto testimgID = gfxDevice.loadImageFromFile(AssetFS::GetInstance().GetFullPath("game://kitty.png"));
spdlog::info("Test image loaded with id: {}", testimgID); // spdlog::info("Test image loaded with id: {}", testimgID);
testMaterialID = materialCache.addMaterial(gfxDevice, { // testMaterialID = materialCache.addMaterial(gfxDevice, {
.baseColor = glm::vec3(1.f), // .baseColor = glm::vec3(1.f),
.diffuseTexture = testimgID, // .diffuseTexture = testimgID,
}); // });
spdlog::info("Test material created with id: {}", testMaterialID); // spdlog::info("Test material created with id: {}", testMaterialID);
//
camera.SetRotation(glm::radians(glm::vec2(90.f, 0.f))); // camera.SetRotation(glm::radians(glm::vec2(90.f, 0.f)));
//
auto& scene = SceneManager::GetInstance().CreateScene("Main"); auto& scene = SceneManager::GetInstance().CreateScene("Main");
// auto testCube = std::make_shared<GameObject>("TestCube");
// auto meshComp = testCube->AddComponent<MeshRendererComponent>();
// meshComp->SetMeshID(testMeshID);
// meshComp->SetMaterialID(testMaterialID);
const int count = 100;
const float radius = 5.0f;
const float orbitRadius = 5.0f;
for (int i = 0; i < count; ++i) {
// auto childCube = std::make_shared<GameObject>(fmt::format("ChildCube{}", i));
// //
// auto childMeshComp = childCube->AddComponent<MeshRendererComponent>(); // // auto testCube = std::make_shared<GameObject>("TestCube");
// childMeshComp->SetMeshID(testMeshID); // // auto meshComp = testCube->AddComponent<MeshRendererComponent>();
// childMeshComp->SetMaterialID(testMaterialID); // // meshComp->SetMeshID(testMeshID);
// // meshComp->SetMaterialID(testMaterialID);
// const int count = 100;
// const float radius = 5.0f;
// //
// childCube->GetTransform().SetWorldScale(glm::vec3(0.1f)); // const float orbitRadius = 5.0f;
// //
// // Add orbit + self spin // for (int i = 0; i < count; ++i) {
// auto orbit = childCube->AddComponent<OrbitAndSpin>(orbitRadius, glm::vec3(0.0f)); // // auto childCube = std::make_shared<GameObject>(fmt::format("ChildCube{}", i));
// orbit->Randomize(1337u + (uint32_t)i); // stable random per index // //
// // auto childMeshComp = childCube->AddComponent<MeshRendererComponent>();
// // childMeshComp->SetMeshID(testMeshID);
// // childMeshComp->SetMaterialID(testMaterialID);
// //
// // childCube->GetTransform().SetWorldScale(glm::vec3(0.1f));
// //
// // // Add orbit + self spin
// // auto orbit = childCube->AddComponent<OrbitAndSpin>(orbitRadius, glm::vec3(0.0f));
// // orbit->Randomize(1337u + (uint32_t)i); // stable random per index
// //
// // scene.Add(childCube);
// }
// // testCube->AddComponent<Spinner>(glm::vec3(0, 1, 0), glm::radians(10.0f)); // spin around Y, rad/sec
// //rotate 180 around X axis
// // testCube->GetTransform().SetLocalRotation(glm::quat(glm::vec3(glm::radians(180.0f), 0.0f, 0.0f)));
// //
// auto globeRoot = std::make_shared<GameObject>("GlobeRoot");
// globeRoot->GetTransform().SetWorldPosition(glm::vec3(0.0f));
// globeRoot->AddComponent<Spinner>(glm::vec3(0, 1, 0), 1.0f); // spin around Y, rad/sec
// scene.Add(globeRoot);
// //
// scene.Add(childCube);
}
// testCube->AddComponent<Spinner>(glm::vec3(0, 1, 0), glm::radians(10.0f)); // spin around Y, rad/sec
//rotate 180 around X axis
// testCube->GetTransform().SetLocalRotation(glm::quat(glm::vec3(glm::radians(180.0f), 0.0f, 0.0f)));
// //
auto globeRoot = std::make_shared<GameObject>("GlobeRoot");
globeRoot->GetTransform().SetWorldPosition(glm::vec3(0.0f));
globeRoot->AddComponent<Spinner>(glm::vec3(0, 1, 0), 1.0f); // spin around Y, rad/sec
scene.Add(globeRoot);
// scene.Add(testCube);
// const auto skyboxID = AssetFS::GetInstance().GetFullPath("engine://textures/skybox.jpg");
// const auto skyboxID = AssetFS::GetInstance().GetFullPath("engine://textures/mars.jpg");
const auto skyboxID = AssetFS::GetInstance().GetCookedPathForFile("game://starmap_2020_4k.exr");
// //
// const auto skyboxID = AssetFS::GetInstance().GetFullPath("engine://textures/test-skybox.png"); // // scene.Add(testCube);
// //
const auto vertShaderPath = AssetFS::GetInstance().GetCookedPathForFile("engine://shaders/cubemap.vert"); // // const auto skyboxID = AssetFS::GetInstance().GetFullPath("engine://textures/skybox.jpg");
const auto fragShaderPath = AssetFS::GetInstance().GetCookedPathForFile("engine://shaders/cubemap.frag"); // // const auto skyboxID = AssetFS::GetInstance().GetFullPath("engine://textures/mars.jpg");
// const auto skyboxID = AssetFS::GetInstance().GetCookedPathForFile("game://starmap_2020_4k.exr");
// //
// // const auto skyboxID = AssetFS::GetInstance().GetFullPath("engine://textures/test-skybox.png");
// //
// const auto vertShaderPath = AssetFS::GetInstance().GetCookedPathForFile("engine://shaders/cubemap.vert");
// const auto fragShaderPath = AssetFS::GetInstance().GetCookedPathForFile("engine://shaders/cubemap.frag");
// //
// skyboxCubemap = std::make_unique<CubeMap>();
// skyboxCubemap->LoadCubeMap(skyboxID.generic_string());
// skyboxCubemap->InitCubemapPipeline(vertShaderPath.generic_string(), fragShaderPath.generic_string());
// skyboxCubemap->CreateCubeMap();
// //
skyboxCubemap = std::make_unique<CubeMap>(); // renderer.setSkyboxTexture(skyboxCubemap->GetCubeMapImageID());
skyboxCubemap->LoadCubeMap(skyboxID.generic_string());
skyboxCubemap->InitCubemapPipeline(vertShaderPath.generic_string(), fragShaderPath.generic_string());
skyboxCubemap->CreateCubeMap();
renderer.setSkyboxTexture(skyboxCubemap->GetCubeMapImageID());
// //
const auto planeObj = std::make_shared<GameObject>("GroundPlane"); // //
const auto planeMeshComp = planeObj->AddComponent<MeshRendererComponent>(); // const auto planeObj = std::make_shared<GameObject>("GroundPlane");
const auto planeModel = ModelLoader::LoadGLTF_CPUMeshes_MergedPerMesh(AssetFS::GetInstance().GetFullPath("game://plane.glb").generic_string()); // const auto planeMeshComp = planeObj->AddComponent<MeshRendererComponent>();
const auto planeMeshID = meshCache.addMesh(gfxDevice, planeModel[0]); // const auto planeModel = ModelLoader::LoadGLTF_CPUMeshes_MergedPerMesh(AssetFS::GetInstance().GetFullPath("game://plane.glb").generic_string());
// const auto planeMeshID = meshCache.addMesh(gfxDevice, planeModel[0]);
const auto planeTextureID = gfxDevice.loadImageFromFile(AssetFS::GetInstance().GetFullPath("game://grass.png")); //
const auto planeMaterialID = materialCache.addMaterial(gfxDevice, { // const auto planeTextureID = gfxDevice.loadImageFromFile(AssetFS::GetInstance().GetFullPath("game://grass.png"));
.baseColor = glm::vec3(1.f), // const auto planeMaterialID = materialCache.addMaterial(gfxDevice, {
.textureFilteringMode = TextureFilteringMode::Nearest, // .baseColor = glm::vec3(1.f),
.diffuseTexture = planeTextureID, // .textureFilteringMode = TextureFilteringMode::Nearest,
.name = "GroundPlaneMaterial", // .diffuseTexture = planeTextureID,
}); // .name = "GroundPlaneMaterial",
planeMeshComp->SetMeshID(planeMeshID); // });
planeMeshComp->SetMaterialID(planeMaterialID); // planeMeshComp->SetMeshID(planeMeshID);
planeObj->GetTransform().SetWorldPosition(glm::vec3(0.f, -1.0f, 0.f)); // planeMeshComp->SetMaterialID(planeMaterialID);
planeObj->GetTransform().SetWorldScale(glm::vec3(10.f, 1.f, 10.f)); // planeObj->GetTransform().SetWorldPosition(glm::vec3(0.f, -1.0f, 0.f));
scene.Add(planeObj); // planeObj->GetTransform().SetWorldScale(glm::vec3(10.f, 1.f, 10.f));
// scene.Add(planeObj);
//
// At the bottom of customInit(), replace the incomplete CharObj block: //
// // At the bottom of customInit(), replace the incomplete CharObj block:
const auto CharObj = std::make_shared<GameObject>("Character"); //
// const auto CharObj = std::make_shared<GameObject>("Character");
auto charModel = ModelLoader::LoadSkinnedModel( //
AssetFS::GetInstance().GetFullPath("engine://char2.fbx").generic_string() // auto charModel = ModelLoader::LoadSkinnedModel(
); // AssetFS::GetInstance().GetFullPath("engine://char2.fbx").generic_string()
// );
const auto charMeshID = meshCache.addMesh(gfxDevice, charModel.meshes[0]); //
// const auto charMeshID = meshCache.addMesh(gfxDevice, charModel.meshes[0]);
const auto charTextureID = gfxDevice.loadImageFromFile(AssetFS::GetInstance().GetFullPath("engine://char.jpg")); //
const auto charMaterialID = materialCache.addMaterial(gfxDevice, { // const auto charTextureID = gfxDevice.loadImageFromFile(AssetFS::GetInstance().GetFullPath("engine://char.jpg"));
.baseColor = glm::vec3(1.f), // const auto charMaterialID = materialCache.addMaterial(gfxDevice, {
.diffuseTexture = charTextureID, // .baseColor = glm::vec3(1.f),
.name = "CharacterMaterial", // .diffuseTexture = charTextureID,
}); // .name = "CharacterMaterial",
// });
const auto charMeshComp = CharObj->AddComponent<MeshRendererComponent>(); //
charMeshComp->SetMeshID(charMeshID); // const auto charMeshComp = CharObj->AddComponent<MeshRendererComponent>();
charMeshComp->SetMaterialID(charMaterialID); // charMeshComp->SetMeshID(charMeshID);
// charMeshComp->SetMaterialID(charMaterialID);
//
const auto animator = CharObj->AddComponent<Animator>(); //
animator->setSkeleton(std::move(charModel.skeleton)); // const auto animator = CharObj->AddComponent<Animator>();
for (auto& clip : charModel.animations) { // animator->setSkeleton(std::move(charModel.skeleton));
animator->addClip(std::make_shared<SkeletalAnimation>(std::move(clip))); // for (auto& clip : charModel.animations) {
} // animator->addClip(std::make_shared<SkeletalAnimation>(std::move(clip)));
// }
for (const auto& clip : charModel.animations) //
spdlog::info("Loaded animation: '{}' ({:.2f}s)", clip.name, clip.duration); // for (const auto& clip : charModel.animations)
// spdlog::info("Loaded animation: '{}' ({:.2f}s)", clip.name, clip.duration);
if (!charModel.animations.empty()) //
// animator->play("Armature|Armature|mixamo.com"); // if (!charModel.animations.empty())
// // animator->play(charModel.animations[0].name); // // animator->play("Armature|Armature|mixamo.com");
animator->play("Armature|Armature|Armature|main"); // // // animator->play(charModel.animations[0].name);
// or: animator->play("Run", 0.2f); // 0.2s cross-fade // animator->play("Armature|Armature|Armature|main");
// // or: animator->play("Run", 0.2f); // 0.2s cross-fade
CharObj->GetTransform().SetWorldPosition(glm::vec3(0.f, 0.f, 0.f)); //
// CharObj->GetTransform().SetWorldScale(0.01f, 0.01f, 0.01f); // CharObj->GetTransform().SetWorldPosition(glm::vec3(0.f, 0.f, 0.f));
scene.Add(CharObj); // // CharObj->GetTransform().SetWorldScale(0.01f, 0.01f, 0.01f);
// scene.Add(CharObj);
} }
void LightKeeper::customUpdate(float dt) { void LightKeeper::customUpdate(float dt) {
@@ -198,8 +198,20 @@ void LightKeeper::customDraw() {
} }
void LightKeeper::customCleanup() { void LightKeeper::customCleanup() {
auto device = gfxDevice.getDevice().device;
vkDeviceWaitIdle(device);
SceneManager::GetInstance().Destroy(); SceneManager::GetInstance().Destroy();
renderer.cleanup(gfxDevice.getDevice().device);
if (skyboxCubemap) {
skyboxCubemap.reset();
}
renderer.cleanup(gfxDevice);
materialCache.cleanup(gfxDevice);
meshCache.cleanup(gfxDevice);
} }
void LightKeeper::onWindowResize(int newWidth, int newHeight) { void LightKeeper::onWindowResize(int newWidth, int newHeight) {

View File

@@ -9,7 +9,7 @@ int main(int argc, char* argv[]) {
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Error", SDL_GetError(), nullptr); SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Error", SDL_GetError(), nullptr);
return 1; return 1;
} }
{
std::filesystem::path exeDir = SDL_GetBasePath(); std::filesystem::path exeDir = SDL_GetBasePath();
spdlog::set_level(spdlog::level::debug); spdlog::set_level(spdlog::level::debug);
@@ -24,7 +24,9 @@ int main(int argc, char* argv[]) {
}); });
app.run(); app.run();
app.cleanup(); app.cleanup();
}
SDL_Quit(); SDL_Quit();
return 0; return 0;
} }