perf: giới hạn cache panorama (LRU) + ghim cảnh hiện tại/lân cận, tránh tràn VRAM
This commit is contained in:
@@ -216,6 +216,38 @@ const panoramaTexturePromises = new Map<string, Promise<THREE.Texture>>();
|
||||
const panoramaTextureProgress = new Map<string, number>();
|
||||
const panoramaTextureProgressListeners = new Map<string, Set<(progress: number) => void>>();
|
||||
|
||||
const MAX_CACHED_PANORAMAS = 8; // đủ cho cảnh hiện tại + các cảnh lân cận
|
||||
const pinnedPanoramaUrls = new Set<string>();
|
||||
|
||||
// Ghim các ảnh không được phép dispose (cảnh hiện tại + lân cận).
|
||||
function setPinnedPanoramas(urls: string[]) {
|
||||
pinnedPanoramaUrls.clear();
|
||||
urls.forEach((url) => pinnedPanoramaUrls.add(url));
|
||||
}
|
||||
|
||||
// Đánh dấu ảnh là mới-dùng-nhất (Map giữ thứ tự chèn) rồi dọn nếu vượt giới hạn.
|
||||
function touchPanoramaCache(image: string, texture: THREE.Texture) {
|
||||
panoramaTextureCache.delete(image);
|
||||
panoramaTextureCache.set(image, texture);
|
||||
evictPanoramaTextures();
|
||||
}
|
||||
|
||||
function evictPanoramaTextures() {
|
||||
if (panoramaTextureCache.size <= MAX_CACHED_PANORAMAS) {
|
||||
return;
|
||||
}
|
||||
for (const [url, texture] of panoramaTextureCache) {
|
||||
if (panoramaTextureCache.size <= MAX_CACHED_PANORAMAS) {
|
||||
break;
|
||||
}
|
||||
if (pinnedPanoramaUrls.has(url)) {
|
||||
continue; // không dispose ảnh đang ghim (đang hiển thị/lân cận)
|
||||
}
|
||||
panoramaTextureCache.delete(url);
|
||||
texture.dispose();
|
||||
}
|
||||
}
|
||||
|
||||
function notifyPanoramaProgress(image: string, progress: number) {
|
||||
panoramaTextureProgress.set(image, progress);
|
||||
panoramaTextureProgressListeners.get(image)?.forEach((listener) => listener(progress));
|
||||
@@ -243,6 +275,7 @@ function loadPanoramaTexture(image: string, onProgress?: (progress: number) => v
|
||||
const cachedTexture = panoramaTextureCache.get(image);
|
||||
|
||||
if (cachedTexture) {
|
||||
touchPanoramaCache(image, cachedTexture);
|
||||
onProgress?.(100);
|
||||
return Promise.resolve(cachedTexture);
|
||||
}
|
||||
@@ -263,6 +296,7 @@ function loadPanoramaTexture(image: string, onProgress?: (progress: number) => v
|
||||
texture.colorSpace = THREE.SRGBColorSpace;
|
||||
texture.anisotropy = 8;
|
||||
panoramaTextureCache.set(image, texture);
|
||||
evictPanoramaTextures();
|
||||
panoramaTexturePromises.delete(image);
|
||||
notifyPanoramaProgress(image, 100);
|
||||
resolve(texture);
|
||||
@@ -1311,6 +1345,12 @@ function TourExperience({
|
||||
|
||||
const preloadTourScene = useCallback(
|
||||
(scene: TourScene) => {
|
||||
// Ghim ảnh đang dùng + các cảnh lân cận để LRU không dispose nhầm.
|
||||
const neighborImages = scene.hotspots
|
||||
.map((hotspot) => tourConfig.sceneById.get(hotspot.targetId)?.image)
|
||||
.filter((image): image is string => Boolean(image));
|
||||
setPinnedPanoramas([scene.image, ...neighborImages]);
|
||||
|
||||
const preloadImage = (image: string) => {
|
||||
loadPanoramaTexture(image)
|
||||
.then((texture) => warmPanoramaTexture(image, texture))
|
||||
|
||||
Reference in New Issue
Block a user