diff --git a/CMakeLists.txt b/CMakeLists.txt index 993ef2d..57a406d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -23,3 +23,20 @@ add_dependencies(CookAssets _internal_cook_game_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() diff --git a/destrum/include/destrum/Graphics/Renderer.h b/destrum/include/destrum/Graphics/Renderer.h index 08907d3..5aff843 100644 --- a/destrum/include/destrum/Graphics/Renderer.h +++ b/destrum/include/destrum/Graphics/Renderer.h @@ -33,7 +33,7 @@ public: void endDrawing(); 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 drawSkinnedMesh(MeshID id, diff --git a/destrum/src/App.cpp b/destrum/src/App.cpp index 36576b4..fc6442f 100644 --- a/destrum/src/App.cpp +++ b/destrum/src/App.cpp @@ -126,5 +126,6 @@ void App::run() { } void App::cleanup() { + spdlog::info("Cleaning up"); customCleanup(); } diff --git a/destrum/src/Graphics/GfxDevice.cpp b/destrum/src/Graphics/GfxDevice.cpp index be3fc3f..9bd0d80 100644 --- a/destrum/src/Graphics/GfxDevice.cpp +++ b/destrum/src/Graphics/GfxDevice.cpp @@ -104,18 +104,7 @@ void GfxDevice::init(SDL_Window* window, const std::string& appName, bool vSync) VkPhysicalDeviceProperties props{}; vkGetPhysicalDeviceProperties(physicalDevice, &props); - 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); - } + imageCache.bindlessSetManager.init(device, props.limits.maxSamplerAnisotropy); swapchain.initSync(device); diff --git a/destrum/src/Graphics/ImageCache.cpp b/destrum/src/Graphics/ImageCache.cpp index d990e6b..e7a9280 100644 --- a/destrum/src/Graphics/ImageCache.cpp +++ b/destrum/src/Graphics/ImageCache.cpp @@ -38,12 +38,20 @@ ImageID ImageCache::addImage(GPUImage image) { ImageID ImageCache::addImage(ImageID id, GPUImage image) { image.setBindlessId(static_cast(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 { + assert(id == images.size()); images.push_back(std::move(image)); } - bindlessSetManager.addImage(gfxDevice.getDevice(), id, image.imageView); + + bindlessSetManager.addImage( + gfxDevice.getDevice(), + id, + images[id].imageView + ); return id; } diff --git a/destrum/src/Graphics/Renderer.cpp b/destrum/src/Graphics/Renderer.cpp index 17a7ea5..96b5dc2 100644 --- a/destrum/src/Graphics/Renderer.cpp +++ b/destrum/src/Graphics/Renderer.cpp @@ -112,8 +112,30 @@ void GameRenderer::draw(VkCommandBuffer cmd, GfxDevice& gfxDevice, const Camera& } -void GameRenderer::cleanup(VkDevice device) { - meshPipeline->cleanup(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); + + 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) { diff --git a/lightkeeper/src/Lightkeeper.cpp b/lightkeeper/src/Lightkeeper.cpp index b55c98e..b203a02 100644 --- a/lightkeeper/src/Lightkeeper.cpp +++ b/lightkeeper/src/Lightkeeper.cpp @@ -25,138 +25,138 @@ void LightKeeper::customInit() { const float aspectRatio = static_cast(m_params.renderSize.x) / static_cast(m_params.renderSize.y); camera.setAspectRatio(aspectRatio); - - testMesh.name = "Test Mesh"; - auto list_of_models = ModelLoader::LoadGLTF_CPUMeshes_MergedPerMesh(AssetFS::GetInstance().GetFullPath("game://kitty.glb").generic_string()); - testMesh = list_of_models[0]; - testMeshID = meshCache.addMesh(gfxDevice, testMesh); - spdlog::info("TestMesh uploaded with id: {}", testMeshID); - - auto testimgID = gfxDevice.loadImageFromFile(AssetFS::GetInstance().GetFullPath("game://kitty.png")); - spdlog::info("Test image loaded with id: {}", testimgID); - testMaterialID = materialCache.addMaterial(gfxDevice, { - .baseColor = glm::vec3(1.f), - .diffuseTexture = testimgID, - }); - spdlog::info("Test material created with id: {}", testMaterialID); - - camera.SetRotation(glm::radians(glm::vec2(90.f, 0.f))); - + // + // testMesh.name = "Test Mesh"; + // auto list_of_models = ModelLoader::LoadGLTF_CPUMeshes_MergedPerMesh(AssetFS::GetInstance().GetFullPath("game://kitty.glb").generic_string()); + // testMesh = list_of_models[0]; + // testMeshID = meshCache.addMesh(gfxDevice, testMesh); + // spdlog::info("TestMesh uploaded with id: {}", testMeshID); + // + // auto testimgID = gfxDevice.loadImageFromFile(AssetFS::GetInstance().GetFullPath("game://kitty.png")); + // spdlog::info("Test image loaded with id: {}", testimgID); + // testMaterialID = materialCache.addMaterial(gfxDevice, { + // .baseColor = glm::vec3(1.f), + // .diffuseTexture = testimgID, + // }); + // spdlog::info("Test material created with id: {}", testMaterialID); + // + // camera.SetRotation(glm::radians(glm::vec2(90.f, 0.f))); + // auto& scene = SceneManager::GetInstance().CreateScene("Main"); - - // auto testCube = std::make_shared("TestCube"); - // auto meshComp = testCube->AddComponent(); - // 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(fmt::format("ChildCube{}", i)); - // - // auto childMeshComp = childCube->AddComponent(); - // childMeshComp->SetMeshID(testMeshID); - // childMeshComp->SetMaterialID(testMaterialID); - // - // childCube->GetTransform().SetWorldScale(glm::vec3(0.1f)); - // - // // Add orbit + self spin - // auto orbit = childCube->AddComponent(orbitRadius, glm::vec3(0.0f)); - // orbit->Randomize(1337u + (uint32_t)i); // stable random per index - // - // scene.Add(childCube); - } - // testCube->AddComponent(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("GlobeRoot"); - globeRoot->GetTransform().SetWorldPosition(glm::vec3(0.0f)); - globeRoot->AddComponent(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"); + // // auto testCube = std::make_shared("TestCube"); + // // auto meshComp = testCube->AddComponent(); + // // meshComp->SetMeshID(testMeshID); + // // meshComp->SetMaterialID(testMaterialID); + // const int count = 100; + // const float radius = 5.0f; // - // const auto skyboxID = AssetFS::GetInstance().GetFullPath("engine://textures/test-skybox.png"); + // const float orbitRadius = 5.0f; // - const auto vertShaderPath = AssetFS::GetInstance().GetCookedPathForFile("engine://shaders/cubemap.vert"); - const auto fragShaderPath = AssetFS::GetInstance().GetCookedPathForFile("engine://shaders/cubemap.frag"); + // for (int i = 0; i < count; ++i) { + // // auto childCube = std::make_shared(fmt::format("ChildCube{}", i)); + // // + // // auto childMeshComp = childCube->AddComponent(); + // // childMeshComp->SetMeshID(testMeshID); + // // childMeshComp->SetMaterialID(testMaterialID); + // // + // // childCube->GetTransform().SetWorldScale(glm::vec3(0.1f)); + // // + // // // Add orbit + self spin + // // auto orbit = childCube->AddComponent(orbitRadius, glm::vec3(0.0f)); + // // orbit->Randomize(1337u + (uint32_t)i); // stable random per index + // // + // // scene.Add(childCube); + // } + // // testCube->AddComponent(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("GlobeRoot"); + // globeRoot->GetTransform().SetWorldPosition(glm::vec3(0.0f)); + // globeRoot->AddComponent(glm::vec3(0, 1, 0), 1.0f); // spin around Y, rad/sec + // scene.Add(globeRoot); // - skyboxCubemap = std::make_unique(); - 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("GroundPlane"); - const auto planeMeshComp = planeObj->AddComponent(); - 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, { - .baseColor = glm::vec3(1.f), - .textureFilteringMode = TextureFilteringMode::Nearest, - .diffuseTexture = planeTextureID, - .name = "GroundPlaneMaterial", - }); - planeMeshComp->SetMeshID(planeMeshID); - planeMeshComp->SetMaterialID(planeMaterialID); - planeObj->GetTransform().SetWorldPosition(glm::vec3(0.f, -1.0f, 0.f)); - planeObj->GetTransform().SetWorldScale(glm::vec3(10.f, 1.f, 10.f)); - scene.Add(planeObj); - - - // At the bottom of customInit(), replace the incomplete CharObj block: - - const auto CharObj = std::make_shared("Character"); - - auto charModel = ModelLoader::LoadSkinnedModel( - AssetFS::GetInstance().GetFullPath("engine://char2.fbx").generic_string() - ); - - 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, { - .baseColor = glm::vec3(1.f), - .diffuseTexture = charTextureID, - .name = "CharacterMaterial", - }); - - const auto charMeshComp = CharObj->AddComponent(); - charMeshComp->SetMeshID(charMeshID); - charMeshComp->SetMaterialID(charMaterialID); - - - const auto animator = CharObj->AddComponent(); - animator->setSkeleton(std::move(charModel.skeleton)); - for (auto& clip : charModel.animations) { - animator->addClip(std::make_shared(std::move(clip))); - } - - 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"); - // // animator->play(charModel.animations[0].name); - 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); - scene.Add(CharObj); + // + // // 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"); + // // + // const auto vertShaderPath = AssetFS::GetInstance().GetCookedPathForFile("engine://shaders/cubemap.vert"); + // const auto fragShaderPath = AssetFS::GetInstance().GetCookedPathForFile("engine://shaders/cubemap.frag"); + // // + // skyboxCubemap = std::make_unique(); + // 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("GroundPlane"); + // const auto planeMeshComp = planeObj->AddComponent(); + // 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, { + // .baseColor = glm::vec3(1.f), + // .textureFilteringMode = TextureFilteringMode::Nearest, + // .diffuseTexture = planeTextureID, + // .name = "GroundPlaneMaterial", + // }); + // planeMeshComp->SetMeshID(planeMeshID); + // planeMeshComp->SetMaterialID(planeMaterialID); + // planeObj->GetTransform().SetWorldPosition(glm::vec3(0.f, -1.0f, 0.f)); + // planeObj->GetTransform().SetWorldScale(glm::vec3(10.f, 1.f, 10.f)); + // scene.Add(planeObj); + // + // + // // At the bottom of customInit(), replace the incomplete CharObj block: + // + // const auto CharObj = std::make_shared("Character"); + // + // auto charModel = ModelLoader::LoadSkinnedModel( + // AssetFS::GetInstance().GetFullPath("engine://char2.fbx").generic_string() + // ); + // + // 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, { + // .baseColor = glm::vec3(1.f), + // .diffuseTexture = charTextureID, + // .name = "CharacterMaterial", + // }); + // + // const auto charMeshComp = CharObj->AddComponent(); + // charMeshComp->SetMeshID(charMeshID); + // charMeshComp->SetMaterialID(charMaterialID); + // + // + // const auto animator = CharObj->AddComponent(); + // animator->setSkeleton(std::move(charModel.skeleton)); + // for (auto& clip : charModel.animations) { + // animator->addClip(std::make_shared(std::move(clip))); + // } + // + // 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"); + // // // animator->play(charModel.animations[0].name); + // 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); + // scene.Add(CharObj); } void LightKeeper::customUpdate(float dt) { @@ -198,8 +198,20 @@ void LightKeeper::customDraw() { } void LightKeeper::customCleanup() { + auto device = gfxDevice.getDevice().device; + + vkDeviceWaitIdle(device); + 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) { diff --git a/lightkeeper/src/main.cpp b/lightkeeper/src/main.cpp index 37f4eb1..1a4b83e 100644 --- a/lightkeeper/src/main.cpp +++ b/lightkeeper/src/main.cpp @@ -9,22 +9,24 @@ int main(int argc, char* argv[]) { SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Error", SDL_GetError(), nullptr); 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); - - LightKeeper app; - app.init({ - .windowSize = {800, 600}, - .renderSize = {800, 600}, - .appName = "Astro Engine", - .windowTitle = "Lightkeeper", - .exeDir = exeDir, - }); - app.run(); - app.cleanup(); + LightKeeper app; + app.init({ + .windowSize = {800, 600}, + .renderSize = {800, 600}, + .appName = "Astro Engine", + .windowTitle = "Lightkeeper", + .exeDir = exeDir, + }); + app.run(); + app.cleanup(); + } SDL_Quit(); return 0; } +