diff --git a/src/common/rendering/vulkan/accelstructs/vk_lightmap.cpp b/src/common/rendering/vulkan/accelstructs/vk_lightmap.cpp index 4dbfad0f8..cd044f28b 100644 --- a/src/common/rendering/vulkan/accelstructs/vk_lightmap.cpp +++ b/src/common/rendering/vulkan/accelstructs/vk_lightmap.cpp @@ -12,10 +12,13 @@ static int lastSurfaceCount; static glcycle_t lightmapRaytrace; static glcycle_t lightmapRaytraceLast; +static uint32_t lastPixelCount; +static uint32_t totalPixelCount; + ADD_STAT(lightmapper) { FString out; - out.Format("last: %.3fms\ntotal: %3.fms\nLast batch surface count: %d", lightmapRaytraceLast.TimeMS(), lightmapRaytrace.TimeMS(), lastSurfaceCount); + out.Format("last: %.3fms\ntotal: %3.fms\nLast batch surface count: %d\nLast batch pixel count: %u\nTotal pixel count: %u", lightmapRaytraceLast.TimeMS(), lightmapRaytrace.TimeMS(), lastSurfaceCount, lastPixelCount, totalPixelCount); return out; } @@ -52,6 +55,9 @@ void VkLightmap::SetLevelMesh(LevelMesh* level) lightmapRaytrace.Reset(); lightmapRaytraceLast.Reset(); + totalPixelCount = 0; + lastPixelCount = 0; + lastSurfaceCount = 0; } void VkLightmap::Raytrace(const TArray& surfaces) @@ -66,14 +72,19 @@ void VkLightmap::Raytrace(const TArray& surfaces) CreateAtlasImages(surfaces); + uint32_t pixels = 0; + for (auto& surface : surfaces) { surface->needsUpdate = false; // it may have been set to false already, but lightmapper ultimately decides so + pixels += surface->texHeight * surface->texWidth; } UploadUniforms(); lastSurfaceCount = surfaces.Size(); + lastPixelCount = pixels; + totalPixelCount += pixels; for (size_t pageIndex = 0; pageIndex < atlasImages.size(); pageIndex++) { diff --git a/src/rendering/hwrenderer/doom_levelmesh.cpp b/src/rendering/hwrenderer/doom_levelmesh.cpp index bcd5bff39..99629c554 100644 --- a/src/rendering/hwrenderer/doom_levelmesh.cpp +++ b/src/rendering/hwrenderer/doom_levelmesh.cpp @@ -10,21 +10,87 @@ #include "common/rendering/vulkan/accelstructs/vk_lightmap.h" #include +void PrintMissingLevelMesh() +{ + Printf("No level mesh. Perhaps your level has no lightmap loaded?\n"); +} + +void PrintNoLightmaps() +{ + Printf("Lightmap is not enabled in this level.\n"); +} + +ADD_STAT(lightmap) +{ + FString out; + if (level.levelMesh && level.lightmaps) + { + auto* mesh = level.levelMesh; + + uint32_t usedPixels = 0; + uint32_t updatesNeeded = 0; + uint32_t skies = 0; + uint32_t pixelsTbd = 0; + for (auto& surface : mesh->Surfaces) + { + uint32_t area = surface.texWidth * surface.texHeight; + + if (surface.needsUpdate) + { + pixelsTbd += area; + updatesNeeded++; + } + + if (surface.bSky) + { + skies++; + } + + usedPixels += area; + } + + uint32_t atlasPixelCount = level.levelMesh->LMTextureSize * level.levelMesh->LMTextureSize * level.levelMesh->LMTextureCount; + + out.Format("Surfaces: %u (sky: %u, awaiting updates: %u)\nSurface pixel area to update: %u\nSurface pixel area: %u\nAtlas pixel area: %u\nAtlas efficiency: %.4f%%", + mesh->Surfaces.Size(), skies, updatesNeeded, + pixelsTbd, + usedPixels, + atlasPixelCount, + float(usedPixels) / float(atlasPixelCount) * 100.0f ); + } + else + { + out.Format("No level mesh."); + } + return out; +} + CCMD(dumplevelmesh) { if (level.levelMesh) { level.levelMesh->DumpMesh(FString("levelmesh.obj"), FString("levelmesh.mtl")); - Printf("Level mesh exported."); + Printf("Level mesh exported.\n"); } else { - Printf("No level mesh. Perhaps your level has no lightmap loaded?"); + PrintMissingLevelMesh(); } } CCMD(invalidatelightmap) { + if (!level.levelMesh) + { + PrintMissingLevelMesh(); + return; + } + if (!level.lightmaps) + { + PrintNoLightmaps(); + return; + } + int count = 0; for (auto& surface : level.levelMesh->Surfaces) { @@ -35,6 +101,63 @@ CCMD(invalidatelightmap) Printf("Marked %d out of %d surfaces for update.\n", count, level.levelMesh->Surfaces.Size()); } +CCMD(lightmapinfo) +{ + if (!level.levelMesh) + { + PrintMissingLevelMesh(); + return; + } + if (!level.lightmaps) + { + PrintNoLightmaps(); + return; + } +} + +CCMD(surfaceinfo) +{ + auto* mesh = level.levelMesh; + if (!mesh) + { + PrintMissingLevelMesh(); + return; + } + + auto pov = players[consoleplayer].mo; + + if (!pov) + { + Printf("players[consoleplayer].mo is null.\n"); + return; + } + + auto posXYZ = FVector3(pov->Pos()); + posXYZ.Z = players[consoleplayer].viewz; + + auto angle = pov->Angles.Yaw; + auto pitch = pov->Angles.Pitch; + + auto pc = float(pitch.Cos()); + auto dir = FVector3{ pc * float(angle.Cos()), pc * float(angle.Sin()), -float(pitch.Sin()) }; // No seriously, is there a dedication function for this? + + const auto surface = (DoomLevelMeshSurface*)mesh->Trace(posXYZ, dir, 32000.0f); + + if (surface) + { + Printf("Surface %d (%p)\n Type: %d, TypeIndex: %d, ControlSector: %d\n", mesh->GetSurfaceIndex(surface), surface, surface->Type, surface->typeIndex, surface->ControlSector ? surface->ControlSector->Index() : -1); + Printf(" Atlas page: %d, x:%d, y:%d\n", surface->atlasPageIndex, surface->atlasX, surface->atlasY); + Printf(" Pixels: %dx%d (area: %d)\n", surface->texWidth, surface->texHeight, surface->texWidth * surface->texHeight); + Printf(" Sample dimension: %d\n", surface->sampleDimension); + Printf(" Needs update?: %d\n", surface->needsUpdate); + } + else + { + Printf("No surface was hit.\n"); + return; + } +} + EXTERN_CVAR(Float, lm_scale); DoomLevelMesh::DoomLevelMesh(FLevelLocals &doomMap)