使用任意QML项作为缓存图像源 [英] Using arbitrary QML items as cached image source

查看:911
本文介绍了使用任意QML项作为缓存图像源的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

编辑:原始问题仍然包含在下面,但我决定重新标题一个对开发人员在各种情况下更有用的表格,其中一些在下面的答案中描述,作为解决方案。最初的问题是提供了更广泛的应用领域。






我有一套应用程序的灰度图标,并且要求用户可以更改图标颜色。



因此,显而易见的解决方案是使用库存 Colorize 元素来自 QtGraphicalEffects



效果本身有缓存 property - 缓存特定效果的结果,以便不连续计算。但是,这仅适用于该效果的特定实例,这意味着如果有多个图标实例,并且每个实例都具有着色效果,则不会在不同实例之间共享此缓存。



显然,单个缓存就足够了,考虑到所有图标的大小和颜色都相同,VRAM中的数据可以重复使用,节省VRAM和GPU时间。



所以最大的问题是如何重用该单一效果的单个缓存并多次显示它而不会产生任何开销。



此外,上一个问题是关于我用彩色图标拍摄的当前课程。然而,我可能还有另一种方法。



当然,效率是关键,但也需要简单,我的意思是我可以想到几种低级别的方法非常有效,但它们都需要更复杂的低级实现,它们不可能在QML中完成。

解决方案

解决方案结果出乎意料的简单。



在特定于OP的情况下 - 即着色图标,最有效的方法是简单地使用自定义 ShaderEffect 带有普通片段着色器 - 将 gl_FragColor 设置为所需的颜色,作为<$ c $传递c> vec4 和来源图像的alpha值。实际上没有必要缓存任何东西,因为着色器非常简单快速,而且速度很快。



只有一件事要考虑 - 可能性QML场景图可能会在纹理图集中分配原始图像,然后默认实现将纹理从图集复制到另一个纹理。我们不希望这个因为它失败了目的 - VRAM的使用会上升,因为这将针对每个实例进行,并且新分配的纹理也可能比他们需要的更大因为在某些平台上,纹理的尺寸有限,在这种情况下我们正在谈论图标,所以它们不会那么大。



解决方案是将 supportsAtlasTextures 显式设置为true。这意味着您还必须在图集中传递纹理的偏移量并计算偏移量 - 仍然是非常小的开销。这将确保效率,来自地图集的纹理不会在内存中重复,此外,渲染引擎实际上允许使用来自相同地图集的不同纹理的不同着色器效果在一次调用中一起批处理。






类似的方法可用于缓存几乎任何东西,并使用该缓存来显示图像 - 使用a ShaderEffectSource 捕获所需的图像,然后使用 ShaderEffect 使用更简单的片段着色器 - 只需从源采样器输出数据。几个非常有用的用例立即浮现在脑海中:




  • 它可用于实例化图像,计算强度着色器的结果,请记住, ShaderEffectSource s和 ShaderEffect 可以按任意顺序链接

  • 它可以用来实例化程序生成的图像,再次使用着色器,这样可以用作平铺纹理,甚至可以非常高效地动画

  • 它可以与QML Canvas一起使用使用复杂的画布绘图作为缓存和多个图像的来源

  • 它可以用作图像,由复杂QML的组合生成 Item s - 那些在RAM上实际上相当沉重,想象一下你有1000个对象的场景,每个对象都是由20个不同的QML项目构成的 - 矩形,文本,图像,上帝禁止动画,这是内存中的20000个对象 - 就像我的测试基于500 MB的RAM使用量,但如果它们是相同的,单个对象可用于提供缓存,而所有其他对象只能使用单个着色器效果来显示该缓存。它也会对CPU时间产生影响 - 比如你的设计必然会改变值 - 这是一种非常常见的情况,如果你在内存中有20000个对象,那就是20000个评估绑定 - 即使对于琐碎的表达式,这在移动设备上可能需要几秒钟,在此期间冻结屏幕。缓存可以将冻结时间缩短1000次,几乎不存在。


  • 它还可以用来缓存和实例化动画,大大减少了所需的时间CPU时间,也可以使用视频



EDIT: The original question is still contained below, but I decided to re-title to a form that will be more useful to developers in a variety of cases, some of which described in my answer below, as the solution to the original problem turned out to provide a much wider area of application.


I have a set of greyscale icons for an application, and a requirement that the icon color can be changed by the user.

So, the obvious solution is to use the stock Colorize element from QtGraphicalEffects.

The effect itself has a cached property - which caches the result of that particular effect so that it is not continuously calculated. However, this only applies to that particular instance of the effect, meaning if there are multiple icon instances, and every one has a colorize effect, this cache will not be shared between the different instances.

Obviously, one single cache would be enough, considering that all icons are the same size and color, that data from VRAM can be reused, saving on VRAM and GPU time.

So the big question is how to reuse that single cache of that single effect and display it multiple times without any overheads.

Also, the previous question is regarding the current course I've taken with colorizing icons. However, there might be another approach I am missing.

Naturally, efficiency is key, but simplicity is also desired, I mean I can think of several low level ways to do that very efficiently, but they all require more complex low level implementations, they are not possible to do in QML.

解决方案

The solution turned out to be unexpectedly simple.

In the case, specific to the OP - that is colorize icons, the most efficient way is to simply use a custom ShaderEffect with a trivial fragment shader - set gl_FragColor to the desired color, passed as a vec4 and the alpha value from the source image. There is really no need to cache anything, as the shader is really simple and fast, as fast as it gets.

There is only one thing to consider - the possibility that the QML scenegraph might allocate the original image in a texture atlas, the default implementation will then copy the texture from the atlas to another texture. We do not want this as it defeats the purpose - VRAM usage will rise, as this will be done for every "instance" and there is also the possibility that the newly allocate textures will be larger than they need to be, since on some platforms, there is a limitation to how small a texture can be, and in this case we are talking icons, so they won't be all that big.

The solution is to explicitly set supportsAtlasTextures to true. This means you must also pass the offset of the texture in the atlas and calculate the offset - still very little overhead. This will ensure efficiency, textures from atlases will not be duplicated in memory, and furthermore, the render engine will actually allow different shader effects using different texture from the same atlas to be batched together in one call.


A similar approach can be used to cache pretty much anything, and use that cache to display an "image" - use a ShaderEffectSource to "capture" the desired image, and then use a ShaderEffect with an even more trivial fragment shader - simply output the data from the source sampler. Several extremely useful use-cases immediately come to mind:

  • it can be used to "instantiate" images, the result of computationally intenssive shaders, keep in mind that ShaderEffectSources and ShaderEffects can be chained in arbitrary order
  • it can be used to instantiate procedurally generated images, once again using shaders, such can be used as tiling textures, and even animated very efficiently
  • it can be used together with a QML Canvas to use a complex canvas drawing as a cache and source for multiple "images"
  • it can be used as an image, produced by the composition of complex QML Items - those are actually quite heavy on RAM, imagine a scenario where you have a 1000 objects, and each of them is made out of 20 different QML items - rectangles, texts, images, god forbid animations, that's 20000 object in memory - that's like 500 MBs of RAM usage based on my tests, but if they are identical, a single object can be used to provide cache, and all the other objects can only use a single shader effect to display that cache. It has implications on CPU time as well - say your design is bound to changing values - a very usual scenario, if you have 20000 objects in memory, that's 20000 evaluated bindings - even for trivial expressions this may take several seconds on a mobile device, freezing the screen for that duration. Caching that will reduce the freeze time 1000 times, practically to non-existent.

  • it can can also be used to cache and instantiate animations, significantly reducing the needed CPU time, and also it can work with video as well

这篇关于使用任意QML项作为缓存图像源的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆