Latte: fix shader-cache hang, redundant vertex rebind, and latent UB

- Fix an infinite loop when removing a shader from the middle of a cache chain (the list traversal never advanced).

- Vulkan direct-access path: record the bound vertex-buffer offset so the redundant-bind check works; previously one vkCmdBindVertexBuffers per buffer group was issued on every draw.

- Fix an out-of-bounds __m256i lane read in the clang texture-hash path.

- Fix a use-after-free read in the texture-readback queue and an inverted fetch-shader cache assertion.

- Initialize MetalRenderer commit-threshold fields; avoid re-strlen'ing the shader source when assigning it.
This commit is contained in:
1e1 2026-06-30 21:36:33 +02:00
parent 855e51f3f8
commit 44c19af7db
6 changed files with 16 additions and 11 deletions

View File

@ -170,10 +170,13 @@ void LatteFetchShader::CalculateFetchShaderVkHash()
EVP_DigestFinal_ex(ctx, shaDigest, NULL);
EVP_MD_CTX_free(ctx);
// fold SHA1 hash into a 64bit value
uint64 h = *(uint64*)(shaDigest + 0);
h += *(uint64*)(shaDigest + 8);
h += (uint64)*(uint32*)(shaDigest + 16);
// fold SHA1 hash into a 64bit value (use memcpy to avoid unaligned/strict-aliasing UB)
uint64 shaLow, shaMid;
uint32 shaHigh;
std::memcpy(&shaLow, shaDigest + 0, sizeof(shaLow));
std::memcpy(&shaMid, shaDigest + 8, sizeof(shaMid));
std::memcpy(&shaHigh, shaDigest + 16, sizeof(shaHigh));
uint64 h = shaLow + shaMid + (uint64)shaHigh;
this->vkPipelineHashFragment = h;
}
@ -604,7 +607,7 @@ void LatteFetchShader::UnregisterInCache()
return;
s_spinlockFetchShaderCache.lock();
auto itr = s_fetchShaderByHash.find(m_cacheHash);
cemu_assert(itr == s_fetchShaderByHash.end());
cemu_assert(itr != s_fetchShaderByHash.end());
s_fetchShaderByHash.erase(itr);
s_spinlockFetchShaderCache.unlock();
}

View File

@ -187,6 +187,7 @@ void LatteSHRC_RemoveFromCaches(LatteDecompilerShader* shader)
removed = true;
break;
}
shaderChain = shaderChain->next;
}
}
cemu_assert(removed);
@ -355,7 +356,7 @@ void LatteShader_CreateRendererShader(LatteDecompilerShader* shader, bool compil
shader->isCustomShader = true;
}
else
shaderSrc.assign(shader->strBuf_shaderSource->c_str());
shaderSrc.assign(shader->strBuf_shaderSource->c_str(), shader->strBuf_shaderSource->getLen());
if (shaderType == RendererShader::ShaderType::kVertex &&
(shader->baseHash == 0x15bc7edf9de2ed30 || shader->baseHash == 0x83a697d61a3b9202 ||

View File

@ -159,7 +159,7 @@ uint32 LatteTexture_CalculateTextureDataHash(LatteTexture* hostTexture)
h256 = _mm256_xor_si256(h256, temp);
}
#ifdef __clang__
hashVal = h256[0] + h256[1] + h256[2] + h256[3] + h256[4] + h256[5] + h256[6] + h256[7];
hashVal = (uint32)h256[0] + (uint32)(h256[0] >> 32) + (uint32)h256[1] + (uint32)(h256[1] >> 32) + (uint32)h256[2] + (uint32)(h256[2] >> 32) + (uint32)h256[3] + (uint32)(h256[3] >> 32);
#else
hashVal = h256.m256i_u32[0] + h256.m256i_u32[1] + h256.m256i_u32[2] + h256.m256i_u32[3] + h256.m256i_u32[4] + h256.m256i_u32[5] + h256.m256i_u32[6] + h256.m256i_u32[7];
#endif

View File

@ -151,11 +151,11 @@ void LatteTextureReadback_UpdateFinishedTransfers(bool forceFinish)
LatteTextureView* origTexView = LatteTextureViewLookupCache::lookupSlice(readbackInfo->hostTextureCopy.physAddress, readbackInfo->hostTextureCopy.width, readbackInfo->hostTextureCopy.height, readbackInfo->hostTextureCopy.pitch, 0, 0, readbackInfo->hostTextureCopy.format);
if (origTexView)
LatteTC_ResetTextureChangeTracker(origTexView->baseTexture, true);
delete readbackInfo;
// remove from queue
cemu_assert_debug(!sTextureActiveReadbackQueue.empty());
cemu_assert_debug(readbackInfo == sTextureActiveReadbackQueue.front());
sTextureActiveReadbackQueue.pop();
delete readbackInfo;
}
performanceMonitor.gpuTime_waitForAsync.endMeasuring();
}

View File

@ -535,9 +535,9 @@ private:
MetalEncoderType m_encoderType = MetalEncoderType::None;
MTL::CommandEncoder* m_commandEncoder = nullptr;
uint32 m_recordedDrawcalls;
uint32 m_defaultCommitTreshlod;
uint32 m_commitTreshold;
uint32 m_recordedDrawcalls = 0;
uint32 m_defaultCommitTreshlod = 0;
uint32 m_commitTreshold = 0;
// State
MetalState m_state;

View File

@ -1772,6 +1772,7 @@ void VulkanRenderer::draw_updateVertexBuffersDirectAccess()
VkBuffer attrBuffer = m_importedMem;
VkDeviceSize attrOffset = bufferAddress - m_importedMemBaseAddress;
vkCmdBindVertexBuffers(m_state.currentCommandBuffer, bufferIndex, 1, &attrBuffer, &attrOffset);
m_state.currentVertexBinding[bufferIndex].offset = bufferAddress;
}
}