1Name 2 3 KHR_swap_buffers_with_damage 4 5Name Strings 6 7 EGL_KHR_swap_buffers_with_damage 8 9Contributors 10 11 Robert Bragg 12 Tapani Pälli 13 Kristian Høgsberg 14 Benjamin Franzke 15 Ian Stewart 16 James Jones 17 Ray Smith 18 19Contact 20 21 Robert Bragg, Intel (robert.bragg 'at' intel.com) 22 23IP Status 24 25 No known claims. 26 27Notice 28 29 Copyright (c) 2014 The Khronos Group Inc. Copyright terms at 30 http://www.khronos.org/registry/speccopyright.html 31 32Status 33 34 Complete. 35 Approved by the EGL Working Group on September 17, 2014. 36 Approved by the Khronos Board of Promoters on November 7, 2014. 37 38Version 39 40 Version 13, February 20, 2020 41 42Number 43 44 EGL Extension #84 45 46Extension Type 47 48 EGL display extension 49 50Dependencies 51 52 Requires EGL 1.4 53 54 This extension is written against the wording of the EGL 1.4 55 Specification. 56 57Overview 58 59 This extension provides a means to issue a swap buffers request to 60 display the contents of the current back buffer and also specify a 61 list of damage rectangles that can be passed to a system 62 compositor so it can minimize how much it has to recompose. 63 64 This should be used in situations where an application is only 65 animating a small portion of a surface since it enables the 66 compositor to avoid wasting time recomposing parts of the surface 67 that haven't changed. 68 69Terminology 70 71 This extension and the EGL_KHR_partial_update extension both use the word 72 "damage" for subtly but significantly different purposes: 73 74 "Surface damage" is what the EGL_KHR_swap_buffers_with_damage extension 75 is concerned with. This is the area of the *surface* that changes between 76 frames for that surface. It concerns the differences between two buffers - 77 the current back buffer and the current front buffer. It is useful only to 78 the consumer. 79 80 "Buffer damage" is what the EGL_KHR_partial_update extension is concerned 81 with. This is the area of a particular buffer that has changed since that 82 same buffer was last used. As it only concerns changes to a single buffer, 83 there is no dependency on the next or previous frames or any other buffer. 84 It therefore cannot be used to infer anything about changes to the surface, 85 which requires linking one frame or buffer to another. Buffer damage is 86 therefore only useful to the producer. 87 88 Following are examples of the two different damage types. Note that the 89 final surface content is the same in both cases, but the damaged areas 90 differ according to the type of damage being discussed. 91 92Surface damage example (EGL_KHR_swap_buffers_with_damage) 93 94 The surface damage for frame n is the difference between frame n and frame 95 (n-1), and represents the area that a compositor must recompose. 96 97 Frame 0 Frame 1 Frame 2 Frame 3 Frame 4 98 +---------+ +---------+ +---------+ +---------+ +---------+ 99 | | |#########| |#########| |#########| |#########| 100 | | | | |#########| |#########| |#########| Final surface 101 | | | | | | |#########| |#########| content 102 | | | | | | | | |#########| 103 +---------+ +---------+ +---------+ +---------+ +---------+ 104 105 +---------+ +---------+ +---------+ +---------+ +---------+ 106 |@@@@@@@@@| |@@@@@@@@@| | | | | | | 107 |@@@@@@@@@| | | |@@@@@@@@@| | | | | Surface damage 108 |@@@@@@@@@| | | | | |@@@@@@@@@| | | 109 |@@@@@@@@@| | | | | | | |@@@@@@@@@| 110 +---------+ +---------+ +---------+ +---------+ +---------+ 111 112Buffer damage example (EGL_KHR_partial_update) 113 114 The buffer damage for a frame is the area changed since that same buffer was 115 last used. If the buffer has not been used before, the buffer damage is the 116 entire area of the buffer. 117 118 The buffer marked with an 'X' in the top left corner is the buffer that is 119 being used for that frame. This is the buffer to which the buffer age and 120 the buffer damage relate. 121 122 Note that this example shows a double buffered surface - the actual number 123 of buffers could be different and variable throughout the lifetime of the 124 surface. The age *must* therefore be queried for every frame. 125 126 Frame 0 Frame 1 Frame 2 Frame 3 Frame 4 127 +---------+ +---------+ +---------+ +---------+ +---------+ 128 | | |#########| |#########| |#########| |#########| 129 | | | | |#########| |#########| |#########| Final surface 130 | | | | | | |#########| |#########| content 131 | | | | | | | | |#########| 132 +---------+ +---------+ +---------+ +---------+ +---------+ 133 134 X---------+ +---------+ X---------+ +---------+ X---------+ 135 | | | | |#########| |#########| |#########| 136 | | | | |#########| |#########| |#########| Buffer 1 content 137 | | | | | | | | |#########| 138 | | | | | | | | |#########| 139 +---------+ +---------+ +---------+ +---------+ +---------+ 140 141 X---------+ +---------+ X---------+ +---------+ 142 |#########| |#########| |#########| |#########| 143 | | | | |#########| |#########| Buffer 2 content 144 | | | | |#########| |#########| 145 | | | | | | | | 146 +---------+ +---------+ +---------+ +---------+ 147 148 0 0 2 2 2 Buffer age 149 150 +---------+ +---------+ +---------+ +---------+ +---------+ 151 |@@@@@@@@@| |@@@@@@@@@| |@@@@@@@@@| | | | | 152 |@@@@@@@@@| |@@@@@@@@@| |@@@@@@@@@| |@@@@@@@@@| | | Buffer damage 153 |@@@@@@@@@| |@@@@@@@@@| | | |@@@@@@@@@| |@@@@@@@@@| 154 |@@@@@@@@@| |@@@@@@@@@| | | | | |@@@@@@@@@| 155 +---------+ +---------+ +---------+ +---------+ +---------+ 156 157 158New Procedures and Functions 159 160 EGLBoolean eglSwapBuffersWithDamageKHR ( 161 EGLDisplay dpy, 162 EGLSurface surface, 163 const EGLint *rects, 164 EGLint n_rects); 165 166New Tokens 167 168 None 169 170Changes to Chapter 3 of the EGL 1.4 Specification (EGL Functions and Errors) 171 172 Add the following text to subsection 3.9.1 titled "Posting to a 173 Window" after the description of eglSwapBuffers. 174 175 As an alternative to eglSwapBuffers use: 176 177 EGLBoolean eglSwapBuffersWithDamageKHR ( 178 EGLDisplay dpy, 179 EGLSurface surface, 180 const EGLint *rects, 181 EGLint n_rects); 182 183 to do the same thing as eglSwapBuffers but additionally report 184 a list of rectangles that define the region that has truly 185 changed since the last frame. To be clear; the entire contents 186 of the back buffer will still be swapped to the front so 187 applications using this API must still ensure that the entire 188 back buffer is consistent. The rectangles are only a hint for 189 the system compositor so it can avoid recomposing parts of the 190 surface that haven't really changed. 191 <rects> points to a list of integers in groups of four that 192 each describe a rectangle in screen coordinates in this 193 layout: {x, y, width, height}. The rectangles are specified 194 relative to the bottom-left of the surface and the x and y 195 components of each rectangle specify the bottom-left position 196 of that rectangle. <n_rects> determines how many groups of 4 197 integers can be read from <rects>. It is not necessary to 198 avoid overlaps of the specified rectangles. 199 If <n_rects> is 0 then <rects> is ignored and the entire 200 surface is implicitly damaged and the behaviour is equivalent 201 to calling eglSwapBuffers. 202 The error conditions checked for are the same as for the 203 eglSwapBuffers api. 204 205 Modify the first paragraph of Section 3.9.1 titled "Native Window 206 Resizing" 207 208 "If the native window corresponding to <surface> has been 209 resized prior to the swap, <surface> must be resized to match. 210 <surface> will normally be resized by the EGL implementation 211 at the time the native window is resized. If the 212 implementation cannot do this transparently to the client, 213 then eglSwapBuffers and eglSwapBuffersWithDamageKHR must 214 detect the change and resize surface prior to copying its 215 pixels to the native window. In this case the meaningfulness 216 of any damage rectangles forwarded by 217 eglSwapBuffersWithDamageKHR to the native window system is 218 undefined." 219 220 Modify the following sentences in Section 3.9.3, page 51 (Posting 221 Semantics) 222 223 Paragraph 2, first sentence: 224 225 "If <dpy> and <surface> are the display and surface for the 226 calling thread's current context, eglSwapBuffers, 227 eglSwapBuffersWithDamageKHR, and eglCopyBuffers perform an 228 implicit flush operation on the context (glFlush for OpenGL or 229 OpenGL ES context, vgFlush for an OpenVG context)." 230 231 Paragraph 3, first sentence: 232 233 "The destination of a posting operation (a visible window, for 234 eglSwapBuffers or eglSwapBuffersWithDamageKHR, or a native 235 pixmap, for eglCopyBuffers) should have the same number of 236 components and component sizes as the color buffer it's being 237 copied from." 238 239 Paragraph 6, first two sentences: 240 241 "The function 242 243 EGLBoolean eglSwapInterval(EGLDisplay dpy, EGLint 244 interval); 245 246 specifies the minimum number of video frame periods per color 247 buffer post operation for the window associated with the 248 current context. The interval takes effect when eglSwapBuffers 249 or eglSwapBuffersWithDamageKHR is first called subsequent to 250 the eglSwapInterval call." 251 252 Modify the following sentences in Section 3.9.4, page 52 (Posting 253 Errors) 254 255 Paragraph 1, first sentence: 256 257 "eglSwapBuffers, eglSwapBuffersWithDamageKHR, and 258 eglCopyBuffers return EGL_FALSE on failure." 259 260 Paragraph 1, seventh sentence: 261 262 "If eglSwapBuffers or eglSwapBuffersWithDamageKHR are called 263 and the native window associated with <surface> is no longer 264 valid, an EGL_BAD_NATIVE_WINDOW error is generated. If 265 eglSwapBuffersWithDamageKHR is called and <n_rects>, is less 266 than zero or <n_rects> is greater than zero but <rects> is 267 NULL, EGL_BAD_PARAMETER is generated." 268 269Dependencies on OpenGL ES 270 271 None 272 273Dependencies on OpenVG 274 275 None 276 277Issues 278 2791) Do applications have to make sure the rectangles don't overlap? 280 281 RESOLVED: No, that would be inconvenient for applications and we 282 see no difficulty for implementations to supporting overlapping 283 rectangles. 284 2852) Would it be valid for an implementation to discard the list of 286 rectangles internally and work just in terms of the 287 eglSwapBuffers api? 288 289 RESOLVED: Yes, the rectangles are only there for optimization 290 purposes so although it wouldn't be beneficial to applications if 291 it was convenient at times then it would be compliant for an 292 implementation to discard the rectangles and just call 293 eglSwapBuffers instead. The error conditions that should be 294 checked for are compatible with the requirements for 295 eglSwapBuffers. 296 2973) What origin should be used for damage rectangles? 298 299 RESOLVED: Bottom left since this is consistent with all other 300 uses of 2D window coordinates in EGL and OpenGL that specify a 301 bottom left origin. 302 303 Originally this specification was written with a top-left origin 304 for the damage rectangles even though it was known to be 305 inconsistent and that was because most window systems use a 306 top-left origin and there are some awkward semantic details 307 related to handling native window resizing that we had hoped to 308 simplify. 309 310 This extension and also several other existing EGL extensions 311 struggle to guarantee a reliable behaviour in response to native 312 window resizing which can happen asynchronously on some platforms 313 and this can make it difficult for applications to avoid certain 314 visual artefacts. 315 316 The crux of the problem is that when a native window is 317 asynchronously resized then the window system may maintain the old 318 buffer contents with respect to a different origin than EGL's 319 bottom left origin. For this extension that means that EGL damage 320 rectangles that are intended to map to specific surface contents 321 may end up mapping to different contents when a native window is 322 resized because the rectangles and buffer contents will be moved in 323 different directions in relation to the new window size. 324 325 In the end we decided that this issue isn't simply solved by 326 choosing to use a top-left origin and so we can instead aim for 327 consistency and clarify what guarantees we offer in relation to 328 native window resizing separate from this issue. 329 3304) What guarantees do we provide about the meaningfulness of EGL 331 damage rectangles that are forwarded to the native window system 332 when presenting to a native window that has been resized? 333 334 RESOLVED: The meaningfulness of those forwarded damage rectangles 335 is undefined since this simplifies the implementation requirements 336 and we saw very little benefit to applications from providing 337 stricter guarantees. 338 339 The number of applications that would be able to avoid fully 340 redrawing the contents of a window in response to a window resize 341 is expected to be so low that there would be almost no benefit to 342 defining strict guarantees here. 343 344 Since EGL already states that the contents of window surface 345 buffers become undefined when a native window has been resized, 346 this limitation doesn't introduce any new issue for applications 347 to consider. Applications should already fully redraw buffer 348 contents in response to a native window resize, unless they are 349 following some platform specific documentation that provides 350 additional guarantees. 351 352 For an example of the implementation details that make this an 353 awkward issue to provide guarantees for we can consider X11 based 354 platforms where native windows can be resized asynchronously with 355 respect to a client side EGL surface: 356 357 With X11 there may be multiple "gravity" transformations that can 358 affect how surface buffer content is positioned with respect to a 359 new native window size; there is the core X "bit gravity" and 360 there is the EGL driver gravity that determines how a surface's 361 contents with one size should be mapped to a native window with a 362 different size. Without very careful cooperation between the EGL 363 driver and the core X implementation and without the right 364 architecture to be able to do transforms atomically with respect 365 to different clients that may enact a window resize then it is not 366 possible to reliably map EGL damage rectangles to native window 367 coordinates. 368 369 The disadvantage of a driver that is not able to reliably map EGL 370 damage rectangles to native window coordinates is that a native 371 compositor may re-compose the wrong region of window. This may 372 result in a temporary artefact until the full window gets redrawn 373 and then re-composed. X11 already suffers other similar transient 374 artefacts when resizing windows. 375 376 The authors of this spec believe that even if a driver can't do 377 reliable mappings of EGL damage rectangles then compositors would 378 be able mitigate the majority of related artefacts by ignoring 379 sub-window damage during an interactive window resize. 380 381 The authors of this spec believe that that if an X11 driver did 382 want to reliably map EGL damage rectangles to the native window 383 coordinates then that may be technically feasible depending on the 384 driver architecture. For reference one approach that had been 385 considered (but not tested) is as follows: 386 387 1) When eglSwapBuffersWithDamageKHR is called, send EGL damage 388 rectangles from the client to a driver component within the 389 xserver un-transformed in EGL window surface coordinates with a 390 bottom-left origin. 391 392 2) Within the X server the driver component should look at the 393 bit-gravity of a window and use the bit-gravity convention to 394 copy EGL surface content to the front-buffer of a native window. 395 396 3) Within the X server the driver component should use the same 397 gravity transform that was used to present the surface content 398 to also transform the EGL damage rectangle coordinates. 399 400 Note that because this transform is done in the xserver then 401 this is implicitly synchronized with all clients that would 402 otherwise be able to enact an asynchronous window resize. 403 404 405Revision History 406 407 Version 1, 29/07/2011 408 - First draft 409 Version 2, 03/08/2011 410 - Clarify that the rectangles passed may overlap 411 Version 3, 01/09/2011 412 - Fix a missing '*' in prototype to make rects a pointer 413 Version 4, 11,02,2012 414 - Clarify that implementing in terms of eglSwapBuffers would be 415 compliant. 416 Version 5, 11,02,2012 417 - Tweak the cases where we report BAD_PARAMETER errors 418 Version 6, 05/02/2013 419 - Specify more thorough updates across the EGL 1.4 spec 420 wherever it relates to the eglSwapBuffers api 421 - Clarify that passing <n_rects> of 0 behaves as if 422 eglSwapBuffers were called. 423 Version 7, 14/02/2013 424 - Specify that a bottom-left origin should be used for rectangles 425 Version 8, 19/03/2013 426 - Add Ian and James as contributors 427 - Add an issue explaining why we changed to a bottom-left origin 428 - Clarify that the behaviour is undefined when presenting to a 429 native window that has been resized. 430 - Document the awkward details that would be involved in 431 providing more strict guarantees when presenting to a native 432 window that has been resized. 433 Version 9, 12/06/2013, Chad Versace <chad.versace@intel.com> 434 - Remove the "all rights reserved" clause from the copyright notice. The 435 removal does not change the copyright notice's semantics, since the 436 clause is already implied by any unadorned copyright notice. But, the 437 removal does diminish the likelihood of unwarranted caution in readers 438 of the spec. 439 - Add "IP Status" section to explicitly state that this extension has no 440 knonw IP claims. 441 Version 10, 19/08/2014 442 - Draft for promoting to KHR 443 - Added section on terminology and damage types 444 Version 11, 10/09/2014 445 - Marked as display extension 446 Version 12, 11/05/2014 447 - Change copyright to Khronos after signoff from Intel. 448 Version 13, 20/02/2020, Jon Leech 449 - Constify rects parameter (EGL-Registry issue 98). 450