mirror of
https://github.com/Kelsidavis/WoWee.git
synced 2026-04-15 08:53:51 +00:00
fix: add VkSampler cache to prevent sampler exhaustion crash
Validation layers revealed 9965 VkSamplers allocated against a device limit of 4000 — every VkTexture created its own sampler even when configurations were identical. This exhausted NVIDIA's sampler pool and caused intermittent SIGSEGV in vkCmdBeginRenderPass. Add a thread-safe sampler cache in VkContext that deduplicates samplers by FNV-1a hash of all 14 VkSamplerCreateInfo fields. All texture, render target, renderer, water, and loading screen sampler creation now goes through getOrCreateSampler(). Textures set ownsSampler_=false so shared samplers aren't double-freed. Also auto-disable anisotropy in the cache when the physical device doesn't support the samplerAnisotropy feature, fixing the validation error VUID-VkSamplerCreateInfo-anisotropyEnable-01070.
This commit is contained in:
parent
1556559211
commit
a152023e5e
10 changed files with 194 additions and 40 deletions
|
|
@ -352,8 +352,8 @@ void WaterRenderer::destroySceneHistoryResources() {
|
|||
if (sh.depthImage) { vmaDestroyImage(vkCtx->getAllocator(), sh.depthImage, sh.depthAlloc); sh.depthImage = VK_NULL_HANDLE; sh.depthAlloc = VK_NULL_HANDLE; }
|
||||
sh.sceneSet = VK_NULL_HANDLE;
|
||||
}
|
||||
if (sceneColorSampler) { vkDestroySampler(device, sceneColorSampler, nullptr); sceneColorSampler = VK_NULL_HANDLE; }
|
||||
if (sceneDepthSampler) { vkDestroySampler(device, sceneDepthSampler, nullptr); sceneDepthSampler = VK_NULL_HANDLE; }
|
||||
sceneColorSampler = VK_NULL_HANDLE; // Owned by VkContext sampler cache
|
||||
sceneDepthSampler = VK_NULL_HANDLE; // Owned by VkContext sampler cache
|
||||
sceneHistoryExtent = {0, 0};
|
||||
sceneHistoryReady = false;
|
||||
}
|
||||
|
|
@ -374,13 +374,15 @@ void WaterRenderer::createSceneHistoryResources(VkExtent2D extent, VkFormat colo
|
|||
sampCI.addressModeU = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
|
||||
sampCI.addressModeV = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
|
||||
sampCI.addressModeW = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
|
||||
if (vkCreateSampler(device, &sampCI, nullptr, &sceneColorSampler) != VK_SUCCESS) {
|
||||
sceneColorSampler = vkCtx->getOrCreateSampler(sampCI);
|
||||
if (sceneColorSampler == VK_NULL_HANDLE) {
|
||||
LOG_ERROR("WaterRenderer: failed to create scene color sampler");
|
||||
return;
|
||||
}
|
||||
sampCI.magFilter = VK_FILTER_NEAREST;
|
||||
sampCI.minFilter = VK_FILTER_NEAREST;
|
||||
if (vkCreateSampler(device, &sampCI, nullptr, &sceneDepthSampler) != VK_SUCCESS) {
|
||||
sceneDepthSampler = vkCtx->getOrCreateSampler(sampCI);
|
||||
if (sceneDepthSampler == VK_NULL_HANDLE) {
|
||||
LOG_ERROR("WaterRenderer: failed to create scene depth sampler");
|
||||
return;
|
||||
}
|
||||
|
|
@ -1718,7 +1720,8 @@ void WaterRenderer::createReflectionResources() {
|
|||
sampCI.addressModeU = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
|
||||
sampCI.addressModeV = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
|
||||
sampCI.addressModeW = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
|
||||
if (vkCreateSampler(device, &sampCI, nullptr, &reflectionSampler) != VK_SUCCESS) {
|
||||
reflectionSampler = vkCtx->getOrCreateSampler(sampCI);
|
||||
if (reflectionSampler == VK_NULL_HANDLE) {
|
||||
LOG_ERROR("WaterRenderer: failed to create reflection sampler");
|
||||
return;
|
||||
}
|
||||
|
|
@ -1848,7 +1851,7 @@ void WaterRenderer::destroyReflectionResources() {
|
|||
if (reflectionDepthView) { vkDestroyImageView(device, reflectionDepthView, nullptr); reflectionDepthView = VK_NULL_HANDLE; }
|
||||
if (reflectionColorImage) { vmaDestroyImage(allocator, reflectionColorImage, reflectionColorAlloc); reflectionColorImage = VK_NULL_HANDLE; }
|
||||
if (reflectionDepthImage) { vmaDestroyImage(allocator, reflectionDepthImage, reflectionDepthAlloc); reflectionDepthImage = VK_NULL_HANDLE; }
|
||||
if (reflectionSampler) { vkDestroySampler(device, reflectionSampler, nullptr); reflectionSampler = VK_NULL_HANDLE; }
|
||||
reflectionSampler = VK_NULL_HANDLE; // Owned by VkContext sampler cache
|
||||
if (reflectionUBO) {
|
||||
AllocatedBuffer ab{}; ab.buffer = reflectionUBO; ab.allocation = reflectionUBOAlloc;
|
||||
destroyBuffer(allocator, ab);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue