Pause animation when FPS gets too low
Woof, the "Swirl of Power Effect" item tanks my CPU waaay too much
(I bet it's those 7000x7000 PNGs lolol 😬)
Anyway, before thinking about optimizing specific issues, I'm just adding this emergency switch: if we detect FPS < 2 on any layer, we just pause the whole outfit, until the user decides to unpause.
This commit is contained in:
parent
307ab932c8
commit
bb5ec56752
2 changed files with 44 additions and 5 deletions
|
@ -10,6 +10,7 @@ function OutfitMovieLayer({
|
||||||
height,
|
height,
|
||||||
isPaused = false,
|
isPaused = false,
|
||||||
onLoad = null,
|
onLoad = null,
|
||||||
|
onLowFps = null,
|
||||||
}) {
|
}) {
|
||||||
const [stage, setStage] = React.useState(null);
|
const [stage, setStage] = React.useState(null);
|
||||||
const [library, setLibrary] = React.useState(null);
|
const [library, setLibrary] = React.useState(null);
|
||||||
|
@ -165,6 +166,8 @@ function OutfitMovieLayer({
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const targetFps = library.properties.fps;
|
||||||
|
|
||||||
let lastFpsLoggedAtInMs = performance.now();
|
let lastFpsLoggedAtInMs = performance.now();
|
||||||
let numFramesSinceLastLogged = 0;
|
let numFramesSinceLastLogged = 0;
|
||||||
const intervalId = setInterval(() => {
|
const intervalId = setInterval(() => {
|
||||||
|
@ -181,16 +184,20 @@ function OutfitMovieLayer({
|
||||||
const roundedFps = Math.round(fps * 100) / 100;
|
const roundedFps = Math.round(fps * 100) / 100;
|
||||||
|
|
||||||
console.debug(
|
console.debug(
|
||||||
`[OutfitMovieLayer] FPS: ${roundedFps} (Target: ${library.properties.fps}, ${numFramesSinceLastLogged}, ${timeSinceLastFpsLoggedAtInSec}) (${libraryUrl})`
|
`[OutfitMovieLayer] FPS: ${roundedFps} (Target: ${targetFps}) (${libraryUrl})`
|
||||||
);
|
);
|
||||||
|
|
||||||
|
if (onLowFps && fps < 2) {
|
||||||
|
onLowFps(fps);
|
||||||
|
}
|
||||||
|
|
||||||
lastFpsLoggedAtInMs = now;
|
lastFpsLoggedAtInMs = now;
|
||||||
numFramesSinceLastLogged = 0;
|
numFramesSinceLastLogged = 0;
|
||||||
}
|
}
|
||||||
}, 1000 / library.properties.fps);
|
}, 1000 / targetFps);
|
||||||
|
|
||||||
return () => clearInterval(intervalId);
|
return () => clearInterval(intervalId);
|
||||||
}, [libraryUrl, stage, updateStage, movieClip, library, isPaused]);
|
}, [libraryUrl, stage, updateStage, movieClip, library, isPaused, onLowFps]);
|
||||||
|
|
||||||
// This effect keeps the `movieClip` scaled correctly, based on the canvas
|
// This effect keeps the `movieClip` scaled correctly, based on the canvas
|
||||||
// size and the `library`'s natural size declaration. (If the canvas size
|
// size and the `library`'s natural size declaration. (If the canvas size
|
||||||
|
|
|
@ -1,5 +1,12 @@
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { Box, DarkMode, Flex, Text, useColorModeValue } from "@chakra-ui/react";
|
import {
|
||||||
|
Box,
|
||||||
|
DarkMode,
|
||||||
|
Flex,
|
||||||
|
Text,
|
||||||
|
useColorModeValue,
|
||||||
|
useToast,
|
||||||
|
} from "@chakra-ui/react";
|
||||||
import LRU from "lru-cache";
|
import LRU from "lru-cache";
|
||||||
import { WarningIcon } from "@chakra-ui/icons";
|
import { WarningIcon } from "@chakra-ui/icons";
|
||||||
import { ClassNames } from "@emotion/react";
|
import { ClassNames } from "@emotion/react";
|
||||||
|
@ -54,6 +61,9 @@ export function useOutfitPreview({
|
||||||
onChangeHasAnimations = null,
|
onChangeHasAnimations = null,
|
||||||
...props
|
...props
|
||||||
}) {
|
}) {
|
||||||
|
const [isPaused, setIsPaused] = useLocalStorage("DTIOutfitIsPaused", true);
|
||||||
|
const toast = useToast();
|
||||||
|
|
||||||
const appearance = useOutfitAppearance({
|
const appearance = useOutfitAppearance({
|
||||||
speciesId,
|
speciesId,
|
||||||
colorId,
|
colorId,
|
||||||
|
@ -70,7 +80,26 @@ export function useOutfitPreview({
|
||||||
layersHaveAnimations,
|
layersHaveAnimations,
|
||||||
} = usePreloadLayers(visibleLayers);
|
} = usePreloadLayers(visibleLayers);
|
||||||
|
|
||||||
const [isPaused] = useLocalStorage("DTIOutfitIsPaused", true);
|
const onLowFps = React.useCallback(
|
||||||
|
(fps) => {
|
||||||
|
setIsPaused(true);
|
||||||
|
console.warn(`[OutfitPreview] Pausing due to low FPS: ${fps}`);
|
||||||
|
|
||||||
|
if (!toast.isActive("low-fps-warning")) {
|
||||||
|
toast({
|
||||||
|
id: "low-fps-warning",
|
||||||
|
status: "warning",
|
||||||
|
title: "Sorry, the animation was lagging, so we paused it! 😖",
|
||||||
|
description:
|
||||||
|
"We do this to help make sure your machine doesn't lag too much! " +
|
||||||
|
"You can unpause the preview to try again.",
|
||||||
|
duration: null,
|
||||||
|
isClosable: true,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
[setIsPaused, toast]
|
||||||
|
);
|
||||||
|
|
||||||
React.useEffect(() => {
|
React.useEffect(() => {
|
||||||
if (onChangeHasAnimations) {
|
if (onChangeHasAnimations) {
|
||||||
|
@ -100,6 +129,7 @@ export function useOutfitPreview({
|
||||||
loadingDelayMs={loadingDelayMs}
|
loadingDelayMs={loadingDelayMs}
|
||||||
spinnerVariant={spinnerVariant}
|
spinnerVariant={spinnerVariant}
|
||||||
onChangeHasAnimations={onChangeHasAnimations}
|
onChangeHasAnimations={onChangeHasAnimations}
|
||||||
|
onLowFps={onLowFps}
|
||||||
doTransitions
|
doTransitions
|
||||||
isPaused={isPaused}
|
isPaused={isPaused}
|
||||||
{...props}
|
{...props}
|
||||||
|
@ -122,6 +152,7 @@ export function OutfitLayers({
|
||||||
spinnerVariant = "overlay",
|
spinnerVariant = "overlay",
|
||||||
doTransitions = false,
|
doTransitions = false,
|
||||||
isPaused = true,
|
isPaused = true,
|
||||||
|
onLowFps = null,
|
||||||
...props
|
...props
|
||||||
}) {
|
}) {
|
||||||
const [hiResMode] = useLocalStorage("DTIHiResMode", false);
|
const [hiResMode] = useLocalStorage("DTIHiResMode", false);
|
||||||
|
@ -228,6 +259,7 @@ export function OutfitLayers({
|
||||||
width={canvasSize}
|
width={canvasSize}
|
||||||
height={canvasSize}
|
height={canvasSize}
|
||||||
isPaused={isPaused}
|
isPaused={isPaused}
|
||||||
|
onLowFps={onLowFps}
|
||||||
/>
|
/>
|
||||||
) : (
|
) : (
|
||||||
<Box
|
<Box
|
||||||
|
|
Loading…
Reference in a new issue