#include "vulkanwidget.h" #include "vulkanrenderer.h" #include #include #include #include #include #include #include #include #include #include // Include volk for Vulkan function loading #define VK_NO_PROTOTYPES #include "../../third_party/volk/volk.h" #ifndef M_PI #define M_PI 3.14159265358979323846 #endif // Platform-specific headers #ifdef _WIN32 #include #elif defined(__linux__) #include #endif VulkanWidget::VulkanWidget(QWidget *parent) : RenderWidgetBase(parent) , m_instance(VK_NULL_HANDLE) , m_physicalDevice(VK_NULL_HANDLE) , m_device(VK_NULL_HANDLE) , m_queue(VK_NULL_HANDLE) , m_surface(VK_NULL_HANDLE) , m_swapchain(VK_NULL_HANDLE) , m_commandPool(VK_NULL_HANDLE) , m_initialized(false) , m_renderingEnabled(false) , m_needsResize(false) , m_needsLockedFrameUpdate(false) , m_frameCount(0) , m_queueFamilyIndex(0) , m_currentFrame(0) , m_surfaceWidth(0) , m_surfaceHeight(0) , m_renderTimer(nullptr) , m_renderer(nullptr) , m_rotationAngle(0.0) , m_wavePhase(0.0) , m_startTime(QDateTime::currentDateTime()) , m_lastLockDuration(0) , m_lastLockFrameCount(0) , m_lockPaintFrameCount(0) , m_lockCount(0) , m_isClosing(false) , m_lastFrameTime(QDateTime::currentDateTime()) , m_currentFps(0.0) { // Set widget attributes for native window setAttribute(Qt::WA_NativeWindow); setAttribute(Qt::WA_PaintOnScreen); setAttribute(Qt::WA_OpaquePaintEvent); // Create render timer m_renderTimer = new QTimer(this); connect(m_renderTimer, &QTimer::timeout, this, &VulkanWidget::onRenderTimer); // Initialize FPS calculation m_frameTimes.reserve(FPS_SAMPLE_COUNT); qDebug() << "VulkanWidget created"; } VulkanWidget::~VulkanWidget() { qDebug() << "VulkanWidget destroying..."; if (m_renderTimer) { m_renderTimer->stop(); } // Clean up renderer first if (m_renderer) { m_renderer->cleanup(); delete m_renderer; m_renderer = nullptr; } cleanupVulkan(); qDebug() << "VulkanWidget destroyed"; } // 实现 RenderWidgetBase 接口 bool VulkanWidget::initializeRenderer() { return initializeVulkan(); } void VulkanWidget::setRenderingEnabled(bool enabled) { if (m_renderingEnabled == enabled) { return; } m_renderingEnabled = enabled; if (m_renderingEnabled) { qDebug() << "Vulkan rendering ENABLED - Resuming animations"; // 恢复渲染时,重新启动定时器(锁屏时已停止) if (!m_renderTimer->isActive()) { m_renderTimer->start(16); // ~60 FPS qDebug() << "Render timer restarted"; } // Unlocked: calculate lock duration if (m_lastLockTime.isValid()) { QDateTime unlockTime = QDateTime::currentDateTime(); m_lastLockDuration = m_lastLockTime.secsTo(unlockTime); m_lockPaintFrameCount = m_frameCount - m_lastLockFrameCount; qDebug() << "Screen was locked for" << m_lastLockDuration << "seconds"; qDebug() << "Frames at lock:" << m_lastLockFrameCount << "- Frames painted during lock:" << m_lockPaintFrameCount; } m_startTime = QDateTime::currentDateTime(); } else { qDebug() << "Vulkan rendering DISABLED - Showing locked state"; // 关键修复:渲染一帧锁屏界面后停止定时器 m_needsLockedFrameUpdate = true; // 标记需要渲染锁屏帧 // Locked: record lock time m_pauseTime = QDateTime::currentDateTime(); m_lastLockTime = m_pauseTime; m_lastLockFrameCount = m_frameCount; m_lockCount++; qDebug() << "Screen locked at" << m_lastLockTime.toString("yyyy-MM-dd hh:mm:ss") << "- Lock count:" << m_lockCount << "- Frame count at lock:" << m_lastLockFrameCount; } } bool VulkanWidget::isRenderingEnabled() const { return m_renderingEnabled; } int VulkanWidget::getRenderFrameCount() const { return m_frameCount; } void VulkanWidget::resetFrameCount() { m_frameCount = 0; qDebug() << "Vulkan frame count reset"; } QString VulkanWidget::getRendererType() const { return QString("Vulkan"); } bool VulkanWidget::initializeVulkan() { qDebug() << "Initializing Vulkan..."; if (m_initialized) { qDebug() << "Vulkan already initialized"; return true; } // Step 1: Initialize volk if (!initializeVolk()) { setError("Failed to initialize volk"); return false; } // Step 2: Create Vulkan instance if (!createInstance()) { setError("Failed to create Vulkan instance"); return false; } // Step 3: Create surface from native window if (!createSurface()) { setError("Failed to create Vulkan surface"); return false; } // Step 4: Select physical device if (!selectPhysicalDevice()) { setError("Failed to select physical device"); return false; } // Step 5: Create logical device if (!createDevice()) { setError("Failed to create logical device"); return false; } // Step 6: Create swapchain if (!createSwapchain()) { setError("Failed to create swapchain"); return false; } // Step 7: Create command objects if (!createCommandObjects()) { setError("Failed to create command objects"); return false; } // Step 8: Create synchronization objects if (!createSyncObjects()) { setError("Failed to create sync objects"); return false; } // Step 9: Create VulkanRenderer - but only if we have reasonable dimensions if (m_surfaceWidth >= 100 && m_surfaceHeight >= 100) { m_renderer = new VulkanRenderer(); // Get swapchain format VkSurfaceFormatKHR surfaceFormat; uint32_t formatCount = 0; vkGetPhysicalDeviceSurfaceFormatsKHR(m_physicalDevice, m_surface, &formatCount, nullptr); if (formatCount > 0) { std::vector formats(formatCount); vkGetPhysicalDeviceSurfaceFormatsKHR(m_physicalDevice, m_surface, &formatCount, formats.data()); surfaceFormat = formats[0]; } // Initialize renderer if (!m_renderer->initialize(m_device, m_physicalDevice, m_queue, m_queueFamilyIndex, static_cast(surfaceFormat.format), m_surfaceWidth, m_surfaceHeight)) { setError("Failed to initialize VulkanRenderer"); delete m_renderer; m_renderer = nullptr; return false; } qDebug() << "VulkanRenderer initialized successfully!"; qDebug() << "Widget size:" << width() << "x" << height() << "| Surface size:" << m_surfaceWidth << "x" << m_surfaceHeight; } else { qDebug() << "VulkanRenderer initialization deferred - window too small:" << m_surfaceWidth << "x" << m_surfaceHeight; } m_initialized = true; qDebug() << "Vulkan initialization successful!"; return true; } bool VulkanWidget::initializeVolk() { qDebug() << "Initializing volk..."; VkResult result = volkInitialize(); if (result != VK_SUCCESS) { qDebug() << "Failed to initialize volk, error code:" << result; return false; } qDebug() << "Volk initialized successfully"; return true; } bool VulkanWidget::createInstance() { qDebug() << "Creating Vulkan instance..."; VkApplicationInfo appInfo = {}; appInfo.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO; appInfo.pApplicationName = "VulkanWidget"; appInfo.applicationVersion = VK_MAKE_VERSION(1, 0, 0); appInfo.pEngineName = "No Engine"; appInfo.engineVersion = VK_MAKE_VERSION(1, 0, 0); appInfo.apiVersion = VK_API_VERSION_1_0; std::vector extensions = getRequiredInstanceExtensions(); VkInstanceCreateInfo createInfo = {}; createInfo.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO; createInfo.pApplicationInfo = &appInfo; createInfo.enabledExtensionCount = static_cast(extensions.size()); createInfo.ppEnabledExtensionNames = extensions.data(); createInfo.enabledLayerCount = 0; VkResult result = vkCreateInstance(&createInfo, nullptr, &m_instance); if (result != VK_SUCCESS) { qDebug() << "Failed to create Vulkan instance, error code:" << result; return false; } // Load instance-level functions volkLoadInstance(m_instance); qDebug() << "Vulkan instance created successfully"; return true; } bool VulkanWidget::createSurface() { qDebug() << "Creating Vulkan surface from native window..."; if (!windowHandle()) { qDebug() << "Window handle not available, creating window..."; create(); if (!windowHandle()) { qDebug() << "Failed to create window handle"; return false; } } QWindow *window = windowHandle(); #ifdef _WIN32 VkWin32SurfaceCreateInfoKHR createInfo = {}; createInfo.sType = VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR; createInfo.hwnd = reinterpret_cast(window->winId()); createInfo.hinstance = GetModuleHandle(nullptr); VkResult result = vkCreateWin32SurfaceKHR(m_instance, &createInfo, nullptr, &m_surface); #elif defined(__linux__) VkXlibSurfaceCreateInfoKHR createInfo = {}; createInfo.sType = VK_STRUCTURE_TYPE_XLIB_SURFACE_CREATE_INFO_KHR; // Get X11 display - use default display createInfo.dpy = XOpenDisplay(nullptr); if (!createInfo.dpy) { qDebug() << "Failed to open X11 display"; return false; } createInfo.window = static_cast(window->winId()); VkResult result = vkCreateXlibSurfaceKHR(m_instance, &createInfo, nullptr, &m_surface); #elif defined(__APPLE__) // macOS requires MoltenVK and Metal VkMetalSurfaceCreateInfoEXT createInfo = {}; createInfo.sType = VK_STRUCTURE_TYPE_METAL_SURFACE_CREATE_INFO_EXT; createInfo.pLayer = nullptr; // This needs proper Metal layer setup VkResult result = vkCreateMetalSurfaceEXT(m_instance, &createInfo, nullptr, &m_surface); #else qDebug() << "Unsupported platform for Vulkan surface creation"; return false; #endif if (result != VK_SUCCESS) { qDebug() << "Failed to create Vulkan surface, error code:" << result; return false; } qDebug() << "Vulkan surface created successfully"; return true; } bool VulkanWidget::selectPhysicalDevice() { qDebug() << "Selecting physical device..."; uint32_t deviceCount = 0; vkEnumeratePhysicalDevices(m_instance, &deviceCount, nullptr); if (deviceCount == 0) { qDebug() << "Failed to find GPUs with Vulkan support"; return false; } std::vector devices(deviceCount); vkEnumeratePhysicalDevices(m_instance, &deviceCount, devices.data()); // Select the first suitable device for (const auto& device : devices) { VkPhysicalDeviceProperties properties; vkGetPhysicalDeviceProperties(device, &properties); qDebug() << "Found device:" << properties.deviceName; // Temporarily set physical device to check queue families m_physicalDevice = device; // Check if device supports our queue family uint32_t queueFamilyIndex; if (findQueueFamily(queueFamilyIndex)) { m_queueFamilyIndex = queueFamilyIndex; qDebug() << "Selected device:" << properties.deviceName; return true; } } // Reset if no suitable device found m_physicalDevice = VK_NULL_HANDLE; qDebug() << "Failed to find suitable physical device"; return false; } bool VulkanWidget::findQueueFamily(uint32_t &queueFamilyIndex) { uint32_t queueFamilyCount = 0; vkGetPhysicalDeviceQueueFamilyProperties(m_physicalDevice, &queueFamilyCount, nullptr); std::vector queueFamilies(queueFamilyCount); vkGetPhysicalDeviceQueueFamilyProperties(m_physicalDevice, &queueFamilyCount, queueFamilies.data()); for (uint32_t i = 0; i < queueFamilyCount; i++) { // Check if queue family supports graphics if (queueFamilies[i].queueFlags & VK_QUEUE_GRAPHICS_BIT) { // Check if queue family supports presentation VkBool32 presentSupport = false; vkGetPhysicalDeviceSurfaceSupportKHR(m_physicalDevice, i, m_surface, &presentSupport); if (presentSupport) { queueFamilyIndex = i; return true; } } } return false; } bool VulkanWidget::createDevice() { qDebug() << "Creating logical device..."; float queuePriority = 1.0f; VkDeviceQueueCreateInfo queueCreateInfo = {}; queueCreateInfo.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO; queueCreateInfo.queueFamilyIndex = m_queueFamilyIndex; queueCreateInfo.queueCount = 1; queueCreateInfo.pQueuePriorities = &queuePriority; // Query supported features first VkPhysicalDeviceFeatures supportedFeatures; vkGetPhysicalDeviceFeatures(m_physicalDevice, &supportedFeatures); VkPhysicalDeviceFeatures deviceFeatures = {}; // Enable sample rate shading for better MSAA quality if (supportedFeatures.sampleRateShading) { deviceFeatures.sampleRateShading = VK_TRUE; qDebug() << "Sample rate shading feature enabled"; } else { qDebug() << "Sample rate shading not supported by device"; } // Enable wide lines if supported (for smoother line rendering) if (supportedFeatures.wideLines) { deviceFeatures.wideLines = VK_TRUE; qDebug() << "Wide lines feature enabled"; } std::vector deviceExtensions = getRequiredDeviceExtensions(); VkDeviceCreateInfo createInfo = {}; createInfo.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO; createInfo.pQueueCreateInfos = &queueCreateInfo; createInfo.queueCreateInfoCount = 1; createInfo.pEnabledFeatures = &deviceFeatures; createInfo.enabledExtensionCount = static_cast(deviceExtensions.size()); createInfo.ppEnabledExtensionNames = deviceExtensions.data(); createInfo.enabledLayerCount = 0; VkResult result = vkCreateDevice(m_physicalDevice, &createInfo, nullptr, &m_device); if (result != VK_SUCCESS) { qDebug() << "Failed to create logical device, error code:" << result; return false; } // Load device-level functions volkLoadDevice(m_device); // Get queue handle vkGetDeviceQueue(m_device, m_queueFamilyIndex, 0, &m_queue); qDebug() << "Logical device created successfully"; return true; } bool VulkanWidget::createSwapchain() { qDebug() << "Creating swapchain..."; qDebug() << "Widget size:" << width() << "x" << height(); qDebug() << "Device pixel ratio:" << devicePixelRatioF(); // Don't create swapchain if closing if (m_isClosing) { qDebug() << "Aborting swapchain creation - widget is closing"; return false; } // Query surface capabilities VkSurfaceCapabilitiesKHR capabilities; VkResult result = vkGetPhysicalDeviceSurfaceCapabilitiesKHR(m_physicalDevice, m_surface, &capabilities); if (result != VK_SUCCESS) { qDebug() << "Failed to get surface capabilities, error code:" << result; return false; } qDebug() << "Surface capabilities - current extent:" << capabilities.currentExtent.width << "x" << capabilities.currentExtent.height; qDebug() << "Surface capabilities - min extent:" << capabilities.minImageExtent.width << "x" << capabilities.minImageExtent.height; qDebug() << "Surface capabilities - max extent:" << capabilities.maxImageExtent.width << "x" << capabilities.maxImageExtent.height; // Validate surface capabilities - detect invalid/corrupted values // This can happen when the window is being destroyed if (capabilities.currentExtent.width > 16384 || capabilities.currentExtent.height > 16384 || capabilities.minImageExtent.width > 16384 || capabilities.minImageExtent.height > 16384 || capabilities.maxImageExtent.width > 1000000 || capabilities.maxImageExtent.height > 1000000) { qDebug() << "ERROR: Invalid surface capabilities detected - surface may be destroyed"; qDebug() << "This usually happens when the window is being closed"; return false; } // Query surface formats uint32_t formatCount; vkGetPhysicalDeviceSurfaceFormatsKHR(m_physicalDevice, m_surface, &formatCount, nullptr); std::vector formats(formatCount); vkGetPhysicalDeviceSurfaceFormatsKHR(m_physicalDevice, m_surface, &formatCount, formats.data()); // Query present modes uint32_t presentModeCount; vkGetPhysicalDeviceSurfacePresentModesKHR(m_physicalDevice, m_surface, &presentModeCount, nullptr); std::vector presentModes(presentModeCount); vkGetPhysicalDeviceSurfacePresentModesKHR(m_physicalDevice, m_surface, &presentModeCount, presentModes.data()); // Select format VkSurfaceFormatKHR surfaceFormat = formats[0]; for (const auto& format : formats) { if (format.format == VK_FORMAT_B8G8R8A8_SRGB && format.colorSpace == VK_COLOR_SPACE_SRGB_NONLINEAR_KHR) { surfaceFormat = format; break; } } // Select present mode (prefer mailbox, fallback to FIFO) VkPresentModeKHR presentMode = VK_PRESENT_MODE_FIFO_KHR; for (const auto& mode : presentModes) { if (mode == VK_PRESENT_MODE_MAILBOX_KHR) { presentMode = mode; break; } } // Determine extent VkExtent2D extent; if (capabilities.currentExtent.width != UINT32_MAX) { extent = capabilities.currentExtent; qDebug() << "Using surface-provided extent:" << extent.width << "x" << extent.height; } else { // Calculate extent based on widget size with DPI scaling uint32_t pixelWidth = static_cast(width() * devicePixelRatioF()); uint32_t pixelHeight = static_cast(height() * devicePixelRatioF()); extent.width = std::max(capabilities.minImageExtent.width, std::min(capabilities.maxImageExtent.width, pixelWidth)); extent.height = std::max(capabilities.minImageExtent.height, std::min(capabilities.maxImageExtent.height, pixelHeight)); qDebug() << "Calculated extent from widget:" << extent.width << "x" << extent.height << "(widget:" << width() << "x" << height() << "* DPR:" << devicePixelRatioF() << ")"; } m_surfaceWidth = extent.width; m_surfaceHeight = extent.height; qDebug() << "Final swapchain extent:" << m_surfaceWidth << "x" << m_surfaceHeight; // Determine image count - limit to MAX_FRAMES_IN_FLIGHT for proper synchronization uint32_t imageCount = capabilities.minImageCount + 1; if (capabilities.maxImageCount > 0 && imageCount > capabilities.maxImageCount) { imageCount = capabilities.maxImageCount; } // 确保不超过 MAX_FRAMES_IN_FLIGHT,避免三缓冲同步问题 if (imageCount > MAX_FRAMES_IN_FLIGHT) { qDebug() << "Limiting swapchain images from" << imageCount << "to" << MAX_FRAMES_IN_FLIGHT; imageCount = MAX_FRAMES_IN_FLIGHT; } VkSwapchainCreateInfoKHR createInfo = {}; createInfo.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR; createInfo.surface = m_surface; createInfo.minImageCount = imageCount; createInfo.imageFormat = surfaceFormat.format; createInfo.imageColorSpace = surfaceFormat.colorSpace; createInfo.imageExtent = extent; createInfo.imageArrayLayers = 1; createInfo.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT; createInfo.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE; createInfo.preTransform = capabilities.currentTransform; createInfo.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR; createInfo.presentMode = presentMode; createInfo.clipped = VK_TRUE; createInfo.oldSwapchain = VK_NULL_HANDLE; VkResult swapchainResult = vkCreateSwapchainKHR(m_device, &createInfo, nullptr, &m_swapchain); if (swapchainResult != VK_SUCCESS) { qDebug() << "Failed to create swapchain, error code:" << swapchainResult; return false; } // Retrieve swapchain images vkGetSwapchainImagesKHR(m_device, m_swapchain, &imageCount, nullptr); m_swapchainImages.resize(imageCount); vkGetSwapchainImagesKHR(m_device, m_swapchain, &imageCount, reinterpret_cast(m_swapchainImages.data())); // Create image views for swapchain images m_swapchainImageViews.resize(imageCount); for (uint32_t i = 0; i < imageCount; i++) { VkImageViewCreateInfo viewInfo = {}; viewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; viewInfo.image = reinterpret_cast(m_swapchainImages[i]); viewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D; viewInfo.format = surfaceFormat.format; viewInfo.components.r = VK_COMPONENT_SWIZZLE_IDENTITY; viewInfo.components.g = VK_COMPONENT_SWIZZLE_IDENTITY; viewInfo.components.b = VK_COMPONENT_SWIZZLE_IDENTITY; viewInfo.components.a = VK_COMPONENT_SWIZZLE_IDENTITY; viewInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; viewInfo.subresourceRange.baseMipLevel = 0; viewInfo.subresourceRange.levelCount = 1; viewInfo.subresourceRange.baseArrayLayer = 0; viewInfo.subresourceRange.layerCount = 1; VkImageView imageView; VkResult viewResult = vkCreateImageView(m_device, &viewInfo, nullptr, &imageView); if (viewResult != VK_SUCCESS) { qDebug() << "Failed to create image view" << i << ", error code:" << viewResult; return false; } m_swapchainImageViews[i] = reinterpret_cast(imageView); } qDebug() << "Swapchain created successfully with" << imageCount << "images (MAX_FRAMES_IN_FLIGHT=" << MAX_FRAMES_IN_FLIGHT << "), size:" << m_surfaceWidth << "x" << m_surfaceHeight; return true; } bool VulkanWidget::createCommandObjects() { qDebug() << "Creating command objects..."; VkCommandPoolCreateInfo poolInfo = {}; poolInfo.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO; poolInfo.queueFamilyIndex = m_queueFamilyIndex; poolInfo.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT; VkResult result = vkCreateCommandPool(m_device, &poolInfo, nullptr, &m_commandPool); if (result != VK_SUCCESS) { qDebug() << "Failed to create command pool, error code:" << result; return false; } m_commandBuffers.resize(MAX_FRAMES_IN_FLIGHT); VkCommandBufferAllocateInfo allocInfo = {}; allocInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO; allocInfo.commandPool = m_commandPool; allocInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY; allocInfo.commandBufferCount = static_cast(m_commandBuffers.size()); result = vkAllocateCommandBuffers(m_device, &allocInfo, m_commandBuffers.data()); if (result != VK_SUCCESS) { qDebug() << "Failed to allocate command buffers, error code:" << result; return false; } qDebug() << "Command objects created successfully"; return true; } bool VulkanWidget::createSyncObjects() { qDebug() << "Creating synchronization objects..."; m_imageAvailableSemaphores.resize(MAX_FRAMES_IN_FLIGHT); m_renderFinishedSemaphores.resize(MAX_FRAMES_IN_FLIGHT); m_inFlightFences.resize(MAX_FRAMES_IN_FLIGHT); VkSemaphoreCreateInfo semaphoreInfo = {}; semaphoreInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO; VkFenceCreateInfo fenceInfo = {}; fenceInfo.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO; fenceInfo.flags = VK_FENCE_CREATE_SIGNALED_BIT; for (int i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) { if (vkCreateSemaphore(m_device, &semaphoreInfo, nullptr, &m_imageAvailableSemaphores[i]) != VK_SUCCESS || vkCreateSemaphore(m_device, &semaphoreInfo, nullptr, &m_renderFinishedSemaphores[i]) != VK_SUCCESS || vkCreateFence(m_device, &fenceInfo, nullptr, &m_inFlightFences[i]) != VK_SUCCESS) { qDebug() << "Failed to create synchronization objects"; return false; } } qDebug() << "Synchronization objects created successfully"; return true; } bool VulkanWidget::recreateSwapchain() { qDebug() << "Recreating swapchain..."; // Don't recreate if closing if (m_isClosing) { qDebug() << "Aborting swapchain recreation - widget is closing"; return false; } // Wait for device to be idle vkDeviceWaitIdle(m_device); // Cleanup old swapchain cleanupSwapchain(); // Create new swapchain if (!createSwapchain()) { qDebug() << "Failed to recreate swapchain"; return false; } // Update renderer with new surface dimensions if (m_renderer) { qDebug() << "Updating VulkanRenderer to surface size:" << m_surfaceWidth << "x" << m_surfaceHeight; m_renderer->resize(m_surfaceWidth, m_surfaceHeight); } qDebug() << "Swapchain recreated successfully"; return true; } void VulkanWidget::renderFrame() { // Don't render if closing or not initialized if (!m_initialized || m_isClosing) { return; } // 关键修复:即使 renderingEnabled=false 也继续渲染,以显示锁屏状态 // 只是传递不同的 paintingEnabled 参数给 renderer // Calculate FPS QDateTime currentTime = QDateTime::currentDateTime(); qint64 frameTimeUs = m_lastFrameTime.msecsTo(currentTime) * 1000; // Convert to microseconds m_lastFrameTime = currentTime; if (frameTimeUs > 0) { // Add frame time to circular buffer if (m_frameTimes.size() >= FPS_SAMPLE_COUNT) { m_frameTimes.erase(m_frameTimes.begin()); } m_frameTimes.push_back(frameTimeUs); // Calculate average FPS from recent frames if (!m_frameTimes.empty()) { qint64 totalTimeUs = 0; for (qint64 time : m_frameTimes) { totalTimeUs += time; } double avgFrameTimeUs = static_cast(totalTimeUs) / m_frameTimes.size(); m_currentFps = 1000000.0 / avgFrameTimeUs; // Convert microseconds to FPS } } // Wait for previous frame vkWaitForFences(m_device, 1, &m_inFlightFences[m_currentFrame], VK_TRUE, UINT64_MAX); // Acquire next image uint32_t imageIndex; VkResult result = vkAcquireNextImageKHR(m_device, m_swapchain, UINT64_MAX, m_imageAvailableSemaphores[m_currentFrame], VK_NULL_HANDLE, &imageIndex); if (result == VK_ERROR_OUT_OF_DATE_KHR) { recreateSwapchain(); return; } else if (result != VK_SUCCESS && result != VK_SUBOPTIMAL_KHR) { //qDebug() << "Failed to acquire swapchain image"; return; } // Reset fence vkResetFences(m_device, 1, &m_inFlightFences[m_currentFrame]); // Record command buffer vkResetCommandBuffer(m_commandBuffers[m_currentFrame], 0); recordCommandBuffer(m_commandBuffers[m_currentFrame], imageIndex); // Submit command buffer VkSubmitInfo submitInfo = {}; submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; VkSemaphore waitSemaphores[] = {m_imageAvailableSemaphores[m_currentFrame]}; VkPipelineStageFlags waitStages[] = {VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT}; submitInfo.waitSemaphoreCount = 1; submitInfo.pWaitSemaphores = waitSemaphores; submitInfo.pWaitDstStageMask = waitStages; submitInfo.commandBufferCount = 1; submitInfo.pCommandBuffers = &m_commandBuffers[m_currentFrame]; VkSemaphore signalSemaphores[] = {m_renderFinishedSemaphores[m_currentFrame]}; submitInfo.signalSemaphoreCount = 1; submitInfo.pSignalSemaphores = signalSemaphores; result = vkQueueSubmit(m_queue, 1, &submitInfo, m_inFlightFences[m_currentFrame]); if (result != VK_SUCCESS) { qDebug() << "Failed to submit draw command buffer! Error code = " << result; return; } // Present VkPresentInfoKHR presentInfo = {}; presentInfo.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR; presentInfo.waitSemaphoreCount = 1; presentInfo.pWaitSemaphores = signalSemaphores; VkSwapchainKHR swapchains[] = {m_swapchain}; presentInfo.swapchainCount = 1; presentInfo.pSwapchains = swapchains; presentInfo.pImageIndices = &imageIndex; result = vkQueuePresentKHR(m_queue, &presentInfo); if (result == VK_ERROR_OUT_OF_DATE_KHR || result == VK_SUBOPTIMAL_KHR || m_needsResize) { m_needsResize = false; recreateSwapchain(); } else if (result != VK_SUCCESS) { qDebug() << "Failed to present swapchain image"; } m_currentFrame = (m_currentFrame + 1) % MAX_FRAMES_IN_FLIGHT; m_frameCount++; } void VulkanWidget::recordCommandBuffer(VkCommandBuffer commandBuffer, uint32_t imageIndex) { // Initialize renderer now if we didn't do it earlier (window was too small) if (!m_renderer && m_surfaceWidth >= 100 && m_surfaceHeight >= 100) { qDebug() << "Creating deferred VulkanRenderer with actual surface size:" << m_surfaceWidth << "x" << m_surfaceHeight; m_renderer = new VulkanRenderer(); VkSurfaceFormatKHR surfaceFormat; uint32_t formatCount = 0; vkGetPhysicalDeviceSurfaceFormatsKHR(m_physicalDevice, m_surface, &formatCount, nullptr); if (formatCount > 0) { std::vector formats(formatCount); vkGetPhysicalDeviceSurfaceFormatsKHR(m_physicalDevice, m_surface, &formatCount, formats.data()); surfaceFormat = formats[0]; } if (!m_renderer->initialize(m_device, m_physicalDevice, m_queue, m_queueFamilyIndex, static_cast(surfaceFormat.format), m_surfaceWidth, m_surfaceHeight)) { qDebug() << "Failed to initialize deferred VulkanRenderer"; delete m_renderer; m_renderer = nullptr; } else { qDebug() << "Deferred VulkanRenderer initialized successfully with surface size:" << m_surfaceWidth << "x" << m_surfaceHeight; } } // Use VulkanRenderer if available if (m_renderer) { if (imageIndex >= m_swapchainImageViews.size()) { qDebug() << "ERROR: imageIndex out of bounds!"; return; } VkImageView imageView = reinterpret_cast(m_swapchainImageViews[imageIndex]); // Build lock info string QString lockInfo; if (m_lastLockTime.isValid()) { lockInfo = QString("Last Lock: %1\nDuration: %2s\nFrame Count at Lock: %3\nFrames During Lock: %4\nLock Count: %5") .arg(m_lastLockTime.toString("hh:mm:ss")) .arg(m_lastLockDuration) .arg(m_lastLockFrameCount) .arg(m_lockPaintFrameCount) .arg(m_lockCount); } // Calculate elapsed time in seconds QDateTime now = QDateTime::currentDateTime(); qint64 elapsedTime = m_startTime.secsTo(now); m_renderer->recordCommandBuffer(commandBuffer, imageIndex, imageView, m_frameCount, static_cast(elapsedTime), m_currentFps, m_rotationAngle, m_wavePhase, m_renderingEnabled, lockInfo.toStdString()); return; } // Fallback: Simple clear color pass VkCommandBufferBeginInfo beginInfo = {}; beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; vkBeginCommandBuffer(commandBuffer, &beginInfo); VkClearColorValue clearColor; float hue = (m_frameCount % 360) / 360.0f; float r = std::abs(std::sin(hue * 6.28318f)); float g = std::abs(std::sin((hue + 0.33f) * 6.28318f)); float b = std::abs(std::sin((hue + 0.66f) * 6.28318f)); clearColor.float32[0] = r * 0.5f + 0.1f; clearColor.float32[1] = g * 0.5f + 0.1f; clearColor.float32[2] = b * 0.5f + 0.1f; clearColor.float32[3] = 1.0f; VkImageSubresourceRange range = {}; range.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; range.baseMipLevel = 0; range.levelCount = 1; range.baseArrayLayer = 0; range.layerCount = 1; VkImage image = reinterpret_cast(m_swapchainImages[imageIndex]); VkImageMemoryBarrier barrier1 = {}; barrier1.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; barrier1.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED; barrier1.newLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL; barrier1.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; barrier1.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; barrier1.image = image; barrier1.subresourceRange = range; barrier1.srcAccessMask = 0; barrier1.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; vkCmdPipelineBarrier(commandBuffer, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 0, nullptr, 0, nullptr, 1, &barrier1); vkCmdClearColorImage(commandBuffer, image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, &clearColor, 1, &range); VkImageMemoryBarrier barrier2 = {}; barrier2.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; barrier2.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL; barrier2.newLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR; barrier2.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; barrier2.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; barrier2.image = image; barrier2.subresourceRange = range; barrier2.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; barrier2.dstAccessMask = 0; vkCmdPipelineBarrier(commandBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, 0, 0, nullptr, 0, nullptr, 1, &barrier2); vkEndCommandBuffer(commandBuffer); } void VulkanWidget::cleanupSwapchain() { // Destroy image views first for (void* imageView : m_swapchainImageViews) { if (imageView != nullptr) { vkDestroyImageView(m_device, reinterpret_cast(imageView), nullptr); } } m_swapchainImageViews.clear(); if (m_swapchain != VK_NULL_HANDLE) { vkDestroySwapchainKHR(m_device, m_swapchain, nullptr); m_swapchain = VK_NULL_HANDLE; } m_swapchainImages.clear(); } void VulkanWidget::cleanupVulkan() { if (!m_initialized) { return; } if (m_device != VK_NULL_HANDLE) { vkDeviceWaitIdle(m_device); } // Cleanup sync objects for (int i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) { if (m_imageAvailableSemaphores[i] != VK_NULL_HANDLE) { vkDestroySemaphore(m_device, m_imageAvailableSemaphores[i], nullptr); } if (m_renderFinishedSemaphores[i] != VK_NULL_HANDLE) { vkDestroySemaphore(m_device, m_renderFinishedSemaphores[i], nullptr); } if (m_inFlightFences[i] != VK_NULL_HANDLE) { vkDestroyFence(m_device, m_inFlightFences[i], nullptr); } } // Cleanup command pool if (m_commandPool != VK_NULL_HANDLE) { vkDestroyCommandPool(m_device, m_commandPool, nullptr); } // Cleanup swapchain cleanupSwapchain(); // Cleanup device if (m_device != VK_NULL_HANDLE) { vkDestroyDevice(m_device, nullptr); } // Cleanup surface if (m_surface != VK_NULL_HANDLE) { vkDestroySurfaceKHR(m_instance, m_surface, nullptr); } // Cleanup instance if (m_instance != VK_NULL_HANDLE) { vkDestroyInstance(m_instance, nullptr); } m_initialized = false; qDebug() << "Vulkan cleanup complete"; } void VulkanWidget::showEvent(QShowEvent *event) { QWidget::showEvent(event); if (!m_initialized) { initializeVulkan(); } } void VulkanWidget::hideEvent(QHideEvent *event) { QWidget::hideEvent(event); setRenderingEnabled(false); } void VulkanWidget::closeEvent(QCloseEvent *event) { qDebug() << "VulkanWidget closeEvent - stopping rendering and cleaning up"; // Set closing flag to prevent any further rendering attempts m_isClosing = true; // Stop the render timer immediately if (m_renderTimer) { m_renderTimer->stop(); qDebug() << "Render timer stopped on close"; } // Wait for device to be idle before accepting close event if (m_device != VK_NULL_HANDLE) { vkDeviceWaitIdle(m_device); qDebug() << "Vulkan device idle on close"; } // Accept the close event QWidget::closeEvent(event); } void VulkanWidget::resizeEvent(QResizeEvent *event) { QWidget::resizeEvent(event); if (m_initialized) { m_needsResize = true; // Note: Don't update renderer size here - it will be updated after swapchain recreation // The renderer must use the actual surface dimensions (m_surfaceWidth/Height), // not the widget dimensions, which may differ on high DPI displays } } void VulkanWidget::paintEvent(QPaintEvent *event) { // Do nothing - rendering is handled by Vulkan Q_UNUSED(event); } QPaintEngine* VulkanWidget::paintEngine() const { // Return nullptr to prevent Qt from using QPainter return nullptr; } void VulkanWidget::onRenderTimer() { if (m_renderingEnabled) { // Update animation parameters m_rotationAngle += 2.0; if (m_rotationAngle >= 360.0) { m_rotationAngle -= 360.0; } m_wavePhase += 0.05; if (m_wavePhase >= 2 * M_PI) { m_wavePhase -= 2 * M_PI; } // 正常渲染 renderFrame(); } else if (m_needsLockedFrameUpdate) { // 锁屏状态:只渲染一帧显示锁屏界面 m_needsLockedFrameUpdate = false; renderFrame(); // 渲染完锁屏帧后停止定时器,避免浪费资源 m_renderTimer->stop(); qDebug() << "Locked frame rendered, timer stopped"; } // 否则:锁屏状态且已渲染锁屏帧,不做任何事 } void VulkanWidget::setError(const QString &error) { m_lastError = error; qDebug() << "VulkanWidget Error:" << error; } std::vector VulkanWidget::getRequiredInstanceExtensions() { std::vector extensions; extensions.push_back(VK_KHR_SURFACE_EXTENSION_NAME); #ifdef _WIN32 extensions.push_back(VK_KHR_WIN32_SURFACE_EXTENSION_NAME); #elif defined(__linux__) extensions.push_back(VK_KHR_XLIB_SURFACE_EXTENSION_NAME); #elif defined(__APPLE__) extensions.push_back(VK_EXT_METAL_SURFACE_EXTENSION_NAME); #endif return extensions; } std::vector VulkanWidget::getRequiredDeviceExtensions() { std::vector extensions; extensions.push_back(VK_KHR_SWAPCHAIN_EXTENSION_NAME); return extensions; }