mirror of
https://github.com/Kelsidavis/WoWee.git
synced 2026-04-17 17:43:52 +00:00
Fix MSAA 8x crash and eliminate redundant GPU stalls
- Add error handling: revert to 1x if recreateSwapchain fails - Clamp requested MSAA to device maximum before applying - Retry MSAA color image allocation without TRANSIENT on failure - Remove redundant vkDeviceWaitIdle from WMO/M2/Character recreatePipelines (caller already waits once, was causing ~13 stalls instead of 1)
This commit is contained in:
parent
e12141a673
commit
fa1867cf2f
5 changed files with 17 additions and 7 deletions
|
|
@ -2568,7 +2568,6 @@ void CharacterRenderer::dumpAnimations(uint32_t instanceId) const {
|
||||||
void CharacterRenderer::recreatePipelines() {
|
void CharacterRenderer::recreatePipelines() {
|
||||||
if (!vkCtx_) return;
|
if (!vkCtx_) return;
|
||||||
VkDevice device = vkCtx_->getDevice();
|
VkDevice device = vkCtx_->getDevice();
|
||||||
vkDeviceWaitIdle(device);
|
|
||||||
|
|
||||||
// Destroy old main-pass pipelines (NOT shadow, NOT pipeline layout)
|
// Destroy old main-pass pipelines (NOT shadow, NOT pipeline layout)
|
||||||
if (opaquePipeline_) { vkDestroyPipeline(device, opaquePipeline_, nullptr); opaquePipeline_ = VK_NULL_HANDLE; }
|
if (opaquePipeline_) { vkDestroyPipeline(device, opaquePipeline_, nullptr); opaquePipeline_ = VK_NULL_HANDLE; }
|
||||||
|
|
|
||||||
|
|
@ -3683,7 +3683,6 @@ float M2Renderer::raycastBoundingBoxes(const glm::vec3& origin, const glm::vec3&
|
||||||
void M2Renderer::recreatePipelines() {
|
void M2Renderer::recreatePipelines() {
|
||||||
if (!vkCtx_) return;
|
if (!vkCtx_) return;
|
||||||
VkDevice device = vkCtx_->getDevice();
|
VkDevice device = vkCtx_->getDevice();
|
||||||
vkDeviceWaitIdle(device);
|
|
||||||
|
|
||||||
// Destroy old main-pass pipelines (NOT shadow, NOT pipeline layouts)
|
// Destroy old main-pass pipelines (NOT shadow, NOT pipeline layouts)
|
||||||
if (opaquePipeline_) { vkDestroyPipeline(device, opaquePipeline_, nullptr); opaquePipeline_ = VK_NULL_HANDLE; }
|
if (opaquePipeline_) { vkDestroyPipeline(device, opaquePipeline_, nullptr); opaquePipeline_ = VK_NULL_HANDLE; }
|
||||||
|
|
|
||||||
|
|
@ -726,16 +726,25 @@ void Renderer::shutdown() {
|
||||||
void Renderer::setMsaaSamples(VkSampleCountFlagBits samples) {
|
void Renderer::setMsaaSamples(VkSampleCountFlagBits samples) {
|
||||||
if (!vkCtx) return;
|
if (!vkCtx) return;
|
||||||
|
|
||||||
|
// Clamp to device maximum
|
||||||
|
VkSampleCountFlagBits maxSamples = vkCtx->getMaxUsableSampleCount();
|
||||||
|
if (samples > maxSamples) samples = maxSamples;
|
||||||
|
|
||||||
VkSampleCountFlagBits current = vkCtx->getMsaaSamples();
|
VkSampleCountFlagBits current = vkCtx->getMsaaSamples();
|
||||||
if (samples == current) return;
|
if (samples == current) return;
|
||||||
|
|
||||||
LOG_INFO("Changing MSAA from ", static_cast<int>(current), "x to ", static_cast<int>(samples), "x");
|
LOG_INFO("Changing MSAA from ", static_cast<int>(current), "x to ", static_cast<int>(samples), "x");
|
||||||
|
|
||||||
|
// Single GPU wait — all subsequent operations are CPU-side object creation
|
||||||
vkDeviceWaitIdle(vkCtx->getDevice());
|
vkDeviceWaitIdle(vkCtx->getDevice());
|
||||||
|
|
||||||
// Set new MSAA and recreate swapchain (render pass, depth, MSAA image, framebuffers)
|
// Set new MSAA and recreate swapchain (render pass, depth, MSAA image, framebuffers)
|
||||||
vkCtx->setMsaaSamples(samples);
|
vkCtx->setMsaaSamples(samples);
|
||||||
vkCtx->recreateSwapchain(window->getWidth(), window->getHeight());
|
if (!vkCtx->recreateSwapchain(window->getWidth(), window->getHeight())) {
|
||||||
|
LOG_ERROR("MSAA change failed — reverting to 1x");
|
||||||
|
vkCtx->setMsaaSamples(VK_SAMPLE_COUNT_1_BIT);
|
||||||
|
vkCtx->recreateSwapchain(window->getWidth(), window->getHeight());
|
||||||
|
}
|
||||||
|
|
||||||
// Recreate all sub-renderer pipelines (they embed sample count from render pass)
|
// Recreate all sub-renderer pipelines (they embed sample count from render pass)
|
||||||
if (terrainRenderer) terrainRenderer->recreatePipelines();
|
if (terrainRenderer) terrainRenderer->recreatePipelines();
|
||||||
|
|
@ -758,7 +767,6 @@ void Renderer::setMsaaSamples(VkSampleCountFlagBits samples) {
|
||||||
if (auto* lf = skySystem->getLensFlare()) lf->recreatePipelines();
|
if (auto* lf = skySystem->getLensFlare()) lf->recreatePipelines();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Lightning is standalone (not instantiated in Renderer, no action needed)
|
|
||||||
// Selection circle + overlay use lazy init, just destroy them
|
// Selection circle + overlay use lazy init, just destroy them
|
||||||
VkDevice device = vkCtx->getDevice();
|
VkDevice device = vkCtx->getDevice();
|
||||||
if (selCirclePipeline) { vkDestroyPipeline(device, selCirclePipeline, nullptr); selCirclePipeline = VK_NULL_HANDLE; }
|
if (selCirclePipeline) { vkDestroyPipeline(device, selCirclePipeline, nullptr); selCirclePipeline = VK_NULL_HANDLE; }
|
||||||
|
|
|
||||||
|
|
@ -384,8 +384,13 @@ bool VkContext::createMsaaColorImage() {
|
||||||
allocInfo.preferredFlags = VK_MEMORY_PROPERTY_LAZILY_ALLOCATED_BIT;
|
allocInfo.preferredFlags = VK_MEMORY_PROPERTY_LAZILY_ALLOCATED_BIT;
|
||||||
|
|
||||||
if (vmaCreateImage(allocator, &imgInfo, &allocInfo, &msaaColorImage_, &msaaColorAllocation_, nullptr) != VK_SUCCESS) {
|
if (vmaCreateImage(allocator, &imgInfo, &allocInfo, &msaaColorImage_, &msaaColorAllocation_, nullptr) != VK_SUCCESS) {
|
||||||
LOG_ERROR("Failed to create MSAA color image");
|
// Retry without TRANSIENT (some drivers reject it at high sample counts)
|
||||||
return false;
|
imgInfo.usage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
|
||||||
|
allocInfo.preferredFlags = 0;
|
||||||
|
if (vmaCreateImage(allocator, &imgInfo, &allocInfo, &msaaColorImage_, &msaaColorAllocation_, nullptr) != VK_SUCCESS) {
|
||||||
|
LOG_ERROR("Failed to create MSAA color image");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
VkImageViewCreateInfo viewInfo{};
|
VkImageViewCreateInfo viewInfo{};
|
||||||
|
|
|
||||||
|
|
@ -2884,7 +2884,6 @@ float WMORenderer::raycastBoundingBoxes(const glm::vec3& origin, const glm::vec3
|
||||||
void WMORenderer::recreatePipelines() {
|
void WMORenderer::recreatePipelines() {
|
||||||
if (!vkCtx_) return;
|
if (!vkCtx_) return;
|
||||||
VkDevice device = vkCtx_->getDevice();
|
VkDevice device = vkCtx_->getDevice();
|
||||||
vkDeviceWaitIdle(device);
|
|
||||||
|
|
||||||
// Destroy old main-pass pipelines (NOT shadow, NOT pipeline layout)
|
// Destroy old main-pass pipelines (NOT shadow, NOT pipeline layout)
|
||||||
if (opaquePipeline_) { vkDestroyPipeline(device, opaquePipeline_, nullptr); opaquePipeline_ = VK_NULL_HANDLE; }
|
if (opaquePipeline_) { vkDestroyPipeline(device, opaquePipeline_, nullptr); opaquePipeline_ = VK_NULL_HANDLE; }
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue