CSS3 过滤器性能和 CPU 用法:为什么某些过滤器会对 CPU 造成负担?
CSS3 filter performance & CPU usage: Why do certain filters tax the CPU?
考虑来自 David Nuon 的这个演示:
http://zunostudios.com/demos/css32014-demos/filters.html
正如大卫在他的 post 中注意到的:
You'll notice that the more the sliders are to the right, the less
responsive the page becomes.
这是真的。更改图像后,我看到我的 CPU 如何开始大量工作。
我自己无法回答的是为什么在所有 css 修改之后页面仍然没有响应。就像所有的动画都是 2fps。
如果工作完成了,为什么还要继续工作?
编辑:
在 xengravity 的帮助下,我可以看到也许在所有过滤器都向右之后,GPU 似乎以疯狂的速度执行以下操作:
1.- 拍摄原图。
2.- 修改它(数学计算、blabla 等)。
但总是从原始图像开始。也许这就是为什么它看起来这么慢....
编辑:将演示添加到片段中以备将来 posterity
var update_filter = function () {
var styles = [
'grayscale( ' + parseInt($('#grayscale').val()) * .01 + ')',
'blur( ' + $('#blur').val() + 'px)',
'sepia( ' + $('#sepia').val() + '%)',
'brightness( ' + parseInt($('#brightness').val()) * .01 + ')',
'contrast( ' + $('#contrast').val() * .1 + ')',
'hue-rotate( ' + $('#hue-rotate').val() * 3.6 + 'deg)',
'invert( ' + $('#invert').val() + '%)',
'saturate( ' + parseInt($('#saturate').val()) * .1 + ')',
'opacity( ' + parseInt($('#opacity').val()) * .01 + ')',
'drop-shadow( ' + (function (n) {
return '0px ' +
'0px ' +
n + 'px ' +
'black)'; }
)($('#drop-shadow').val()) ,
];
var styles = '-webkit-filter:\n' + styles.map(function (e) { return '\t' + e;} ).join('\n') + ';';
$('#image').attr('style', styles);
$('#code').val(styles);
};
$('#reset').click( function () {
$('#grayscale').val( $('#grayscale').data('default') );
$('#blur').val( $('#blur').data('default') );
$('#sepia').val( $('#sepia').data('default') );
$('#brightness').val( $('#brightness').data('default') );
$('#contrast').val( $('#contrast').data('default') );
$('#hue-rotate').val( $('#hue-rotate').data('default') );
$('#invert').val( $('#invert').data('default') );
$('#saturate').val( $('#saturate').data('default') );
$('#opacity').val( $('#opacity').data('default') );
$('#drop-shadow').val( $('#drop-shadow').data('default') );
update_filter();
});
$( 'input[type="range"]').change(update_filter );
update_filter();
body, html {
background: #fff;
}
.wrapper {
width: 800px;
height: 400px;
background: #fff;
border-radius: 5px;
position: relative;
margin: 60px auto 0 auto;
}
.controls {
background: #ddd;
width: 250px;
position: absolute;
right: 0;
bottom: 0;
top: 0;
}
.image {
background: url(transparency.png);
width: 550px;
position: absolute;
left: 0;
bottom: 0;
top: 0;
}
.controls {
padding: 0 0 0 0;
}
.controls li {
list-style: none;
margin: 0;
padding: 5px 15px;
border-bottom: 1px solid #aaa;
}
.controls li span {
font-size: 13px;
}
.controls li span::after {
content: '()';
}
.controls li input {
color: #333;
float: right;
}
#code {
position: absolute;
left:0;
right: 0;
bottom: -155px;
border:0;
font-family: monospace;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.0.3/jquery.min.js"></script>
<div class="wrapper">
<div class="image">
<img id="image" src="http://i.imgur.com/WdIGZ1t.png" alt="">
</div>
<div class="controls">
<ul class="controls"><li>
<span>blur</span>
<input type="range" id="blur" min="0" max="100" value="0" data-default="0">
</li>
<li>
<span>grayscale</span>
<input type="range" id="grayscale" min="0" max="100" value="0" data-default="0">
</li>
<li>
<span>drop-shadow</span>
<input type="range" id="drop-shadow" min="0" max="100" value="0" data-default="0">
</li>
<li>
<span>sepia</span>
<input type="range" id="sepia" min="0" max="100" value="0" data-default="0">
</li>
<li>
<span>brightness</span>
<input type="range" id="brightness" min="0" max="100" value="100" data-default="100">
</li>
<li>
<span>contrast</span>
<input type="range" id="contrast" min="0" max="100" value="10" data-default="10">
</li>
<li>
<span>hue-rotate</span>
<input type="range" id="hue-rotate" min="0" max="100" value="0" data-default="0">
</li>
<li>
<span>invert</span>
<input type="range" id="invert" min="0" max="100" value="0" data-default="0">
</li>
<li>
<span>saturate</span>
<input type="range" id="saturate" min="0" max="100" value="10" data-default="10">
</li>
<li>
<span>opacity</span>
<input type="range" id="opacity" min="0" max="100" value="100" data-default="100">
</li>
<li><button id="reset">Reset</button></li>
</div>
<textarea id="code" cols="20" rows="11"></textarea>
</div>
您会注意到,只有当您使用模糊或阴影时,性能才会受到严重影响。如果您使用任何其他过滤器,则很少 cpu 使用或任何性能影响的迹象。
首先要了解的是,并非所有过滤器都生而平等。
大多数过滤器在 1:1 级别上修改像素,这是一个相对直接的计算。
但是,当您使用 "blur" 或 "shadow" 引入任何内容时,它可能不再是 1:1 计算。
假设您使用半径参数并将其设置为 5px。您现在需要查看 5 倍的像素数量来计算模糊效果。
当您将此与其他过滤器组合在一起时,所需的计算量会增加。
现代浏览器能够利用 GPU 来帮助进行这些计算以加快处理速度,但您会注意到 GPU 较弱的设备会受到影响。
所以专门回答你的问题。过滤后CPU不是运行,其实还在计算中!当您像示例中那样输入疯狂的值(例如 100 像素的半径)时,您可以想象 CPU 上的计算强度有多大。
以下是 CSS 过滤器性能的快速指南:
- 灰度/快速
- 棕褐色/快速
- 饱和/快速
- 色调旋转/快速
- 反转/快速
- 不透明度/变量
- 亮度/快度
- 对比度/快
- 模糊/缓慢
- 阴影/慢速
- url() / 变量
这个"app"的主要问题是绘画。而且,如果您应用一些滤镜效果,或者甚至疯狂地使用滑块,您实际上是在使用非常适合 GPU 的计算量大的操作来杀死 CPU。它非常擅长这个东西。如果您使用时间轴工具并跟踪您的应用程序,您会看到大量的绿色条,这表明主线程上正在绘制和绘制 (CPU)。您需要做的是手动将使用这些滤镜效果的元素提升到层。您可以使用 transform: translateZ(0);
或新的 will-change: transform;
等一些 hack 来做到这一点,之后您将看到应用程序响应能力的巨大改进。但是在 2012 及以下一代的移动设备上,您可能会忘记良好的性能,这对他们来说太多了。
尝试通过开发工具添加此代码并观察结果,如果不是更快请告诉我?
img#image {
transform: translateZ(0); /*for older browsers*/
will-change: transform;
}
考虑来自 David Nuon 的这个演示:
http://zunostudios.com/demos/css32014-demos/filters.html
正如大卫在他的 post 中注意到的:
You'll notice that the more the sliders are to the right, the less responsive the page becomes.
这是真的。更改图像后,我看到我的 CPU 如何开始大量工作。
我自己无法回答的是为什么在所有 css 修改之后页面仍然没有响应。就像所有的动画都是 2fps。
如果工作完成了,为什么还要继续工作?
编辑: 在 xengravity 的帮助下,我可以看到也许在所有过滤器都向右之后,GPU 似乎以疯狂的速度执行以下操作:
1.- 拍摄原图。
2.- 修改它(数学计算、blabla 等)。
但总是从原始图像开始。也许这就是为什么它看起来这么慢....
编辑:将演示添加到片段中以备将来 posterity
var update_filter = function () {
var styles = [
'grayscale( ' + parseInt($('#grayscale').val()) * .01 + ')',
'blur( ' + $('#blur').val() + 'px)',
'sepia( ' + $('#sepia').val() + '%)',
'brightness( ' + parseInt($('#brightness').val()) * .01 + ')',
'contrast( ' + $('#contrast').val() * .1 + ')',
'hue-rotate( ' + $('#hue-rotate').val() * 3.6 + 'deg)',
'invert( ' + $('#invert').val() + '%)',
'saturate( ' + parseInt($('#saturate').val()) * .1 + ')',
'opacity( ' + parseInt($('#opacity').val()) * .01 + ')',
'drop-shadow( ' + (function (n) {
return '0px ' +
'0px ' +
n + 'px ' +
'black)'; }
)($('#drop-shadow').val()) ,
];
var styles = '-webkit-filter:\n' + styles.map(function (e) { return '\t' + e;} ).join('\n') + ';';
$('#image').attr('style', styles);
$('#code').val(styles);
};
$('#reset').click( function () {
$('#grayscale').val( $('#grayscale').data('default') );
$('#blur').val( $('#blur').data('default') );
$('#sepia').val( $('#sepia').data('default') );
$('#brightness').val( $('#brightness').data('default') );
$('#contrast').val( $('#contrast').data('default') );
$('#hue-rotate').val( $('#hue-rotate').data('default') );
$('#invert').val( $('#invert').data('default') );
$('#saturate').val( $('#saturate').data('default') );
$('#opacity').val( $('#opacity').data('default') );
$('#drop-shadow').val( $('#drop-shadow').data('default') );
update_filter();
});
$( 'input[type="range"]').change(update_filter );
update_filter();
body, html {
background: #fff;
}
.wrapper {
width: 800px;
height: 400px;
background: #fff;
border-radius: 5px;
position: relative;
margin: 60px auto 0 auto;
}
.controls {
background: #ddd;
width: 250px;
position: absolute;
right: 0;
bottom: 0;
top: 0;
}
.image {
background: url(transparency.png);
width: 550px;
position: absolute;
left: 0;
bottom: 0;
top: 0;
}
.controls {
padding: 0 0 0 0;
}
.controls li {
list-style: none;
margin: 0;
padding: 5px 15px;
border-bottom: 1px solid #aaa;
}
.controls li span {
font-size: 13px;
}
.controls li span::after {
content: '()';
}
.controls li input {
color: #333;
float: right;
}
#code {
position: absolute;
left:0;
right: 0;
bottom: -155px;
border:0;
font-family: monospace;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.0.3/jquery.min.js"></script>
<div class="wrapper">
<div class="image">
<img id="image" src="http://i.imgur.com/WdIGZ1t.png" alt="">
</div>
<div class="controls">
<ul class="controls"><li>
<span>blur</span>
<input type="range" id="blur" min="0" max="100" value="0" data-default="0">
</li>
<li>
<span>grayscale</span>
<input type="range" id="grayscale" min="0" max="100" value="0" data-default="0">
</li>
<li>
<span>drop-shadow</span>
<input type="range" id="drop-shadow" min="0" max="100" value="0" data-default="0">
</li>
<li>
<span>sepia</span>
<input type="range" id="sepia" min="0" max="100" value="0" data-default="0">
</li>
<li>
<span>brightness</span>
<input type="range" id="brightness" min="0" max="100" value="100" data-default="100">
</li>
<li>
<span>contrast</span>
<input type="range" id="contrast" min="0" max="100" value="10" data-default="10">
</li>
<li>
<span>hue-rotate</span>
<input type="range" id="hue-rotate" min="0" max="100" value="0" data-default="0">
</li>
<li>
<span>invert</span>
<input type="range" id="invert" min="0" max="100" value="0" data-default="0">
</li>
<li>
<span>saturate</span>
<input type="range" id="saturate" min="0" max="100" value="10" data-default="10">
</li>
<li>
<span>opacity</span>
<input type="range" id="opacity" min="0" max="100" value="100" data-default="100">
</li>
<li><button id="reset">Reset</button></li>
</div>
<textarea id="code" cols="20" rows="11"></textarea>
</div>
您会注意到,只有当您使用模糊或阴影时,性能才会受到严重影响。如果您使用任何其他过滤器,则很少 cpu 使用或任何性能影响的迹象。
首先要了解的是,并非所有过滤器都生而平等。
大多数过滤器在 1:1 级别上修改像素,这是一个相对直接的计算。
但是,当您使用 "blur" 或 "shadow" 引入任何内容时,它可能不再是 1:1 计算。
假设您使用半径参数并将其设置为 5px。您现在需要查看 5 倍的像素数量来计算模糊效果。
当您将此与其他过滤器组合在一起时,所需的计算量会增加。
现代浏览器能够利用 GPU 来帮助进行这些计算以加快处理速度,但您会注意到 GPU 较弱的设备会受到影响。
所以专门回答你的问题。过滤后CPU不是运行,其实还在计算中!当您像示例中那样输入疯狂的值(例如 100 像素的半径)时,您可以想象 CPU 上的计算强度有多大。
以下是 CSS 过滤器性能的快速指南:
- 灰度/快速
- 棕褐色/快速
- 饱和/快速
- 色调旋转/快速
- 反转/快速
- 不透明度/变量
- 亮度/快度
- 对比度/快
- 模糊/缓慢
- 阴影/慢速
- url() / 变量
这个"app"的主要问题是绘画。而且,如果您应用一些滤镜效果,或者甚至疯狂地使用滑块,您实际上是在使用非常适合 GPU 的计算量大的操作来杀死 CPU。它非常擅长这个东西。如果您使用时间轴工具并跟踪您的应用程序,您会看到大量的绿色条,这表明主线程上正在绘制和绘制 (CPU)。您需要做的是手动将使用这些滤镜效果的元素提升到层。您可以使用 transform: translateZ(0);
或新的 will-change: transform;
等一些 hack 来做到这一点,之后您将看到应用程序响应能力的巨大改进。但是在 2012 及以下一代的移动设备上,您可能会忘记良好的性能,这对他们来说太多了。
尝试通过开发工具添加此代码并观察结果,如果不是更快请告诉我?
img#image {
transform: translateZ(0); /*for older browsers*/
will-change: transform;
}