Detect browser graphics performance?

余生颓废 提交于 2021-02-07 08:56:14

问题


I have a graphically intensive website. It has all kinds of CSS3 animations running over a blurred video background. It looks great on my desktop and on GPU-enabled MacBook Pros, but it runs like junk on my laptop and MacBook Air.

So basically, I want to know if there is a way to detect Browser graphics performance with Javascript (or anything) and then only apply the CSS animations if the performance reaches a threshold. The site has a loading screen, so I have some time to test for performance.

I know I can detect WebGL with Modernizr, but unfortunately even my laptop tests positive for WebGL even though performance is very poor so I need an alternative.

Thanks


回答1:


This is an old question, but I'll give my 2 cents since I dealt with something similar recently.

I did something similar using GreenSock to measure frame drops. But I'm sure it's very similar if you want to implement it with requestAnimationFrame.

The following code works as follows:

  1. listen to animation frame

    Since I'm using GSAP, I'm listening to the TweenLite.ticker 'tick' event. For requestAnimationFrame, you can do the same with window.requestAnimationFrame(callback);

  2. measure the number of frames every second and update additional data like lowestFrameRate & numberOfDrops

  3. if the condition applies, simplify the calculations to improve FPS

    The condition can either be the lowest FPS for the site (lowestFrameRate), or the number of times a frame drop occurred (numberOfDrops). It depends on your specific strategy

FPS(true /* showDebugBox */ );

function FPS(showDebugBox) {

  // SHOW FRAMERATE UI FOR DEBUGGING
  if (showDebugBox) {
    $('body').append([
      '<div class="hud">',
      'FPS: <span id="framerate">0</span>; ',
      'lowest FPS: <span id="lowest">null</span>; ',
      'DROPS Below 30: <span id="drops">0</span>',
      '</div>'
    ].join(''));
  }

  var $framerate = showDebugBox ? document.querySelector("#framerate") : {};
  var $lowest = showDebugBox ? document.querySelector("#lowest") : {};
  var $drops = showDebugBox ? document.querySelector("#drops") : {};
  var prevTime = 0;
  var frames = 0;
  var ticker = TweenLite.ticker;

  var fps;

  // will keep the lowest framerate the site was rendered at
  // keep in mind that the first render is almost always lower
  // than the average framerate later
  var lowestFrameRate = -1;
  // will keep tab on the number of drops below 30fps.
  // when this happens, disable some animations in order to
  // keep the requestAnimationFrame cycle short
  var numberOfDrops = 0;

  ticker.addEventListener("tick", update);

  function update() {

    var current = ticker.time;

    frames++;

    if (current > prevTime + 1) {
      fps = Math.round(frames / (current - prevTime));
      $framerate.textContent = fps;
      prevTime = current;
      frames = 0;

      // initialize lowestFrameRate with first fps value
      if (lowestFrameRate === -1) {
        lowestFrameRate = fps;

        $lowest.textContent = lowestFrameRate;
        console.info('lowest framrate initialized', lowestFrameRate);
      }

      // update lowest frame rate
      if (fps < lowestFrameRate) {
        lowestFrameRate = fps;

        $lowest.textContent = lowestFrameRate;
        console.info('lowest framerate', lowestFrameRate);
      }

      // update number of times frame rate dropped below 30
      if (fps < 30) {
        numberOfDrops++;

        // you can reduce the complexity of the animations
        // here if you want to base it on a drop below a threshold

        $drops.textContent = numberOfDrops;
        console.info('framerate dropped below 30');
      }

      // if there were more than 2 drops
      if (numberOfDrops >= 2) {
        // you can reduce the complexity of the animations here
        // if you want to base it on the number of drops.

        // you also need to define an end scenario for this thing
        // what happens if the frames continue to drop?
      }
    }
  }
}
.hud {
  position: fixed;
  top: 0;
  left: 0;
  font-family: "Lucida Console", Monaco, monospace;
  letter-spacing: 1px;
  line-height: 1.6;
  font-size: 10px;
  padding: 4px 8px;
  background: rgba(0, 0, 0, 0.3);
  pointer-events: none;
  user-select: none;
  z-index: 5000;
}

body {
  height: 500vh;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/1.19.0/TweenMax.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>



回答2:


As suggested by @blazemonger you can use window.requestAnimationFrame to detect the current FPS rate. Presumably if the FPS rate drops below a certain value you could automatically disable animations.

I also recommend having a "Stop animations" button placed somewhere conspicious on your website for the benefit of those of us who prefer static websites for readability's sake, in addition to those who don't want to drain their laptop batteries more than usual.

Here is a crude example of something that will stop any animations if the frame-rate drops below 30Hz:

var start = null;
var last  = null;
window.requestAnimationFrame(fpsMeasureLoop);
function fpsMeasureLoop(timestamp) {
    if( start == null ) {
        last = start = timestamp;
        return;
    }
    var dTime = timestamp - last;
    if( dTime > 33 ) {
        // If more than 33ms since last frame (i.e. below 30fps)
        document.getElementsByTagName("body")[0].className = "paused";
    }
    window.requestAnimationFrame(fpsMeasureLoop);
}

You'll need this CSS:

.paused{
    -webkit-animation-play-state:paused;
    -moz-animation-play-state:paused;
    -o-animation-play-state:paused; 
    animation-play-state:paused;
}

It's buggy because if the framerate drops below 30Hz for any reason it will stop them. Adding logic to spot trending framerates is an exercise for the reader.



来源:https://stackoverflow.com/questions/28729514/detect-browser-graphics-performance

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!