В настоящее время я пытаюсь изменить программу Vulkan-Tutorial в рендерерал для моего игрового двигателя, но столкнулся с проблемами, когда мой рендерин медленно потребляет постоянно растущее количество оперативной памяти с течением времени, особенно если я рендеринг тысячи сетей ( Все они являются экземплярами одной и той же сетки на данный момент). < /p>
Прилагается мой код рендеринга (вся инициализация и другие не связанные материалы опущены): < /p>
const int MAX_FRAMES_IN_FLIGHT = 2;
void VulkanRenderer::recordCommandBuffer(VkCommandBuffer commandBuffer, uint32_t imageIndex) {
VkCommandBufferBeginInfo beginInfo = {};
beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
VkResult result = vkBeginCommandBuffer(commandBuffer, &beginInfo);
if (result != VK_SUCCESS) {
throw std::runtime_error("Failed to begin recording command buffer!");
}
VkRenderPassBeginInfo renderPassInfo = {};
renderPassInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
renderPassInfo.renderPass = app.renderPass;
renderPassInfo.framebuffer = app.swapChainFramebuffers[imageIndex];
renderPassInfo.renderArea.offset = { 0, 0 };
renderPassInfo.renderArea.extent = app.swapChainExtent;
std::array clearValues = {};
clearValues[0].color = { { 0.0f, 0.0f, 0.0f, 1.0f } };
clearValues[1].depthStencil = { 1.0f, 0 };
renderPassInfo.clearValueCount = static_cast(clearValues.size());
renderPassInfo.pClearValues = clearValues.data();
vkCmdBeginRenderPass(commandBuffer, &renderPassInfo, VK_SUBPASS_CONTENTS_INLINE);
vkCmdBindPipeline(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, app.graphicsPipeline);
// Bind the global UBO descriptor set (set 0) for view/projection
vkCmdBindDescriptorSets(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS,
app.pipelineLayout, 0, 1, &app.globalDescriptorSets[imageIndex],
0, nullptr);
// Iterate over all objects with a MeshComponent and Transform
// This is basically a wrapper for entt's registry.view() function
ObjectManager::Instance().forEachObjectWithComponents([&](MeshComponent& meshComp, Transform& transform) {
// Retrieve (or create) the mesh buffer. (Assumes that AssetManager::meshCache contains a Mesh for meshComp.uuid.)
Mesh& mesh = AssetManager::Instance().meshCache[meshComp.uuid];
VulkanMeshBuffer* meshBuffer = CreateMeshBuffer(meshComp.uuid, mesh);
// Bind vertex and index buffers
VkBuffer vertexBuffers[] = { meshBuffer->vertexBuffer };
VkDeviceSize offsets[] = { 0 };
vkCmdBindVertexBuffers(commandBuffer, 0, 1, vertexBuffers, offsets);
vkCmdBindIndexBuffer(commandBuffer, meshBuffer->indexBuffer, 0, VK_INDEX_TYPE_UINT32);
// Retrieve texture resources for this object’s texture and bind them (set 1)
TextureResource* texRes = getTextureResource(meshComp.TextureUUID);
vkCmdBindDescriptorSets(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS,
app.pipelineLayout, 1, 1, &texRes->descriptorSet,
0, nullptr);
// Compute the model matrix from the Transform component:
glm::mat4 model = glm::translate(glm::mat4(1.0f), transform.position);
model = glm::rotate(model, transform.rotation.x, glm::vec3(1, 0, 0));
model = glm::rotate(model, transform.rotation.y, glm::vec3(0, 1, 0));
model = glm::rotate(model, transform.rotation.z, glm::vec3(0, 0, 1));
model = glm::scale(model, transform.scale);
// Push the model matrix as a push constant (the range was set in the pipeline layout)
vkCmdPushConstants(commandBuffer, app.pipelineLayout, VK_SHADER_STAGE_VERTEX_BIT, 0, sizeof(glm::mat4), &model);
// Issue the draw call (using the index count from the mesh)
vkCmdDrawIndexed(commandBuffer, static_cast(mesh.indices.size()), 1, 0, 0, 0);
});
vkCmdEndRenderPass(commandBuffer);
result = vkEndCommandBuffer(commandBuffer);
if (result != VK_SUCCESS) {
throw VulkanError("Failed to record command buffer!", result);
}
}
void VulkanRenderer::updateUniformBuffer(uint32_t currentImage) {
GlobalUBO ubo = {};
ubo.view = glm::lookAt(glm::vec3(10.0f, 10.0f, 10.0f),
glm::vec3(0.0f, 0.0f, 0.0f),
glm::vec3(0.0f, 1.0f, 0.0f));
ubo.proj = glm::perspective(glm::radians(45.0f),
app.swapChainExtent.width / (float)app.swapChainExtent.height,
0.001f, 1000.0f);
ubo.proj[1][1] *= -1; // Flip Y-axis for Vulkan
void* data;
vkMapMemory(app.device, app.uniformBuffersMemory[currentImage], 0, sizeof(ubo), 0, &data);
memcpy(data, &ubo, sizeof(ubo));
vkUnmapMemory(app.device, app.uniformBuffersMemory[currentImage]);
}
void VulkanRenderer::drawFrame() {
vkWaitForFences(app.device, 1, &app.inFlightFences[app.currentFrame], VK_TRUE, UINT64_MAX);
vkResetFences(app.device, 1, &app.inFlightFences[app.currentFrame]);
uint32_t imageIndex;
vkAcquireNextImageKHR(app.device, app.swapChain, UINT64_MAX, app.imageAvailableSemaphores[app.currentFrame], VK_NULL_HANDLE, &imageIndex);
// Update the uniform buffer for the current image
updateUniformBuffer(imageIndex);
// Check if a previous frame is still using this image
if (app.imagesInFlight[imageIndex] != VK_NULL_HANDLE) {
vkWaitForFences(app.device, 1, &app.imagesInFlight[imageIndex], VK_TRUE, UINT64_MAX);
}
// Mark the image as now being in use by this frame
app.imagesInFlight[imageIndex] = app.inFlightFences[app.currentFrame];
// Re-record the command buffer for this frame.
vkResetCommandBuffer(app.commandBuffers[imageIndex], 0);
recordCommandBuffer(app.commandBuffers[imageIndex], imageIndex);
VkSubmitInfo submitInfo = {};
submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
VkSemaphore waitSemaphores[] = { app.imageAvailableSemaphores[app.currentFrame] };
VkPipelineStageFlags waitStages[] = { VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT };
submitInfo.waitSemaphoreCount = 1;
submitInfo.pWaitSemaphores = waitSemaphores;
submitInfo.pWaitDstStageMask = waitStages;
submitInfo.commandBufferCount = 1;
submitInfo.pCommandBuffers = &app.commandBuffers[imageIndex];
VkSemaphore signalSemaphores[] = { app.renderFinishedSemaphores[app.currentFrame] };
submitInfo.signalSemaphoreCount = 1;
submitInfo.pSignalSemaphores = signalSemaphores;
if (vkQueueSubmit(app.graphicsQueue, 1, &submitInfo, app.inFlightFences[app.currentFrame]) != VK_SUCCESS) {
throw std::runtime_error("Failed to submit draw command buffer!");
}
VkPresentInfoKHR presentInfo = {};
presentInfo.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR;
presentInfo.waitSemaphoreCount = 1;
presentInfo.pWaitSemaphores = signalSemaphores;
VkSwapchainKHR swapChains[] = { app.swapChain };
presentInfo.swapchainCount = 1;
presentInfo.pSwapchains = swapChains;
presentInfo.pImageIndices = &imageIndex;
VkResult result = vkQueuePresentKHR(app.presentQueue, &presentInfo);
if (result == VK_ERROR_OUT_OF_DATE_KHR || result == VK_SUBOPTIMAL_KHR || app.framebufferResized) {
app.framebufferResized = false; // Reset the resize flag
recreateSwapChain(); // Recreate the swap chain when necessary
}
else if (result != VK_SUCCESS) {
throw std::runtime_error("Failed to present swap chain image!");
}
app.currentFrame = (app.currentFrame + 1) % MAX_FRAMES_IN_FLIGHT;
}
void VulkanRenderer::Update()
{
last_frame_elapsed += Engine::Instance().GetDeltaTime();
if (last_frame_elapsed >= frame_time) {
drawFrame();
vkDeviceWaitIdle(app.device); // Wait until GPU finishes rendering
last_frame_elapsed = 0.0;
}
}
< /code>
Я где -то испортил? Потому что я не могу выяснить, какая часть моей программы сочетает память. На данный момент загружает модели < /p>
ObjectManager < /p>
#pragma once
#include "entt/entt.hpp"
#include
#include
#include "UUID.h"
#include "Object.h"
class ObjectManager {
public:
static ObjectManager& Instance();
ObjectManager(const ObjectManager&) = delete;
ObjectManager& operator=(const ObjectManager&) = delete;
// Method to create a new Object
Object createObject(const std::string& name);
template
void forEachObjectWithComponents(std::function func)
{
registry.view().each(func);
}
// Get all objects that have the following components
template
std::vector getObjectsWithComponents() {
std::vector objects;
for (auto entity : registry.view()) {
Object o;
o.entity_id = entity;
objects.push_back(o);
}
return objects;
}
// Method to remove an Object
void removeObject(Object obj);
// Component management with EnTT
template
T& addComponent(Object o, Args&&... args) {
return registry.emplace(o.entity_id, std::forward(args)...);
}
// Function to get a component
template
T* getComponent(Object o) {
return registry.try_get(o.entity_id);
}
// Function to remove a component
template
void removeComponent(Object o) {
ObjectManager::Instance().registry.remove(o.entity_id);
}
private:
ObjectManager() = default;
~ObjectManager() = default;
friend class Object;
Object getObjectFromEntity(entt::entity entity);
std::unordered_map uuidMap; // Map to store UUIDs to objects
std::unordered_map objectName; // Map to store object names
entt::registry registry;
};
< /code>
объект < /p>
#pragma once
#include "entt/entt.hpp"
#include
#include
// Object now serves as an interface to manage entities in EnTT
class Object {
public:
std::string GetName() const;
void SetName(const std::string& name);
// Needed for using Object as a key in std::unordered_map
bool operator==(const Object& other) const {
return entity_id == other.entity_id;
}
private:
Object() = default;
Object(entt::registry& registry);
friend struct std::hash;
friend class ObjectManager; // Needed to delete objects
entt::entity entity_id; // EnTT entity ID
};
// Needed for using Object as a key in std::unordered_map
namespace std {
template
struct hash {
std::size_t operator()(const Object& k) const {
return static_cast(k.entity_id);
}
};
}
< /code>
scenemanager (может заменить при необходимости) < /p>
// Temporary model and texture, will be replaced when we have a proper asset system
const std::string MODEL_PATH = "viking_room.obj";
const std::string TEXTURE_PATH = "viking_room.png";
const std::string LAPTOP = "Laptop_High-Polay_HP_BI_2_obj.obj";
SceneManager& SceneManager::Instance() {
static SceneManager instance;
return instance;
}
void SceneManager::LoadScene() {
// Load the scene
UUID mesh = AssetManager::Instance().loadModel(MODEL_PATH);
UUID texture = AssetManager::Instance().loadTexture(TEXTURE_PATH);
// Create a new object
Object obj = ObjectManager::Instance().createObject("Object");
MeshComponent& m = ObjectManager::Instance().addComponent(obj);
m.uuid = mesh;
m.TextureUUID = texture;
// Add transform component to allow manipulation of the object in the scene
ObjectManager::Instance().addComponent(obj);
Object obj2 = ObjectManager::Instance().createObject("Object2");
UUID mesh2 = AssetManager::Instance().loadModel(LAPTOP);
Transform& t2 = ObjectManager::Instance().addComponent(obj2);
MeshComponent& m2 = ObjectManager::Instance().addComponent(obj2);
m2.uuid = mesh2;
// Stress test
for (int i = 0; i < 10000; i++) {
Object objM = ObjectManager::Instance().createObject("ObjectM");
Transform& t3 = ObjectManager::Instance().addComponent(objM);
// Randomise the transform
t3.position = { (float)(rand() % 20) - 10, (float)(rand() % 20) - 10, (float)(rand() % 20) - 10 };
t3.scale = { 0.1f, 0.1f, 0.1f };
MeshComponent& m3 = ObjectManager::Instance().addComponent(objM);
m3.uuid = mesh2;
}
}
Подробнее здесь: https://stackoverflow.com/questions/794 ... ore-memory
Вулкан продолжает потреблять все больше и больше памяти [закрыто] ⇐ C++
-
- Похожие темы
- Ответы
- Просмотры
- Последнее сообщение