mirror of
https://github.com/Kelsidavis/WoWee.git
synced 2026-04-14 16:33:52 +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
|
|
@ -343,7 +343,8 @@ bool Renderer::createPerFrameResources() {
|
|||
sampCI.borderColor = VK_BORDER_COLOR_FLOAT_OPAQUE_WHITE;
|
||||
sampCI.compareEnable = VK_TRUE;
|
||||
sampCI.compareOp = VK_COMPARE_OP_LESS_OR_EQUAL;
|
||||
if (vkCreateSampler(device, &sampCI, nullptr, &shadowSampler) != VK_SUCCESS) {
|
||||
shadowSampler = vkCtx->getOrCreateSampler(sampCI);
|
||||
if (shadowSampler == VK_NULL_HANDLE) {
|
||||
LOG_ERROR("Failed to create shadow sampler");
|
||||
return false;
|
||||
}
|
||||
|
|
@ -597,7 +598,7 @@ void Renderer::destroyPerFrameResources() {
|
|||
shadowDepthLayout_[i] = VK_IMAGE_LAYOUT_UNDEFINED;
|
||||
}
|
||||
if (shadowRenderPass) { vkDestroyRenderPass(device, shadowRenderPass, nullptr); shadowRenderPass = VK_NULL_HANDLE; }
|
||||
if (shadowSampler) { vkDestroySampler(device, shadowSampler, nullptr); shadowSampler = VK_NULL_HANDLE; }
|
||||
shadowSampler = VK_NULL_HANDLE; // Owned by VkContext sampler cache
|
||||
}
|
||||
|
||||
void Renderer::updatePerFrameUBO() {
|
||||
|
|
@ -4057,7 +4058,8 @@ bool Renderer::initFSRResources() {
|
|||
samplerInfo.addressModeV = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
|
||||
samplerInfo.addressModeW = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
|
||||
samplerInfo.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR;
|
||||
if (vkCreateSampler(device, &samplerInfo, nullptr, &fsr_.sceneSampler) != VK_SUCCESS) {
|
||||
fsr_.sceneSampler = vkCtx->getOrCreateSampler(samplerInfo);
|
||||
if (fsr_.sceneSampler == VK_NULL_HANDLE) {
|
||||
LOG_ERROR("FSR: failed to create sampler");
|
||||
destroyFSRResources();
|
||||
return false;
|
||||
|
|
@ -4171,7 +4173,7 @@ void Renderer::destroyFSRResources() {
|
|||
if (fsr_.descPool) { vkDestroyDescriptorPool(device, fsr_.descPool, nullptr); fsr_.descPool = VK_NULL_HANDLE; fsr_.descSet = VK_NULL_HANDLE; }
|
||||
if (fsr_.descSetLayout) { vkDestroyDescriptorSetLayout(device, fsr_.descSetLayout, nullptr); fsr_.descSetLayout = VK_NULL_HANDLE; }
|
||||
if (fsr_.sceneFramebuffer) { vkDestroyFramebuffer(device, fsr_.sceneFramebuffer, nullptr); fsr_.sceneFramebuffer = VK_NULL_HANDLE; }
|
||||
if (fsr_.sceneSampler) { vkDestroySampler(device, fsr_.sceneSampler, nullptr); fsr_.sceneSampler = VK_NULL_HANDLE; }
|
||||
fsr_.sceneSampler = VK_NULL_HANDLE; // Owned by VkContext sampler cache
|
||||
destroyImage(device, alloc, fsr_.sceneDepthResolve);
|
||||
destroyImage(device, alloc, fsr_.sceneMsaaColor);
|
||||
destroyImage(device, alloc, fsr_.sceneDepth);
|
||||
|
|
@ -4350,11 +4352,11 @@ bool Renderer::initFSR2Resources() {
|
|||
samplerInfo.addressModeU = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
|
||||
samplerInfo.addressModeV = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
|
||||
samplerInfo.addressModeW = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
|
||||
vkCreateSampler(device, &samplerInfo, nullptr, &fsr2_.linearSampler);
|
||||
fsr2_.linearSampler = vkCtx->getOrCreateSampler(samplerInfo);
|
||||
|
||||
samplerInfo.minFilter = VK_FILTER_NEAREST;
|
||||
samplerInfo.magFilter = VK_FILTER_NEAREST;
|
||||
vkCreateSampler(device, &samplerInfo, nullptr, &fsr2_.nearestSampler);
|
||||
fsr2_.nearestSampler = vkCtx->getOrCreateSampler(samplerInfo);
|
||||
|
||||
#if WOWEE_HAS_AMD_FSR2
|
||||
// Initialize AMD FSR2 context; fall back to internal path on any failure.
|
||||
|
|
@ -4753,8 +4755,8 @@ void Renderer::destroyFSR2Resources() {
|
|||
if (fsr2_.motionVecDescSetLayout) { vkDestroyDescriptorSetLayout(device, fsr2_.motionVecDescSetLayout, nullptr); fsr2_.motionVecDescSetLayout = VK_NULL_HANDLE; }
|
||||
|
||||
if (fsr2_.sceneFramebuffer) { vkDestroyFramebuffer(device, fsr2_.sceneFramebuffer, nullptr); fsr2_.sceneFramebuffer = VK_NULL_HANDLE; }
|
||||
if (fsr2_.linearSampler) { vkDestroySampler(device, fsr2_.linearSampler, nullptr); fsr2_.linearSampler = VK_NULL_HANDLE; }
|
||||
if (fsr2_.nearestSampler) { vkDestroySampler(device, fsr2_.nearestSampler, nullptr); fsr2_.nearestSampler = VK_NULL_HANDLE; }
|
||||
fsr2_.linearSampler = VK_NULL_HANDLE; // Owned by VkContext sampler cache
|
||||
fsr2_.nearestSampler = VK_NULL_HANDLE; // Owned by VkContext sampler cache
|
||||
|
||||
destroyImage(device, alloc, fsr2_.motionVectors);
|
||||
for (int i = 0; i < 2; i++) destroyImage(device, alloc, fsr2_.history[i]);
|
||||
|
|
@ -5273,7 +5275,8 @@ bool Renderer::initFXAAResources() {
|
|||
samplerInfo.addressModeV = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
|
||||
samplerInfo.addressModeW = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
|
||||
samplerInfo.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR;
|
||||
if (vkCreateSampler(device, &samplerInfo, nullptr, &fxaa_.sceneSampler) != VK_SUCCESS) {
|
||||
fxaa_.sceneSampler = vkCtx->getOrCreateSampler(samplerInfo);
|
||||
if (fxaa_.sceneSampler == VK_NULL_HANDLE) {
|
||||
LOG_ERROR("FXAA: failed to create sampler");
|
||||
destroyFXAAResources();
|
||||
return false;
|
||||
|
|
@ -5383,7 +5386,7 @@ void Renderer::destroyFXAAResources() {
|
|||
if (fxaa_.descPool) { vkDestroyDescriptorPool(device, fxaa_.descPool, nullptr); fxaa_.descPool = VK_NULL_HANDLE; fxaa_.descSet = VK_NULL_HANDLE; }
|
||||
if (fxaa_.descSetLayout) { vkDestroyDescriptorSetLayout(device, fxaa_.descSetLayout, nullptr); fxaa_.descSetLayout = VK_NULL_HANDLE; }
|
||||
if (fxaa_.sceneFramebuffer) { vkDestroyFramebuffer(device, fxaa_.sceneFramebuffer, nullptr); fxaa_.sceneFramebuffer = VK_NULL_HANDLE; }
|
||||
if (fxaa_.sceneSampler) { vkDestroySampler(device, fxaa_.sceneSampler, nullptr); fxaa_.sceneSampler = VK_NULL_HANDLE; }
|
||||
fxaa_.sceneSampler = VK_NULL_HANDLE; // Owned by VkContext sampler cache
|
||||
destroyImage(device, alloc, fxaa_.sceneDepthResolve);
|
||||
destroyImage(device, alloc, fxaa_.sceneMsaaColor);
|
||||
destroyImage(device, alloc, fxaa_.sceneDepth);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue