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 panoramaTextureProgress = new Map<string, number>();
|
||||||
const panoramaTextureProgressListeners = new Map<string, Set<(progress: number) => void>>();
|
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) {
|
function notifyPanoramaProgress(image: string, progress: number) {
|
||||||
panoramaTextureProgress.set(image, progress);
|
panoramaTextureProgress.set(image, progress);
|
||||||
panoramaTextureProgressListeners.get(image)?.forEach((listener) => listener(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);
|
const cachedTexture = panoramaTextureCache.get(image);
|
||||||
|
|
||||||
if (cachedTexture) {
|
if (cachedTexture) {
|
||||||
|
touchPanoramaCache(image, cachedTexture);
|
||||||
onProgress?.(100);
|
onProgress?.(100);
|
||||||
return Promise.resolve(cachedTexture);
|
return Promise.resolve(cachedTexture);
|
||||||
}
|
}
|
||||||
@@ -263,6 +296,7 @@ function loadPanoramaTexture(image: string, onProgress?: (progress: number) => v
|
|||||||
texture.colorSpace = THREE.SRGBColorSpace;
|
texture.colorSpace = THREE.SRGBColorSpace;
|
||||||
texture.anisotropy = 8;
|
texture.anisotropy = 8;
|
||||||
panoramaTextureCache.set(image, texture);
|
panoramaTextureCache.set(image, texture);
|
||||||
|
evictPanoramaTextures();
|
||||||
panoramaTexturePromises.delete(image);
|
panoramaTexturePromises.delete(image);
|
||||||
notifyPanoramaProgress(image, 100);
|
notifyPanoramaProgress(image, 100);
|
||||||
resolve(texture);
|
resolve(texture);
|
||||||
@@ -1311,6 +1345,12 @@ function TourExperience({
|
|||||||
|
|
||||||
const preloadTourScene = useCallback(
|
const preloadTourScene = useCallback(
|
||||||
(scene: TourScene) => {
|
(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) => {
|
const preloadImage = (image: string) => {
|
||||||
loadPanoramaTexture(image)
|
loadPanoramaTexture(image)
|
||||||
.then((texture) => warmPanoramaTexture(image, texture))
|
.then((texture) => warmPanoramaTexture(image, texture))
|
||||||
|
|||||||
Reference in New Issue
Block a user