添加多模型渲染,添加贴图渲染,添加平行光, 暂时不上传assets
This commit is contained in:
@@ -0,0 +1,324 @@
|
||||
//
|
||||
// Created by atdunbg on 2026/9/21.
|
||||
//
|
||||
#include <Engine/Core/Stats.h>
|
||||
#include <Engine/Core/Log.h>
|
||||
|
||||
#include <fstream>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
|
||||
namespace Engine
|
||||
{
|
||||
Stats& Stats::Get()
|
||||
{
|
||||
static Stats instance;
|
||||
return instance;
|
||||
}
|
||||
|
||||
// ============ 资源计数 ============
|
||||
|
||||
void Stats::AddTexture(u64 bytes)
|
||||
{
|
||||
std::lock_guard lock(m_Mutex);
|
||||
m_TextureCount++;
|
||||
m_TextureBytes += bytes;
|
||||
m_FrameAllocation += bytes;
|
||||
m_TotalAllocation += bytes;
|
||||
}
|
||||
|
||||
void Stats::RemoveTexture(u64 bytes)
|
||||
{
|
||||
std::lock_guard lock(m_Mutex);
|
||||
if (m_TextureCount > 0) m_TextureCount--;
|
||||
if (m_TextureBytes >= bytes) m_TextureBytes -= bytes;
|
||||
m_FrameDeallocation += bytes;
|
||||
m_TotalDeallocation += bytes;
|
||||
}
|
||||
|
||||
void Stats::AddMesh(u64 vertexBytes, u64 indexBytes)
|
||||
{
|
||||
std::lock_guard lock(m_Mutex);
|
||||
m_MeshCount++;
|
||||
u64 total = vertexBytes + indexBytes;
|
||||
m_MeshBytes += total;
|
||||
m_FrameAllocation += total;
|
||||
m_TotalAllocation += total;
|
||||
}
|
||||
|
||||
void Stats::RemoveMesh(u64 vertexBytes, u64 indexBytes)
|
||||
{
|
||||
std::lock_guard lock(m_Mutex);
|
||||
if (m_MeshCount > 0) m_MeshCount--;
|
||||
u64 total = vertexBytes + indexBytes;
|
||||
if (m_MeshBytes >= total) m_MeshBytes -= total;
|
||||
m_FrameDeallocation += total;
|
||||
m_TotalDeallocation += total;
|
||||
}
|
||||
|
||||
void Stats::AddBuffer(u64 bytes)
|
||||
{
|
||||
std::lock_guard lock(m_Mutex);
|
||||
m_BufferCount++;
|
||||
m_BufferBytes += bytes;
|
||||
m_FrameAllocation += bytes;
|
||||
m_TotalAllocation += bytes;
|
||||
}
|
||||
|
||||
void Stats::RemoveBuffer(u64 bytes)
|
||||
{
|
||||
std::lock_guard lock(m_Mutex);
|
||||
if (m_BufferCount > 0) m_BufferCount--;
|
||||
if (m_BufferBytes >= bytes) m_BufferBytes -= bytes;
|
||||
m_FrameDeallocation += bytes;
|
||||
m_TotalDeallocation += bytes;
|
||||
}
|
||||
|
||||
void Stats::AddMemoryBlock(u64 bytes)
|
||||
{
|
||||
std::lock_guard lock(m_Mutex);
|
||||
m_MemoryBlockBytes += bytes;
|
||||
}
|
||||
|
||||
void Stats::RemoveMemoryBlock(u64 bytes)
|
||||
{
|
||||
std::lock_guard lock(m_Mutex);
|
||||
if (m_MemoryBlockBytes >= bytes) m_MemoryBlockBytes -= bytes;
|
||||
}
|
||||
|
||||
void Stats::AddMemoryUsed(u64 bytes)
|
||||
{
|
||||
std::lock_guard lock(m_Mutex);
|
||||
m_MemoryUsedBytes += bytes;
|
||||
}
|
||||
|
||||
void Stats::RemoveMemoryUsed(u64 bytes)
|
||||
{
|
||||
std::lock_guard lock(m_Mutex);
|
||||
if (m_MemoryUsedBytes >= bytes) m_MemoryUsedBytes -= bytes;
|
||||
}
|
||||
|
||||
// ============ 每帧 ============
|
||||
|
||||
void Stats::BeginFrame()
|
||||
{
|
||||
std::lock_guard lock(m_Mutex);
|
||||
m_FrameAllocation = 0;
|
||||
m_FrameDeallocation = 0;
|
||||
}
|
||||
|
||||
void Stats::EndFrame()
|
||||
{
|
||||
}
|
||||
|
||||
void Stats::AddAllocation(u64 bytes)
|
||||
{
|
||||
std::lock_guard lock(m_Mutex);
|
||||
m_FrameAllocation += bytes;
|
||||
m_TotalAllocation += bytes;
|
||||
}
|
||||
|
||||
void Stats::AddDeallocation(u64 bytes)
|
||||
{
|
||||
std::lock_guard lock(m_Mutex);
|
||||
m_FrameDeallocation += bytes;
|
||||
m_TotalDeallocation += bytes;
|
||||
}
|
||||
|
||||
// ============ 进程内存采样 ============
|
||||
|
||||
Stats::ProcessMemory Stats::ReadProcessMemory() const
|
||||
{
|
||||
ProcessMemory result;
|
||||
|
||||
// ---- 1. 从 /proc/self/status 读 VmRSS 和 VmSize ----
|
||||
// 这是内核报告的权威 RSS。smaps_rollup 会漏掉某些 NVIDIA 显存映射,
|
||||
// 但 status 的 VmRSS 包含所有 VMA。
|
||||
{
|
||||
std::ifstream status("/proc/self/status");
|
||||
std::string line;
|
||||
while (std::getline(status, line))
|
||||
{
|
||||
if (line.rfind("VmRSS:", 0) == 0)
|
||||
{
|
||||
std::istringstream iss(line.substr(6));
|
||||
u64 kb = 0;
|
||||
iss >> kb;
|
||||
result.Rss = kb * 1024;
|
||||
}
|
||||
else if (line.rfind("VmSize:", 0) == 0)
|
||||
{
|
||||
std::istringstream iss(line.substr(7));
|
||||
u64 kb = 0;
|
||||
iss >> kb;
|
||||
result.VmSize = kb * 1024;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ---- 2. 从 /proc/self/smaps_rollup 读 PSS 和分项 ----
|
||||
// 注意:Rss 不从这里读,用上面的。
|
||||
{
|
||||
std::ifstream smaps("/proc/self/smaps_rollup");
|
||||
std::string line;
|
||||
while (std::getline(smaps, line))
|
||||
{
|
||||
std::istringstream iss(line);
|
||||
std::string key;
|
||||
u64 value = 0;
|
||||
std::string unit;
|
||||
|
||||
iss >> key;
|
||||
if (key.empty()) continue;
|
||||
if (key.back() == ':') key.pop_back();
|
||||
|
||||
if (key == "Pss")
|
||||
{
|
||||
iss >> value >> unit;
|
||||
result.Pss = value * 1024;
|
||||
}
|
||||
else if (key == "Shared_Clean")
|
||||
{
|
||||
iss >> value >> unit;
|
||||
result.SharedClean = value * 1024;
|
||||
}
|
||||
else if (key == "Private_Dirty")
|
||||
{
|
||||
iss >> value >> unit;
|
||||
result.PrivateDirty = value * 1024;
|
||||
}
|
||||
else if (key == "Private_Clean")
|
||||
{
|
||||
iss >> value >> unit;
|
||||
result.PrivateClean = value * 1024;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void Stats::SampleProcessMemory()
|
||||
{
|
||||
std::lock_guard lock(m_Mutex);
|
||||
m_ProcessMem = ReadProcessMemory();
|
||||
}
|
||||
|
||||
// ============ 打印 ============
|
||||
|
||||
static double MB(u64 bytes) { return bytes / (1024.0 * 1024.0); }
|
||||
|
||||
void Stats::Print() const
|
||||
{
|
||||
std::lock_guard lock(m_Mutex);
|
||||
|
||||
auto proc = ReadProcessMemory();
|
||||
|
||||
ENGINE_INFO("========== Resource Stats ==========");
|
||||
ENGINE_INFO("Textures: {:>4} ({:.2f} MB)", m_TextureCount, MB(m_TextureBytes));
|
||||
ENGINE_INFO("Meshes: {:>4} ({:.2f} MB)", m_MeshCount, MB(m_MeshBytes));
|
||||
ENGINE_INFO("Buffers: {:>4} ({:.2f} MB)", m_BufferCount, MB(m_BufferBytes));
|
||||
ENGINE_INFO("--- GPU MemoryAllocator ---");
|
||||
ENGINE_INFO("Allocated: {:.2f} MB", MB(m_MemoryBlockBytes));
|
||||
ENGINE_INFO("Used: {:.2f} MB", MB(m_MemoryUsedBytes));
|
||||
ENGINE_INFO("Wasted: {:.2f} MB", MB(m_MemoryBlockBytes - m_MemoryUsedBytes));
|
||||
ENGINE_INFO("--- Process Memory ---");
|
||||
ENGINE_INFO("VmSize: {:.2f} MB", MB(proc.VmSize));
|
||||
ENGINE_INFO("RSS (resident): {:.2f} MB", MB(proc.Rss));
|
||||
ENGINE_INFO("PSS: {:.2f} MB", MB(proc.Pss));
|
||||
ENGINE_INFO(" Shared Clean: {:.2f} MB", MB(proc.SharedClean));
|
||||
ENGINE_INFO(" Private Dirty: {:.2f} MB", MB(proc.PrivateDirty));
|
||||
ENGINE_INFO(" Private Clean: {:.2f} MB", MB(proc.PrivateClean));
|
||||
ENGINE_INFO("====================================");
|
||||
}
|
||||
|
||||
void Stats::PrintDetailed() const
|
||||
{
|
||||
std::lock_guard lock(m_Mutex);
|
||||
|
||||
auto proc = ReadProcessMemory();
|
||||
|
||||
ENGINE_INFO("==================== Detailed Memory Stats ====================");
|
||||
|
||||
ENGINE_INFO(" Resources");
|
||||
ENGINE_INFO(" Textures: {:>6} {:>10.2f} MB", m_TextureCount, MB(m_TextureBytes));
|
||||
ENGINE_INFO(" Meshes: {:>6} {:>10.2f} MB", m_MeshCount, MB(m_MeshBytes));
|
||||
ENGINE_INFO(" Buffers: {:>6} {:>10.2f} MB", m_BufferCount, MB(m_BufferBytes));
|
||||
ENGINE_INFO(" Total: {:>10.2f} MB",
|
||||
MB(m_TextureBytes + m_MeshBytes + m_BufferBytes));
|
||||
|
||||
ENGINE_INFO(" GPU MemoryAllocator");
|
||||
ENGINE_INFO(" Allocated: {:>10.2f} MB", MB(m_MemoryBlockBytes));
|
||||
ENGINE_INFO(" Used: {:>10.2f} MB", MB(m_MemoryUsedBytes));
|
||||
ENGINE_INFO(" Wasted: {:>10.2f} MB",
|
||||
MB(m_MemoryBlockBytes - m_MemoryUsedBytes));
|
||||
|
||||
ENGINE_INFO(" Allocation Churn");
|
||||
ENGINE_INFO(" This frame: +{:.2f} MB / -{:.2f} MB",
|
||||
MB(m_FrameAllocation), MB(m_FrameDeallocation));
|
||||
ENGINE_INFO(" Total: +{:.2f} MB / -{:.2f} MB",
|
||||
MB(m_TotalAllocation), MB(m_TotalDeallocation));
|
||||
|
||||
ENGINE_INFO(" Process Memory (/proc/self/status + smaps_rollup)");
|
||||
ENGINE_INFO(" VmSize: {:>10.2f} MB", MB(proc.VmSize));
|
||||
ENGINE_INFO(" RSS: {:>10.2f} MB", MB(proc.Rss));
|
||||
ENGINE_INFO(" PSS: {:>10.2f} MB", MB(proc.Pss));
|
||||
ENGINE_INFO(" Shared Clean: {:>10.2f} MB", MB(proc.SharedClean));
|
||||
ENGINE_INFO(" Private Dirty: {:>10.2f} MB", MB(proc.PrivateDirty));
|
||||
ENGINE_INFO(" Private Clean: {:>10.2f} MB", MB(proc.PrivateClean));
|
||||
|
||||
ENGINE_INFO(" Unaccounted (RSS - GPU Blocks)");
|
||||
u64 engineTotal = m_MemoryBlockBytes;
|
||||
if (proc.Rss > engineTotal)
|
||||
{
|
||||
ENGINE_INFO(" {:.2f} MB (Vulkan driver, libs, stack, heap, ...)",
|
||||
MB(proc.Rss - engineTotal));
|
||||
}
|
||||
else
|
||||
{
|
||||
ENGINE_INFO(" (GPU blocks are the bulk of RSS)");
|
||||
}
|
||||
|
||||
ENGINE_INFO("===============================================================");
|
||||
}
|
||||
|
||||
void Stats::PrintComparison() const
|
||||
{
|
||||
std::lock_guard lock(m_Mutex);
|
||||
|
||||
auto proc = ReadProcessMemory();
|
||||
|
||||
u64 resourceTotal = m_TextureBytes + m_MeshBytes + m_BufferBytes;
|
||||
|
||||
ENGINE_INFO("=============== Memory Comparison ===============");
|
||||
ENGINE_INFO("");
|
||||
ENGINE_INFO("[Engine 自己统计]");
|
||||
ENGINE_INFO(" Textures {:>10.2f} MB", MB(m_TextureBytes));
|
||||
ENGINE_INFO(" Meshes {:>10.2f} MB", MB(m_MeshBytes));
|
||||
ENGINE_INFO(" Buffers {:>10.2f} MB", MB(m_BufferBytes));
|
||||
ENGINE_INFO(" ─────────────────────────────────────");
|
||||
ENGINE_INFO(" 资源合计 {:>10.2f} MB", MB(resourceTotal));
|
||||
ENGINE_INFO("");
|
||||
ENGINE_INFO(" Allocator Used {:>10.2f} MB", MB(m_MemoryUsedBytes));
|
||||
ENGINE_INFO(" Allocator Allocated {:>10.2f} MB", MB(m_MemoryBlockBytes));
|
||||
ENGINE_INFO(" Allocator Wasted {:>10.2f} MB",
|
||||
MB(m_MemoryBlockBytes - m_MemoryUsedBytes));
|
||||
ENGINE_INFO("");
|
||||
ENGINE_INFO("[系统 /proc 读出的]");
|
||||
ENGINE_INFO(" VmRSS {:>10.2f} MB", MB(proc.Rss));
|
||||
ENGINE_INFO(" VmSize {:>10.2f} MB", MB(proc.VmSize));
|
||||
ENGINE_INFO(" PSS {:>10.2f} MB", MB(proc.Pss));
|
||||
ENGINE_INFO(" Shared Clean {:>10.2f} MB", MB(proc.SharedClean));
|
||||
ENGINE_INFO(" Private Dirty {:>10.2f} MB", MB(proc.PrivateDirty));
|
||||
ENGINE_INFO(" Private Clean {:>10.2f} MB", MB(proc.PrivateClean));
|
||||
ENGINE_INFO("");
|
||||
ENGINE_INFO("[差值]");
|
||||
ENGINE_INFO(" RSS - Allocator {:>10.2f} MB (Vulkan 驱动 + libs + 栈堆)",
|
||||
MB(proc.Rss > m_MemoryBlockBytes ? proc.Rss - m_MemoryBlockBytes : 0));
|
||||
ENGINE_INFO(" RSS - 资源合计 {:>10.2f} MB (含分配器碎片)",
|
||||
MB(proc.Rss > resourceTotal ? proc.Rss - resourceTotal : 0));
|
||||
ENGINE_INFO(" Allocated - Used {:>10.2f} MB (分配器空闲块)",
|
||||
MB(m_MemoryBlockBytes - m_MemoryUsedBytes));
|
||||
ENGINE_INFO("================================================");
|
||||
}
|
||||
} // namespace Engine
|
||||
@@ -8,32 +8,46 @@
|
||||
|
||||
#include <GLFW/glfw3.h>
|
||||
|
||||
namespace Engine {
|
||||
namespace Engine
|
||||
{
|
||||
void Window::FramebufferResizeCallback(GLFWwindow* window, int width, int height)
|
||||
{
|
||||
auto* self = static_cast<Window*>(glfwGetWindowUserPointer(window));
|
||||
self->m_FramebufferResized = true;
|
||||
}
|
||||
|
||||
Window::Window(const std::string& title, u32 width, u32 height)
|
||||
: m_Width(width), m_Height(height), m_Title(title)
|
||||
{
|
||||
if (!glfwInit()) {
|
||||
if (!glfwInit())
|
||||
{
|
||||
ENGINE_FATAL("glfwInit failed");
|
||||
return;
|
||||
}
|
||||
|
||||
glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
|
||||
glfwWindowHint(GLFW_RESIZABLE, GLFW_FALSE);
|
||||
// glfwWindowHint(GLFW_RESIZABLE, GLFW_FALSE);
|
||||
|
||||
m_Window = glfwCreateWindow(width, height, title.c_str(), nullptr, nullptr);
|
||||
if (!m_Window) {
|
||||
if (!m_Window)
|
||||
{
|
||||
ENGINE_FATAL("glfwCreateWindow failed");
|
||||
glfwTerminate();
|
||||
return;
|
||||
}
|
||||
|
||||
ENGINE_INFO("Window created: {} ({}x{})", title, width, height);
|
||||
|
||||
// callbacks
|
||||
|
||||
glfwSetWindowUserPointer(m_Window, this);
|
||||
glfwSetFramebufferSizeCallback(m_Window, FramebufferResizeCallback);
|
||||
}
|
||||
|
||||
Window::~Window()
|
||||
{
|
||||
if (m_Window) {
|
||||
if (m_Window)
|
||||
{
|
||||
glfwDestroyWindow(m_Window);
|
||||
}
|
||||
glfwTerminate();
|
||||
@@ -52,7 +66,8 @@ namespace Engine {
|
||||
vk::SurfaceKHR Window::CreateSurface(vk::Instance instance)
|
||||
{
|
||||
VkSurfaceKHR surface;
|
||||
if (glfwCreateWindowSurface(instance, m_Window, nullptr, &surface) != VK_SUCCESS) {
|
||||
if (glfwCreateWindowSurface(instance, m_Window, nullptr, &surface) != VK_SUCCESS)
|
||||
{
|
||||
ENGINE_FATAL("glfwCreateWindowSurface failed");
|
||||
return nullptr;
|
||||
}
|
||||
@@ -71,4 +86,38 @@ namespace Engine {
|
||||
return std::vector<const char*>(extensions, extensions + count);
|
||||
}
|
||||
|
||||
} // namespace Engine
|
||||
void Window::GetFramebufferSize(int& width, int& height) const
|
||||
{
|
||||
glfwGetFramebufferSize(m_Window, &width, &height);
|
||||
}
|
||||
|
||||
bool Window::IsKeyPressed(int key) const
|
||||
{
|
||||
return glfwGetKey(m_Window, key) == GLFW_PRESS;
|
||||
}
|
||||
|
||||
void Window::GetMouseDelta(float& dx, float& dy)
|
||||
{
|
||||
double mx, my;
|
||||
glfwGetCursorPos(m_Window, &mx, &my);
|
||||
|
||||
static double lastX = mx;
|
||||
static double lastY = my;
|
||||
static bool first = true;
|
||||
|
||||
if (first)
|
||||
{
|
||||
lastX = mx;
|
||||
lastY = my;
|
||||
first = false;
|
||||
dx = dy = 0.0f;
|
||||
return;
|
||||
}
|
||||
|
||||
dx = static_cast<float>(mx - lastX);
|
||||
dy = static_cast<float>(my - lastY);
|
||||
|
||||
lastX = mx;
|
||||
lastY = my;
|
||||
}
|
||||
} // namespace Engine
|
||||
|
||||
Reference in New Issue
Block a user