Optimize geometry updates and cache text buffers
Update geometry only periodically (every 5 frames) and reduce logging frequency. Destroy and null out old buffers before recreating them to avoid double frees and leaks. Cache lastRenderedText and only rebuild text vertex/index buffers when the content or size changes; reuse buffers across frames and clean them up on rebuild or shutdown. Replace vkDeviceWaitIdle in copyBuffer with fence-based wait (longer timeout) and remove noisy debug prints. Added members and cleanup for text buffers and index count
This commit is contained in:
parent
95b83d5ed3
commit
fdb25ed816
|
|
@ -53,6 +53,11 @@ VulkanRenderer::VulkanRenderer()
|
||||||
, m_fontTextureMemory(VK_NULL_HANDLE)
|
, m_fontTextureMemory(VK_NULL_HANDLE)
|
||||||
, m_fontTextureView(VK_NULL_HANDLE)
|
, m_fontTextureView(VK_NULL_HANDLE)
|
||||||
, m_fontSampler(VK_NULL_HANDLE)
|
, m_fontSampler(VK_NULL_HANDLE)
|
||||||
|
, m_textVertexBuffer(VK_NULL_HANDLE)
|
||||||
|
, m_textVertexMemory(VK_NULL_HANDLE)
|
||||||
|
, m_textIndexBuffer(VK_NULL_HANDLE)
|
||||||
|
, m_textIndexMemory(VK_NULL_HANDLE)
|
||||||
|
, m_textIndexCount(0)
|
||||||
, m_msaaImage(VK_NULL_HANDLE)
|
, m_msaaImage(VK_NULL_HANDLE)
|
||||||
, m_msaaImageMemory(VK_NULL_HANDLE)
|
, m_msaaImageMemory(VK_NULL_HANDLE)
|
||||||
, m_msaaImageView(VK_NULL_HANDLE)
|
, m_msaaImageView(VK_NULL_HANDLE)
|
||||||
|
|
@ -372,6 +377,11 @@ void VulkanRenderer::cleanup()
|
||||||
if (m_backgroundVertexMemory) vkFreeMemory(m_device, m_backgroundVertexMemory, nullptr);
|
if (m_backgroundVertexMemory) vkFreeMemory(m_device, m_backgroundVertexMemory, nullptr);
|
||||||
if (m_backgroundIndexBuffer) vkDestroyBuffer(m_device, m_backgroundIndexBuffer, nullptr);
|
if (m_backgroundIndexBuffer) vkDestroyBuffer(m_device, m_backgroundIndexBuffer, nullptr);
|
||||||
if (m_backgroundIndexMemory) vkFreeMemory(m_device, m_backgroundIndexMemory, nullptr);
|
if (m_backgroundIndexMemory) vkFreeMemory(m_device, m_backgroundIndexMemory, nullptr);
|
||||||
|
|
||||||
|
if (m_textVertexBuffer) vkDestroyBuffer(m_device, m_textVertexBuffer, nullptr);
|
||||||
|
if (m_textVertexMemory) vkFreeMemory(m_device, m_textVertexMemory, nullptr);
|
||||||
|
if (m_textIndexBuffer) vkDestroyBuffer(m_device, m_textIndexBuffer, nullptr);
|
||||||
|
if (m_textIndexMemory) vkFreeMemory(m_device, m_textIndexMemory, nullptr);
|
||||||
|
|
||||||
if (m_circleVertexBuffer) vkDestroyBuffer(m_device, m_circleVertexBuffer, nullptr);
|
if (m_circleVertexBuffer) vkDestroyBuffer(m_device, m_circleVertexBuffer, nullptr);
|
||||||
if (m_circleVertexMemory) vkFreeMemory(m_device, m_circleVertexMemory, nullptr);
|
if (m_circleVertexMemory) vkFreeMemory(m_device, m_circleVertexMemory, nullptr);
|
||||||
|
|
@ -487,31 +497,54 @@ void VulkanRenderer::recordCommandBuffer(VkCommandBuffer commandBuffer,
|
||||||
paintingEnabled = false;
|
paintingEnabled = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update geometry buffers BEFORE recording commands
|
// Update geometry buffers periodically (every 5 frames) to maintain animation
|
||||||
if (paintingEnabled) {
|
// 修复:不要每帧重建 buffers,但需要定期更新以保持动画效果
|
||||||
|
static int geometryUpdateCounter = 0;
|
||||||
|
bool shouldUpdateGeometry = (paintingEnabled &&
|
||||||
|
(m_circleVertexBuffer == VK_NULL_HANDLE ||
|
||||||
|
(++geometryUpdateCounter % 5) == 0));
|
||||||
|
|
||||||
|
if (shouldUpdateGeometry) {
|
||||||
std::vector<Vertex> circleVertices, waveVertices;
|
std::vector<Vertex> circleVertices, waveVertices;
|
||||||
std::vector<uint16_t> circleIndices, waveIndices;
|
std::vector<uint16_t> circleIndices, waveIndices;
|
||||||
|
|
||||||
// Debug: Print dimensions used for geometry generation
|
static int geomCreateCounter = 0;
|
||||||
static int geomDebugCounter = 0;
|
if (geomCreateCounter++ % 60 == 0) { // Log every 60 updates (~12 seconds at 60fps)
|
||||||
if (geomDebugCounter++ % 300 == 0) { // Every ~5 seconds at 60fps
|
std::cout << "Updating geometry buffers (#" << geomCreateCounter
|
||||||
std::cout << "VulkanRenderer geometry generation using: "
|
<< ") for: " << m_width << "x" << m_height << std::endl;
|
||||||
<< m_width << "x" << m_height << std::endl;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 生成动态几何体(使用当前动画参数)
|
||||||
generateRotatingCircles(circleVertices, circleIndices, rotationAngle);
|
generateRotatingCircles(circleVertices, circleIndices, rotationAngle);
|
||||||
generateWaveEffect(waveVertices, waveIndices, wavePhase);
|
generateWaveEffect(waveVertices, waveIndices, wavePhase);
|
||||||
|
|
||||||
// Update or create circle buffers
|
// Cleanup old buffers before creating new ones
|
||||||
if (m_circleVertexBuffer) {
|
if (m_circleVertexBuffer) {
|
||||||
vkDestroyBuffer(m_device, m_circleVertexBuffer, nullptr);
|
vkDestroyBuffer(m_device, m_circleVertexBuffer, nullptr);
|
||||||
vkFreeMemory(m_device, m_circleVertexMemory, nullptr);
|
vkFreeMemory(m_device, m_circleVertexMemory, nullptr);
|
||||||
|
m_circleVertexBuffer = VK_NULL_HANDLE;
|
||||||
|
m_circleVertexMemory = VK_NULL_HANDLE;
|
||||||
}
|
}
|
||||||
if (m_circleIndexBuffer) {
|
if (m_circleIndexBuffer) {
|
||||||
vkDestroyBuffer(m_device, m_circleIndexBuffer, nullptr);
|
vkDestroyBuffer(m_device, m_circleIndexBuffer, nullptr);
|
||||||
vkFreeMemory(m_device, m_circleIndexMemory, nullptr);
|
vkFreeMemory(m_device, m_circleIndexMemory, nullptr);
|
||||||
|
m_circleIndexBuffer = VK_NULL_HANDLE;
|
||||||
|
m_circleIndexMemory = VK_NULL_HANDLE;
|
||||||
|
}
|
||||||
|
if (m_waveVertexBuffer) {
|
||||||
|
vkDestroyBuffer(m_device, m_waveVertexBuffer, nullptr);
|
||||||
|
vkFreeMemory(m_device, m_waveVertexMemory, nullptr);
|
||||||
|
m_waveVertexBuffer = VK_NULL_HANDLE;
|
||||||
|
m_waveVertexMemory = VK_NULL_HANDLE;
|
||||||
|
}
|
||||||
|
if (m_waveIndexBuffer) {
|
||||||
|
vkDestroyBuffer(m_device, m_waveIndexBuffer, nullptr);
|
||||||
|
vkFreeMemory(m_device, m_waveIndexMemory, nullptr);
|
||||||
|
m_waveIndexBuffer = VK_NULL_HANDLE;
|
||||||
|
m_waveIndexMemory = VK_NULL_HANDLE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Create circle buffers (only once)
|
||||||
if (!createVertexBuffer(circleVertices, m_circleVertexBuffer, m_circleVertexMemory)) {
|
if (!createVertexBuffer(circleVertices, m_circleVertexBuffer, m_circleVertexMemory)) {
|
||||||
logError("Failed to create circle vertex buffer - skipping geometry rendering");
|
logError("Failed to create circle vertex buffer - skipping geometry rendering");
|
||||||
m_circleVertexBuffer = VK_NULL_HANDLE;
|
m_circleVertexBuffer = VK_NULL_HANDLE;
|
||||||
|
|
@ -520,22 +553,17 @@ void VulkanRenderer::recordCommandBuffer(VkCommandBuffer commandBuffer,
|
||||||
}
|
}
|
||||||
if (!createIndexBuffer(circleIndices, m_circleIndexBuffer, m_circleIndexMemory)) {
|
if (!createIndexBuffer(circleIndices, m_circleIndexBuffer, m_circleIndexMemory)) {
|
||||||
logError("Failed to create circle index buffer - skipping geometry rendering");
|
logError("Failed to create circle index buffer - skipping geometry rendering");
|
||||||
|
vkDestroyBuffer(m_device, m_circleVertexBuffer, nullptr);
|
||||||
|
vkFreeMemory(m_device, m_circleVertexMemory, nullptr);
|
||||||
|
m_circleVertexBuffer = VK_NULL_HANDLE;
|
||||||
|
m_circleVertexMemory = VK_NULL_HANDLE;
|
||||||
m_circleIndexBuffer = VK_NULL_HANDLE;
|
m_circleIndexBuffer = VK_NULL_HANDLE;
|
||||||
m_circleIndexMemory = VK_NULL_HANDLE;
|
m_circleIndexMemory = VK_NULL_HANDLE;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
m_circleIndexCount = circleIndices.size();
|
m_circleIndexCount = circleIndices.size();
|
||||||
|
|
||||||
// Update or create wave buffers
|
// Create wave buffers (only once)
|
||||||
if (m_waveVertexBuffer) {
|
|
||||||
vkDestroyBuffer(m_device, m_waveVertexBuffer, nullptr);
|
|
||||||
vkFreeMemory(m_device, m_waveVertexMemory, nullptr);
|
|
||||||
}
|
|
||||||
if (m_waveIndexBuffer) {
|
|
||||||
vkDestroyBuffer(m_device, m_waveIndexBuffer, nullptr);
|
|
||||||
vkFreeMemory(m_device, m_waveIndexMemory, nullptr);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!createVertexBuffer(waveVertices, m_waveVertexBuffer, m_waveVertexMemory)) {
|
if (!createVertexBuffer(waveVertices, m_waveVertexBuffer, m_waveVertexMemory)) {
|
||||||
logError("Failed to create wave vertex buffer - skipping geometry rendering");
|
logError("Failed to create wave vertex buffer - skipping geometry rendering");
|
||||||
m_waveVertexBuffer = VK_NULL_HANDLE;
|
m_waveVertexBuffer = VK_NULL_HANDLE;
|
||||||
|
|
@ -544,6 +572,10 @@ void VulkanRenderer::recordCommandBuffer(VkCommandBuffer commandBuffer,
|
||||||
}
|
}
|
||||||
if (!createIndexBuffer(waveIndices, m_waveIndexBuffer, m_waveIndexMemory)) {
|
if (!createIndexBuffer(waveIndices, m_waveIndexBuffer, m_waveIndexMemory)) {
|
||||||
logError("Failed to create wave index buffer - skipping geometry rendering");
|
logError("Failed to create wave index buffer - skipping geometry rendering");
|
||||||
|
vkDestroyBuffer(m_device, m_waveVertexBuffer, nullptr);
|
||||||
|
vkFreeMemory(m_device, m_waveVertexMemory, nullptr);
|
||||||
|
m_waveVertexBuffer = VK_NULL_HANDLE;
|
||||||
|
m_waveVertexMemory = VK_NULL_HANDLE;
|
||||||
m_waveIndexBuffer = VK_NULL_HANDLE;
|
m_waveIndexBuffer = VK_NULL_HANDLE;
|
||||||
m_waveIndexMemory = VK_NULL_HANDLE;
|
m_waveIndexMemory = VK_NULL_HANDLE;
|
||||||
return;
|
return;
|
||||||
|
|
@ -1889,10 +1921,7 @@ bool VulkanRenderer::copyBuffer(VkBuffer srcBuffer, VkBuffer dstBuffer, uint64_t
|
||||||
// Note: 移除 vkDeviceWaitIdle,改用 fence 精确同步
|
// Note: 移除 vkDeviceWaitIdle,改用 fence 精确同步
|
||||||
// vkDeviceWaitIdle 在三缓冲场景下会导致等待失败
|
// vkDeviceWaitIdle 在三缓冲场景下会导致等待失败
|
||||||
// 因为双缓冲的 fence 机制只能确保 2 帧的同步
|
// 因为双缓冲的 fence 机制只能确保 2 帧的同步
|
||||||
|
|
||||||
static int copyCount = 0;
|
|
||||||
std::cout << "copyBuffer called (#" << copyCount++ << "), size=" << size
|
|
||||||
<< " bytes" << std::endl;
|
|
||||||
|
|
||||||
// Create a one-time command pool if not exists
|
// Create a one-time command pool if not exists
|
||||||
if (m_transferCommandPool == VK_NULL_HANDLE) {
|
if (m_transferCommandPool == VK_NULL_HANDLE) {
|
||||||
|
|
@ -1976,8 +2005,6 @@ bool VulkanRenderer::copyBuffer(VkBuffer srcBuffer, VkBuffer dstBuffer, uint64_t
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::cout << "Waiting for fence (timeout=5s)..." << std::endl;
|
|
||||||
|
|
||||||
// Wait for the fence with extended timeout for triple buffering (5 seconds)
|
// Wait for the fence with extended timeout for triple buffering (5 seconds)
|
||||||
// 三缓冲场景下需要更长的等待时间,因为可能有多帧在 GPU 执行
|
// 三缓冲场景下需要更长的等待时间,因为可能有多帧在 GPU 执行
|
||||||
result = vkWaitForFences(m_device, 1, &fence, VK_TRUE, 5000000000ULL); // 5 seconds in nanoseconds
|
result = vkWaitForFences(m_device, 1, &fence, VK_TRUE, 5000000000ULL); // 5 seconds in nanoseconds
|
||||||
|
|
@ -1994,8 +2021,6 @@ bool VulkanRenderer::copyBuffer(VkBuffer srcBuffer, VkBuffer dstBuffer, uint64_t
|
||||||
vkFreeCommandBuffers(m_device, m_transferCommandPool, 1, &commandBuffer);
|
vkFreeCommandBuffers(m_device, m_transferCommandPool, 1, &commandBuffer);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::cout << "copyBuffer completed successfully" << std::endl;
|
|
||||||
|
|
||||||
// Cleanup fence
|
// Cleanup fence
|
||||||
vkDestroyFence(m_device, fence, nullptr);
|
vkDestroyFence(m_device, fence, nullptr);
|
||||||
|
|
@ -2636,6 +2661,36 @@ void VulkanRenderer::drawText(VkCommandBuffer commandBuffer, int frameCount,
|
||||||
return; // Text rendering not available
|
return; // Text rendering not available
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 构建当前帧的文本内容(用于缓存比较)
|
||||||
|
std::string currentText = lockInfo + "|" + std::to_string(paintingEnabled) + "|"
|
||||||
|
+ std::to_string(m_width) + "x" + std::to_string(m_height);
|
||||||
|
|
||||||
|
// 检查文本是否变化,只在变化时重建 buffers
|
||||||
|
bool needsRebuild = (currentText != m_lastRenderedText) || (m_textVertexBuffer == VK_NULL_HANDLE);
|
||||||
|
|
||||||
|
// 如果文本没有变化且 buffers 已存在,直接使用缓存的 buffers
|
||||||
|
if (!needsRebuild && m_textVertexBuffer != VK_NULL_HANDLE && m_textIndexBuffer != VK_NULL_HANDLE) {
|
||||||
|
// Bind text pipeline
|
||||||
|
vkCmdBindPipeline(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, m_textPipeline);
|
||||||
|
|
||||||
|
// Bind descriptor sets for text rendering (if using textures)
|
||||||
|
if (!m_descriptorSets.empty()) {
|
||||||
|
vkCmdBindDescriptorSets(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS,
|
||||||
|
m_textPipelineLayout, 0, 1,
|
||||||
|
&m_descriptorSets[0], 0, nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Draw text using cached buffers
|
||||||
|
VkBuffer vertexBuffers[] = {m_textVertexBuffer};
|
||||||
|
VkDeviceSize offsets[] = {0};
|
||||||
|
vkCmdBindVertexBuffers(commandBuffer, 0, 1, vertexBuffers, offsets);
|
||||||
|
vkCmdBindIndexBuffer(commandBuffer, m_textIndexBuffer, 0, VK_INDEX_TYPE_UINT16);
|
||||||
|
vkCmdDrawIndexed(commandBuffer, m_textIndexCount, 1, 0, 0, 0);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 文本变化了,需要重建 buffers
|
||||||
|
|
||||||
// Bind text pipeline
|
// Bind text pipeline
|
||||||
vkCmdBindPipeline(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, m_textPipeline);
|
vkCmdBindPipeline(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, m_textPipeline);
|
||||||
|
|
||||||
|
|
@ -2743,7 +2798,7 @@ void VulkanRenderer::drawText(VkCommandBuffer commandBuffer, int frameCount,
|
||||||
generateTextQuads(hint, hintX, m_height - 50.0f * scaleY, hintScale, yellow, vertices, indices);
|
generateTextQuads(hint, hintX, m_height - 50.0f * scaleY, hintScale, yellow, vertices, indices);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create temporary buffers for text
|
// Create/update text buffers
|
||||||
if (vertices.empty() || indices.empty()) {
|
if (vertices.empty() || indices.empty()) {
|
||||||
if (textDebugCounter % 300 == 1) {
|
if (textDebugCounter % 300 == 1) {
|
||||||
std::cout << "No text vertices generated - skipping" << std::endl;
|
std::cout << "No text vertices generated - skipping" << std::endl;
|
||||||
|
|
@ -2751,7 +2806,7 @@ void VulkanRenderer::drawText(VkCommandBuffer commandBuffer, int frameCount,
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (textDebugCounter % 300 == 1) {
|
if (textDebugCounter % 300 == 1 || needsRebuild) {
|
||||||
std::cout << "Drawing text with " << vertices.size() << " vertices, "
|
std::cout << "Drawing text with " << vertices.size() << " vertices, "
|
||||||
<< indices.size() << " indices" << std::endl;
|
<< indices.size() << " indices" << std::endl;
|
||||||
std::cout << "Window size: " << m_width << "x" << m_height << std::endl;
|
std::cout << "Window size: " << m_width << "x" << m_height << std::endl;
|
||||||
|
|
@ -2762,47 +2817,45 @@ void VulkanRenderer::drawText(VkCommandBuffer commandBuffer, int frameCount,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Use static buffers for text rendering to avoid recreating every frame
|
// Cleanup old buffers if they exist (only when rebuilding)
|
||||||
static VkBuffer textVertexBuffer = VK_NULL_HANDLE;
|
if (m_textVertexBuffer != VK_NULL_HANDLE) {
|
||||||
static VkDeviceMemory textVertexMemory = VK_NULL_HANDLE;
|
vkDestroyBuffer(m_device, m_textVertexBuffer, nullptr);
|
||||||
static VkBuffer textIndexBuffer = VK_NULL_HANDLE;
|
vkFreeMemory(m_device, m_textVertexMemory, nullptr);
|
||||||
static VkDeviceMemory textIndexMemory = VK_NULL_HANDLE;
|
m_textVertexBuffer = VK_NULL_HANDLE;
|
||||||
|
m_textVertexMemory = VK_NULL_HANDLE;
|
||||||
// Cleanup old buffers if they exist
|
|
||||||
if (textVertexBuffer != VK_NULL_HANDLE) {
|
|
||||||
vkDestroyBuffer(m_device, textVertexBuffer, nullptr);
|
|
||||||
vkFreeMemory(m_device, textVertexMemory, nullptr);
|
|
||||||
textVertexBuffer = VK_NULL_HANDLE;
|
|
||||||
textVertexMemory = VK_NULL_HANDLE;
|
|
||||||
}
|
}
|
||||||
if (textIndexBuffer != VK_NULL_HANDLE) {
|
if (m_textIndexBuffer != VK_NULL_HANDLE) {
|
||||||
vkDestroyBuffer(m_device, textIndexBuffer, nullptr);
|
vkDestroyBuffer(m_device, m_textIndexBuffer, nullptr);
|
||||||
vkFreeMemory(m_device, textIndexMemory, nullptr);
|
vkFreeMemory(m_device, m_textIndexMemory, nullptr);
|
||||||
textIndexBuffer = VK_NULL_HANDLE;
|
m_textIndexBuffer = VK_NULL_HANDLE;
|
||||||
textIndexMemory = VK_NULL_HANDLE;
|
m_textIndexMemory = VK_NULL_HANDLE;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!createVertexBuffer(vertices, textVertexBuffer, textVertexMemory)) {
|
if (!createVertexBuffer(vertices, m_textVertexBuffer, m_textVertexMemory)) {
|
||||||
logError("Failed to create text vertex buffer - skipping text rendering");
|
logError("Failed to create text vertex buffer - skipping text rendering");
|
||||||
|
m_lastRenderedText.clear(); // 标记为无效,下次重试
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!createIndexBuffer(indices, textIndexBuffer, textIndexMemory)) {
|
if (!createIndexBuffer(indices, m_textIndexBuffer, m_textIndexMemory)) {
|
||||||
logError("Failed to create text index buffer - skipping text rendering");
|
logError("Failed to create text index buffer - skipping text rendering");
|
||||||
vkDestroyBuffer(m_device, textVertexBuffer, nullptr);
|
vkDestroyBuffer(m_device, m_textVertexBuffer, nullptr);
|
||||||
vkFreeMemory(m_device, textVertexMemory, nullptr);
|
vkFreeMemory(m_device, m_textVertexMemory, nullptr);
|
||||||
|
m_textVertexBuffer = VK_NULL_HANDLE;
|
||||||
|
m_textVertexMemory = VK_NULL_HANDLE;
|
||||||
|
m_lastRenderedText.clear(); // 标记为无效,下次重试
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Draw text
|
m_textIndexCount = indices.size();
|
||||||
VkBuffer vertexBuffers[] = {textVertexBuffer};
|
m_lastRenderedText = currentText; // 缓存当前文本内容
|
||||||
|
|
||||||
|
// Draw text with newly created buffers
|
||||||
|
VkBuffer vertexBuffers[] = {m_textVertexBuffer};
|
||||||
VkDeviceSize offsets[] = {0};
|
VkDeviceSize offsets[] = {0};
|
||||||
vkCmdBindVertexBuffers(commandBuffer, 0, 1, vertexBuffers, offsets);
|
vkCmdBindVertexBuffers(commandBuffer, 0, 1, vertexBuffers, offsets);
|
||||||
vkCmdBindIndexBuffer(commandBuffer, textIndexBuffer, 0, VK_INDEX_TYPE_UINT16);
|
vkCmdBindIndexBuffer(commandBuffer, m_textIndexBuffer, 0, VK_INDEX_TYPE_UINT16);
|
||||||
vkCmdDrawIndexed(commandBuffer, indices.size(), 1, 0, 0, 0);
|
vkCmdDrawIndexed(commandBuffer, m_textIndexCount, 1, 0, 0, 0);
|
||||||
|
|
||||||
// Note: Buffers will persist and be reused next frame
|
|
||||||
// They will be cleaned up when the function is called again or at shutdown
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void VulkanRenderer::logError(const char* message)
|
void VulkanRenderer::logError(const char* message)
|
||||||
|
|
|
||||||
|
|
@ -368,6 +368,14 @@ private:
|
||||||
VkImageView m_fontTextureView;
|
VkImageView m_fontTextureView;
|
||||||
VkSampler m_fontSampler;
|
VkSampler m_fontSampler;
|
||||||
std::map<char, CharInfo> m_charInfoMap;
|
std::map<char, CharInfo> m_charInfoMap;
|
||||||
|
|
||||||
|
// 文本缓存,避免每帧重建 text buffers
|
||||||
|
std::string m_lastRenderedText;
|
||||||
|
VkBuffer m_textVertexBuffer;
|
||||||
|
VkDeviceMemory m_textVertexMemory;
|
||||||
|
VkBuffer m_textIndexBuffer;
|
||||||
|
VkDeviceMemory m_textIndexMemory;
|
||||||
|
uint32_t m_textIndexCount;
|
||||||
|
|
||||||
// MSAA 资源
|
// MSAA 资源
|
||||||
VkImage m_msaaImage;
|
VkImage m_msaaImage;
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue