RecursiveBlur.qml 9.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294
  1. // Copyright (C) 2022 The Qt Company Ltd.
  2. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
  3. // Qt-Security score:significant reason:default
  4. import QtQuick
  5. import Qt5Compat.GraphicalEffects.private
  6. /*!
  7. \qmltype RecursiveBlur
  8. \inqmlmodule Qt5Compat.GraphicalEffects
  9. \since QtGraphicalEffects 1.0
  10. \inherits QtQuick2::Item
  11. \ingroup qtgraphicaleffects-blur
  12. \brief Blurs repeatedly, providing a strong blur effect.
  13. The RecursiveBlur effect softens the image by blurring it with an algorithm
  14. that uses a recursive feedback loop to blur the source multiple times. The
  15. effect may give more blurry results than
  16. \l{Qt5Compat.GraphicalEffects::GaussianBlur}{GaussianBlur} or
  17. \l{Qt5Compat.GraphicalEffects::FastBlur}{FastBlur}, but the result is produced
  18. asynchronously and takes more time.
  19. \table
  20. \header
  21. \li Source
  22. \li Effect applied
  23. \row
  24. \li \image Original_bug.png
  25. \li \image RecursiveBlur_bug.png
  26. \endtable
  27. \note This effect is available when running with OpenGL.
  28. \section1 Example
  29. The following example shows how to apply the effect.
  30. \snippet RecursiveBlur-example.qml example
  31. */
  32. Item {
  33. id: rootItem
  34. /*!
  35. This property defines the source item that is going to be blurred.
  36. \note It is not supported to let the effect include itself, for
  37. instance by setting source to the effect's parent.
  38. */
  39. property variant source
  40. /*!
  41. This property defines the distance of neighboring pixels which influence
  42. the blurring of individual pixels. A larger radius provides better
  43. quality, but is slower to render.
  44. \b Note: The radius value in this effect is not intended to be changed
  45. or animated frequently. The correct way to use it is to set the correct
  46. value and keep it unchanged for the whole duration of the iterative blur
  47. sequence.
  48. The value ranges from (no blur) to 16.0 (maximum blur step). By default,
  49. the property is set to \c 0.0 (no blur).
  50. \table
  51. \header
  52. \li Output examples with different radius values
  53. \li
  54. \li
  55. \row
  56. \li \image RecursiveBlur_radius1.png
  57. \li \image RecursiveBlur_radius2.png
  58. \li \image RecursiveBlur_radius3.png
  59. \row
  60. \li \b { radius: 2.5 }
  61. \li \b { radius: 4.5 }
  62. \li \b { radius: 7.5 }
  63. \row
  64. \li \l loops: 20
  65. \li \l loops: 20
  66. \li \l loops: 20
  67. \endtable
  68. */
  69. property real radius: 0.0
  70. /*!
  71. This property allows the effect output pixels to be cached in order to
  72. improve the rendering performance.
  73. Every time the source or effect properties are changed, the pixels in
  74. the cache must be updated. Memory consumption is increased, because an
  75. extra buffer of memory is required for storing the effect output.
  76. It is recommended to disable the cache when the source or the effect
  77. properties are animated.
  78. By default, the property is set to \c false.
  79. */
  80. property bool cached: false
  81. /*!
  82. This property defines the blur behavior near the edges of the item,
  83. where the pixel blurring is affected by the pixels outside the source
  84. edges.
  85. If the property is set to \c true, the pixels outside the source are
  86. interpreted to be transparent, which is similar to OpenGL
  87. clamp-to-border extension. The blur is expanded slightly outside the
  88. effect item area.
  89. If the property is set to \c false, the pixels outside the source are
  90. interpreted to contain the same color as the pixels at the edge of the
  91. item, which is similar to OpenGL clamp-to-edge behavior. The blur does
  92. not expand outside the effect item area.
  93. By default, the property is set to \c false.
  94. \table
  95. \header
  96. \li Output examples with different transparentBorder values
  97. \li
  98. \li
  99. \row
  100. \li \image RecursiveBlur_transparentBorder1.png
  101. \li \image RecursiveBlur_transparentBorder2.png
  102. \row
  103. \li \b { transparentBorder: false }
  104. \li \b { transparentBorder: true }
  105. \row
  106. \li \l loops: 20
  107. \li \l loops: 20
  108. \row
  109. \li \l radius: 7.5
  110. \li \l radius: 7.5
  111. \endtable
  112. */
  113. property bool transparentBorder: false
  114. /*!
  115. This property defines the amount of blur iterations that are going to be
  116. performed for the source. When the property changes, the iterative
  117. blurring process starts. If the value is decreased or if the value
  118. changes from zero to non-zero, a snapshot is taken from the source. The
  119. snapshot is used as a starting point for the process.
  120. The iteration loop tries to run as fast as possible. The speed might be
  121. limited by the VSYNC or the time needed for one blur step, or both.
  122. Sometimes it may be desirable to perform the blurring with a slower
  123. pace. In that case, it may be convenient to control the property with
  124. Animation which increases the value.
  125. The value ranges from 0 to inf. By default, the property is set to \c 0.
  126. \table
  127. \header
  128. \li Output examples with different loops values
  129. \li
  130. \li
  131. \row
  132. \li \image RecursiveBlur_loops1.png
  133. \li \image RecursiveBlur_loops2.png
  134. \li \image RecursiveBlur_loops3.png
  135. \row
  136. \li \b { loops: 4 }
  137. \li \b { loops: 20 }
  138. \li \b { loops: 70 }
  139. \row
  140. \li \l radius: 7.5
  141. \li \l radius: 7.5
  142. \li \l radius: 7.5
  143. \endtable
  144. */
  145. property int loops: 0
  146. /*!
  147. This property holds the progress of asynchronous source blurring
  148. process, from 0.0 (nothing blurred) to 1.0 (finished).
  149. */
  150. property real progress: loops > 0.0 ? Math.min(1.0, recursionTimer.counter / loops) : 0.0
  151. onLoopsChanged: recursiveSource.scheduleUpdate()
  152. onSourceChanged: recursionTimer.reset()
  153. onRadiusChanged: recursionTimer.reset()
  154. onTransparentBorderChanged: recursionTimer.reset()
  155. SourceProxy {
  156. id: sourceProxy
  157. input: rootItem.source
  158. sourceRect: rootItem.transparentBorder ? Qt.rect(-1, -1, parent.width + 2, parent.height + 2) : Qt.rect(0, 0, 0, 0)
  159. }
  160. ShaderEffectSource {
  161. id: cacheItem
  162. anchors.fill: verticalBlur
  163. smooth: true
  164. visible: rootItem.cached
  165. hideSource: visible
  166. live: true
  167. sourceItem: inputItem.visible ? inputItem : verticalBlur
  168. }
  169. Item {
  170. id: recursionTimer
  171. property int counter: 0
  172. function reset() {
  173. counter = 0
  174. recursiveSource.scheduleUpdate()
  175. }
  176. function nextFrame() {
  177. if (loops < counter)
  178. recursionTimer.counter = 0
  179. if (counter > 0)
  180. recursiveSource.sourceItem = verticalBlur
  181. else
  182. recursiveSource.sourceItem = inputItem
  183. if (counter < loops) {
  184. recursiveSource.scheduleUpdate()
  185. counter++
  186. }
  187. }
  188. }
  189. ShaderEffect {
  190. id: inputItem
  191. property variant source: sourceProxy.output
  192. property real expandX: rootItem.transparentBorder ? (horizontalBlur.maximumRadius) / horizontalBlur.width : 0.0
  193. property real expandY: rootItem.transparentBorder ? (horizontalBlur.maximumRadius) / horizontalBlur.height : 0.0
  194. anchors.fill: verticalBlur
  195. visible: !verticalBlur.visible
  196. vertexShader: "qrc:/qt-project.org/imports/Qt5Compat/GraphicalEffects/shaders_ng/recursiveblur.vert.qsb"
  197. fragmentShader: "qrc:/qt-project.org/imports/Qt5Compat/GraphicalEffects/shaders_ng/recursiveblur.frag.qsb"
  198. }
  199. ShaderEffectSource {
  200. id: recursiveSource
  201. visible: false
  202. smooth: true
  203. hideSource: false
  204. live: false
  205. sourceItem: inputItem
  206. recursive: true
  207. onSourceItemChanged: scheduleUpdate()
  208. onScheduledUpdateCompleted: recursionTimer.nextFrame()
  209. }
  210. GaussianDirectionalBlur {
  211. id: verticalBlur
  212. x: rootItem.transparentBorder ? -horizontalBlur.maximumRadius - 1 : 0
  213. y: rootItem.transparentBorder ? -horizontalBlur.maximumRadius - 1 : 0
  214. width: horizontalBlur.width + 2
  215. height: horizontalBlur.height + 2
  216. horizontalStep: 0.0
  217. verticalStep: 1.0 / parent.height
  218. source: ShaderEffectSource {
  219. sourceItem: horizontalBlur
  220. hideSource: true
  221. visible: false
  222. smooth: true
  223. }
  224. deviation: (radius + 1) / 2.3333
  225. radius: rootItem.radius
  226. maximumRadius: Math.ceil(rootItem.radius)
  227. transparentBorder: false
  228. visible: loops > 0
  229. }
  230. GaussianDirectionalBlur {
  231. id: horizontalBlur
  232. width: rootItem.transparentBorder ? parent.width + 2 * maximumRadius + 2 : parent.width
  233. height: rootItem.transparentBorder ? parent.height + 2 * maximumRadius + 2 : parent.height
  234. horizontalStep: 1.0 / parent.width
  235. verticalStep: 0.0
  236. source: recursiveSource
  237. deviation: (radius + 1) / 2.3333
  238. radius: rootItem.radius
  239. maximumRadius: Math.ceil(rootItem.radius)
  240. transparentBorder: false
  241. visible: false
  242. }
  243. }