The open source OpenXR runtime

u/aeg: Implement state machine to correct overshooting and avoid oscillations

authored by

Mateo de Mayo and committed by
Jakob Bornecrantz
85bdbc18 bf311f3c

+204 -25
+4
doc/images/autoexpgain.drawio.svg
··· 1 + <?xml version="1.0" encoding="UTF-8"?> 2 + <!-- Do not edit this file with editors other than diagrams.net --> 3 + <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"> 4 + <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="600px" height="374px" viewBox="-0.5 -0.5 600 374" content="&lt;mxfile host=&quot;app.diagrams.net&quot; modified=&quot;2022-05-18T11:34:31.416Z&quot; agent=&quot;5.0 (X11)&quot; etag=&quot;lviUBxbUCX1CSFnUuSq4&quot; version=&quot;18.0.6&quot; type=&quot;device&quot;&gt;&lt;diagram name=&quot;Page-1&quot; id=&quot;58cdce13-f638-feb5-8d6f-7d28b1aa9fa0&quot;&gt;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&lt;/diagram&gt;&lt;/mxfile&gt;"><defs/><g><path d="M 463 62 L 423.03 62 L 389.37 62" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 384.12 62 L 391.12 58.5 L 389.37 62 L 391.12 65.5 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 64px; margin-left: 424px;"><div style="box-sizing: border-box; font-size: 0px; text-align: center;" data-drawio-colors="color: rgb(0, 0, 0); background-color: rgb(255, 255, 255); "><div style="display: inline-block; font-size: 11px; font-family: Lucida Console; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; background-color: rgb(255, 255, 255); white-space: nowrap;">DARK</div></div></div></foreignObject><text x="424" y="68" fill="rgb(0, 0, 0)" font-family="Lucida Console" font-size="11px" text-anchor="middle">DARK</text></switch></g><path d="M 463 107 L 385.85 261.3" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 383.5 266 L 383.5 258.17 L 385.85 261.3 L 389.76 261.3 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 137px; margin-left: 443px;"><div style="box-sizing: border-box; font-size: 0px; text-align: center;" data-drawio-colors="color: rgb(0, 0, 0); background-color: rgb(255, 255, 255); "><div style="display: inline-block; font-size: 11px; font-family: Lucida Console; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; background-color: rgb(255, 255, 255); white-space: nowrap;"><div>BRIGHT</div><div><font style="font-size: 8px;">overshoot++</font></div></div></div></div></foreignObject><text x="443" y="141" fill="rgb(0, 0, 0)" font-family="Lucida Console" font-size="11px" text-anchor="middle">BRIGHT...</text></switch></g><path d="M 472.96 46.46 L 473.03 27.03 L 63.03 27.03 L 63 150.63" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 63 155.88 L 59.5 148.88 L 63 150.63 L 66.5 148.88 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><rect x="463" y="47" width="120" height="60" rx="9" ry="9" fill="rgb(255, 255, 255)" stroke="rgb(0, 0, 0)" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 118px; height: 1px; padding-top: 77px; margin-left: 464px;"><div style="box-sizing: border-box; font-size: 0px; text-align: center;" data-drawio-colors="color: rgb(0, 0, 0); "><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;"><div><font style="font-size: 18px;" face="Lucida Console">STOP</font></div><div><font style="font-size: 18px;" face="Lucida Console">BRIGHTEN</font></div></div></div></div></foreignObject><text x="523" y="81" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">STOP...</text></switch></g><path d="M 123 157 L 123.03 77.03 L 256.63 77" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 261.88 77 L 254.88 80.5 L 256.63 77 L 254.88 73.5 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 75px; margin-left: 186px;"><div style="box-sizing: border-box; font-size: 0px; text-align: center;" data-drawio-colors="color: rgb(0, 0, 0); background-color: rgb(255, 255, 255); "><div style="display: inline-block; font-size: 11px; font-family: Lucida Console; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; background-color: rgb(255, 255, 255); white-space: nowrap;">DARK</div></div></div></foreignObject><text x="186" y="79" fill="rgb(0, 0, 0)" font-family="Lucida Console" font-size="11px" text-anchor="middle">DARK</text></switch></g><path d="M 123 217 L 123.03 297.03 L 256.63 297" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 261.88 297 L 254.88 300.5 L 256.63 297 L 254.88 293.5 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 299px; margin-left: 184px;"><div style="box-sizing: border-box; font-size: 0px; text-align: center;" data-drawio-colors="color: rgb(0, 0, 0); background-color: rgb(255, 255, 255); "><div style="display: inline-block; font-size: 11px; font-family: Lucida Console; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; background-color: rgb(255, 255, 255); white-space: nowrap;">BRIGHT</div></div></div></foreignObject><text x="184" y="303" fill="rgb(0, 0, 0)" font-family="Lucida Console" font-size="11px" text-anchor="middle">BRIGHT</text></switch></g><path d="M 63 172 L 23.03 172 L 23.03 202 L 56.63 202" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 61.88 202 L 54.88 205.5 L 56.63 202 L 54.88 198.5 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 173px; margin-left: 36px;"><div style="box-sizing: border-box; font-size: 0px; text-align: center;" data-drawio-colors="color: rgb(0, 0, 0); background-color: rgb(255, 255, 255); "><div style="display: inline-block; font-size: 8px; font-family: Lucida Console; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; background-color: rgb(255, 255, 255); white-space: nowrap;"><font style="font-size: 11px;">GOOD</font></div></div></div></foreignObject><text x="36" y="176" fill="rgb(0, 0, 0)" font-family="Lucida Console" font-size="8px" text-anchor="middle">GOOD</text></switch></g><rect x="63" y="157" width="120" height="60" rx="9" ry="9" fill="rgb(255, 255, 255)" stroke="rgb(0, 0, 0)" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 118px; height: 1px; padding-top: 187px; margin-left: 64px;"><div style="box-sizing: border-box; font-size: 0px; text-align: center;" data-drawio-colors="color: rgb(0, 0, 0); "><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;"><div><font style="font-size: 18px;" face="Lucida Console">IDLE</font></div></div></div></div></foreignObject><text x="123" y="191" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">IDLE</text></switch></g><path d="M 383 92 L 456.63 92" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 461.88 92 L 454.88 95.5 L 456.63 92 L 454.88 88.5 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 95px; margin-left: 423px;"><div style="box-sizing: border-box; font-size: 0px; text-align: center;" data-drawio-colors="color: rgb(0, 0, 0); background-color: rgb(255, 255, 255); "><div style="display: inline-block; font-size: 11px; font-family: Lucida Console; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; background-color: rgb(255, 255, 255); white-space: nowrap;">GOOD</div></div></div></foreignObject><text x="423" y="99" fill="rgb(0, 0, 0)" font-family="Lucida Console" font-size="11px" text-anchor="middle">GOOD</text></switch></g><path d="M 323 107 L 313.03 107.03 L 313.03 260.63" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 313.03 265.88 L 309.53 258.88 L 313.03 260.63 L 316.53 258.88 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 207px; margin-left: 303px;"><div style="box-sizing: border-box; font-size: 0px; text-align: center;" data-drawio-colors="color: rgb(0, 0, 0); background-color: rgb(255, 255, 255); "><div style="display: inline-block; font-size: 11px; font-family: Lucida Console; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; background-color: rgb(255, 255, 255); white-space: nowrap;"><div>BRIGHT</div><div style="font-size: 8px;">overshoot++</div></div></div></div></foreignObject><text x="303" y="211" fill="rgb(0, 0, 0)" font-family="Lucida Console" font-size="11px" text-anchor="middle">BRIGHT...</text></switch></g><rect x="263" y="47" width="120" height="60" rx="9" ry="9" fill="rgb(255, 255, 255)" stroke="rgb(0, 0, 0)" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 118px; height: 1px; padding-top: 77px; margin-left: 264px;"><div style="box-sizing: border-box; font-size: 0px; text-align: center;" data-drawio-colors="color: rgb(0, 0, 0); "><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;"><div><font style="font-size: 18px;" face="Lucida Console">BRIGHTEN</font></div></div></div></div></foreignObject><text x="323" y="81" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">BRIGHTEN</text></switch></g><path d="M 493 267 L 493.03 247.03 L 553.03 247.03 L 553.01 260.63" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 553 265.88 L 549.51 258.88 L 553.01 260.63 L 556.51 258.89 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><path d="M 463 267 L 385.85 112.7" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 383.5 108 L 389.76 112.7 L 385.85 112.7 L 383.5 115.83 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 237px; margin-left: 445px;"><div style="box-sizing: border-box; font-size: 0px; text-align: center;" data-drawio-colors="color: rgb(0, 0, 0); background-color: rgb(255, 255, 255); "><div style="display: inline-block; font-size: 11px; font-family: Lucida Console; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; background-color: rgb(255, 255, 255); white-space: nowrap;"><div>DARK</div><div><font style="font-size: 8px;">overshoot++</font><br /></div></div></div></div></foreignObject><text x="445" y="241" fill="rgb(0, 0, 0)" font-family="Lucida Console" font-size="11px" text-anchor="middle">DARK...</text></switch></g><path d="M 475 326.46 L 475.03 347.03 L 63.03 347.03 L 63 223.37" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 63 218.12 L 66.5 225.12 L 63 223.37 L 59.5 225.12 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 345px; margin-left: 421px;"><div style="box-sizing: border-box; font-size: 0px; text-align: center;" data-drawio-colors="color: rgb(0, 0, 0); background-color: rgb(255, 255, 255); "><div style="display: inline-block; font-size: 7px; font-family: Lucida Console; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; background-color: rgb(255, 255, 255); white-space: nowrap;"><div style="font-size: 8px;"><font style="font-size: 11px;">GOOD</font></div><div style="font-size: 8px;"><font style="font-size: 8px;">--wait = 0<br /></font></div></div></div></div></foreignObject><text x="421" y="347" fill="rgb(0, 0, 0)" font-family="Lucida Console" font-size="7px" text-anchor="middle">GOOD...</text></switch></g><path d="M 463 282 L 389.37 282" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 384.12 282 L 391.12 278.5 L 389.37 282 L 391.12 285.5 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 282px; margin-left: 424px;"><div style="box-sizing: border-box; font-size: 0px; text-align: center;" data-drawio-colors="color: rgb(0, 0, 0); background-color: rgb(255, 255, 255); "><div style="display: inline-block; font-size: 11px; font-family: Lucida Console; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; background-color: rgb(255, 255, 255); white-space: nowrap;">BRIGHT</div></div></div></foreignObject><text x="424" y="286" fill="rgb(0, 0, 0)" font-family="Lucida Console" font-size="11px" text-anchor="middle">BRIGHT</text></switch></g><rect x="463" y="267" width="120" height="60" rx="9" ry="9" fill="rgb(255, 255, 255)" stroke="rgb(0, 0, 0)" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 118px; height: 1px; padding-top: 297px; margin-left: 464px;"><div style="box-sizing: border-box; font-size: 0px; text-align: center;" data-drawio-colors="color: rgb(0, 0, 0); "><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;"><div><font style="font-size: 18px;" face="Lucida Console">STOP</font></div><div><font style="font-size: 18px;" face="Lucida Console">DARKEN</font></div></div></div></div></foreignObject><text x="523" y="301" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">STOP...</text></switch></g><path d="M 383 312 L 456.63 312" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 461.88 312 L 454.88 315.5 L 456.63 312 L 454.88 308.5 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 312px; margin-left: 423px;"><div style="box-sizing: border-box; font-size: 0px; text-align: center;" data-drawio-colors="color: rgb(0, 0, 0); background-color: rgb(255, 255, 255); "><div style="display: inline-block; font-size: 11px; font-family: Lucida Console; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; background-color: rgb(255, 255, 255); white-space: nowrap;">GOOD</div></div></div></foreignObject><text x="423" y="316" fill="rgb(0, 0, 0)" font-family="Lucida Console" font-size="11px" text-anchor="middle">GOOD</text></switch></g><path d="M 332.24 266.46 L 332.97 113.37" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 332.99 108.12 L 336.46 115.13 L 332.97 113.37 L 329.46 115.1 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 157px; margin-left: 343px;"><div style="box-sizing: border-box; font-size: 0px; text-align: center;" data-drawio-colors="color: rgb(0, 0, 0); background-color: rgb(255, 255, 255); "><div style="display: inline-block; font-size: 11px; font-family: Lucida Console; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; background-color: rgb(255, 255, 255); white-space: nowrap;"><div>DARK</div><div style="font-size: 8px;">overshoot++<br /></div></div></div></div></foreignObject><text x="343" y="161" fill="rgb(0, 0, 0)" font-family="Lucida Console" font-size="11px" text-anchor="middle">DARK...</text></switch></g><rect x="263" y="267" width="120" height="60" rx="9" ry="9" fill="rgb(255, 255, 255)" stroke="rgb(0, 0, 0)" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 118px; height: 1px; padding-top: 297px; margin-left: 264px;"><div style="box-sizing: border-box; font-size: 0px; text-align: center;" data-drawio-colors="color: rgb(0, 0, 0); "><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;"><div><font style="font-size: 18px;" face="Lucida Console">DARKEN</font></div></div></div></div></foreignObject><text x="323" y="301" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">DARKEN</text></switch></g><path d="M 493 107 L 493.03 127.03 L 553.03 127.03 L 553.01 113.37" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 553 108.12 L 556.51 115.11 L 553.01 113.37 L 549.51 115.12 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 128px; margin-left: 524px;"><div style="box-sizing: border-box; font-size: 0px; text-align: center;" data-drawio-colors="color: rgb(0, 0, 0); background-color: rgb(255, 255, 255); "><div style="display: inline-block; font-size: 8px; font-family: Lucida Console; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; background-color: rgb(255, 255, 255); white-space: nowrap;"><div><font style="font-size: 11px;">GOOD</font></div><div>--wait <font style="font-size: 8px;"><span class="ILfuVd"><span class="hgKElc"><b>≠</b></span></span></font> 0<br /></div></div></div></div></foreignObject><text x="524" y="131" fill="rgb(0, 0, 0)" font-family="Lucida Console" font-size="8px" text-anchor="middle">GOOD...</text></switch></g><path d="M 263 92 L 243.03 92 L 243.03 127.03 L 293.03 127.03 L 293.01 113.37" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 293 108.12 L 296.51 115.11 L 293.01 113.37 L 289.51 115.12 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 125px; margin-left: 258px;"><div style="box-sizing: border-box; font-size: 0px; text-align: center;" data-drawio-colors="color: rgb(0, 0, 0); background-color: rgb(255, 255, 255); "><div style="display: inline-block; font-size: 11px; font-family: Lucida Console; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; background-color: rgb(255, 255, 255); white-space: nowrap;">DARK</div></div></div></foreignObject><text x="258" y="129" fill="rgb(0, 0, 0)" font-family="Lucida Console" font-size="11px" text-anchor="middle">DARK</text></switch></g><path d="M 263 282 L 243.03 282 L 243.03 247.03 L 293.03 247.03 L 293.01 260.63" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 293 265.88 L 289.51 258.88 L 293.01 260.63 L 296.51 258.89 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 248px; margin-left: 263px;"><div style="box-sizing: border-box; font-size: 0px; text-align: center;" data-drawio-colors="color: rgb(0, 0, 0); background-color: rgb(255, 255, 255); "><div style="display: inline-block; font-size: 11px; font-family: Lucida Console; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; background-color: rgb(255, 255, 255); white-space: nowrap;">BRIGHT</div></div></div></foreignObject><text x="263" y="252" fill="rgb(0, 0, 0)" font-family="Lucida Console" font-size="11px" text-anchor="middle">BRIGHT</text></switch></g><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 247px; margin-left: 523px;"><div style="box-sizing: border-box; font-size: 0px; text-align: center;" data-drawio-colors="color: rgb(0, 0, 0); background-color: rgb(255, 255, 255); "><div style="display: inline-block; font-size: 8px; font-family: Lucida Console; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; background-color: rgb(255, 255, 255); white-space: nowrap;"><div><font style="font-size: 11px;">GOOD</font></div><div>--wait <font style="font-size: 8px;"><span class="ILfuVd"><span class="hgKElc"><b>≠</b></span></span></font> 0<br /></div></div></div></div></foreignObject><text x="523" y="250" fill="rgb(0, 0, 0)" font-family="Lucida Console" font-size="8px" text-anchor="middle">GOOD...</text></switch></g><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 27px; margin-left: 413px;"><div style="box-sizing: border-box; font-size: 0px; text-align: center;" data-drawio-colors="color: rgb(0, 0, 0); background-color: rgb(255, 255, 255); "><div style="display: inline-block; font-size: 8px; font-family: Lucida Console; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; background-color: rgb(255, 255, 255); white-space: nowrap;"><div><font style="font-size: 11px;">GOOD</font></div><div>--wait <b>=</b> 0<br /></div></div></div></div></foreignObject><text x="413" y="30" fill="rgb(0, 0, 0)" font-family="Lucida Console" font-size="8px" text-anchor="middle">GOOD...</text></switch></g><rect x="463" y="97" width="120" height="10" fill="none" stroke="none" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 102px; margin-left: 523px;"><div style="box-sizing: border-box; font-size: 0px; text-align: center;" data-drawio-colors="color: rgb(0, 0, 0); "><div style="display: inline-block; font-size: 7px; font-family: Lucida Console; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: nowrap;">On exit sets wait=MAX_WAIT</div></div></div></foreignObject><text x="523" y="104" fill="rgb(0, 0, 0)" font-family="Lucida Console" font-size="7px" text-anchor="middle">On exit sets wait=MAX_WAIT</text></switch></g><rect x="463" y="317" width="120" height="10" fill="none" stroke="none" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 322px; margin-left: 523px;"><div style="box-sizing: border-box; font-size: 0px; text-align: center;" data-drawio-colors="color: rgb(0, 0, 0); "><div style="display: inline-block; font-size: 7px; font-family: Lucida Console; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: nowrap;">On exit sets wait=MAX_WAIT</div></div></div></foreignObject><text x="523" y="324" fill="rgb(0, 0, 0)" font-family="Lucida Console" font-size="7px" text-anchor="middle">On exit sets wait=MAX_WAIT</text></switch></g><rect x="68" y="207" width="110" height="10" fill="none" stroke="none" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 212px; margin-left: 123px;"><div style="box-sizing: border-box; font-size: 0px; text-align: center;" data-drawio-colors="color: rgb(0, 0, 0); "><div style="display: inline-block; font-size: 7px; font-family: Lucida Console; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: nowrap;">On enter sets overshoot=0</div></div></div></foreignObject><text x="123" y="214" fill="rgb(0, 0, 0)" font-family="Lucida Console" font-size="7px" text-anchor="middle">On enter sets overshoot=0</text></switch></g></g><switch><g requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"/><a transform="translate(0,-5)" xlink:href="https://www.diagrams.net/doc/faq/svg-export-text-problems" target="_blank"><text text-anchor="middle" font-size="10px" x="50%" y="100%">Text is not SVG - cannot display</text></a></switch></svg>
+3
doc/images/autoexpgain.drawio.svg.license
··· 1 + Copyright 2022, Collabora, Ltd. 2 + 3 + SPDX-License-Identifier: BSL-1.0
+192 -20
src/xrt/auxiliary/util/u_autoexpgain.c
··· 39 39 40 40 #define LEVELS 256 //!< Possible pixel intensity values, only 8-bit supported 41 41 #define INITIAL_BRIGHTNESS 0.5 42 - #define INITIAL_MAX_BRIGHTNESS_STEP 0.05 //!< 0.1 is faster but introduces oscillations more often 42 + #define INITIAL_MAX_BRIGHTNESS_STEP 0.1 43 43 #define INITIAL_THRESHOLD 0.1 44 44 #define GRID_COLS 40 //!< Amount of columns for the histogram sample grid 45 45 46 + //! AEG State machine states 47 + enum u_aeg_state 48 + { 49 + IDLE, 50 + BRIGHTEN, 51 + STOP_BRIGHTEN, //!< Avoid oscillations by 52 + DARKEN, 53 + STOP_DARKEN, //!< Similar to STOP_BRIGHTEN 54 + }; 55 + 56 + //! This actions are triggered when the image is too dark, bright or good enough 57 + enum u_aeg_action 58 + { 59 + GOOD, 60 + DARK, 61 + BRIGHT, 62 + }; 63 + 46 64 //! Auto exposure and gain (AEG) adjustment algorithm state. 47 65 struct u_autoexpgain 48 66 { 49 67 bool enable; //!< Whether to enable auto exposure and gain adjustment 50 68 69 + //! AEG is a finite state machine. @see set_state. 70 + enum u_aeg_state state; 71 + 51 72 enum u_logging_level log_level; 52 73 53 - //! Algorithm strategy that affects how score and brightness are computed 74 + //! Counts how many times we've overshooted in the last brightness change. 75 + //! It's then used for exponential backoff of the brightness step. 76 + int overshoots; 77 + 78 + //! There are buffer states that wait `frame_delay` frames to ensure we are 79 + //! not overshooting. This field counts the remaining frames to wait. 80 + //! @see set_state 81 + int wait; 82 + 83 + //! The selected strategy affects various targets of the algorithm. 54 84 enum u_aeg_strategy strategy; 55 85 struct u_var_combo strategy_combo; //!< UI combo box for selecting `strategy` 56 86 ··· 70 100 //! images with a good enough `brightness` value. 71 101 float current_score; 72 102 73 - //! Scores further than `threshold` from zero will trigger a `brightness` update. 103 + //! Scores further than `threshold` from the target score will trigger a 104 + //! `brightness` update. 74 105 float threshold; 75 106 76 - uint32_t frame_counter; //!< Number of frames received 77 - 78 - //! Every how many frames should we update `brightness`. Some cameras take a 79 - //! couple of frames until the new exposure/gain sets in and a new score can 80 - //! be recomputed properly. 81 - uint8_t update_every; 107 + //! A camera might take a couple of frames until the new exposure/gain sets in 108 + //! the image. Knowing how many (this variable) helps in avoiding overshooting 109 + //! brightness changes. 110 + int frame_delay; 82 111 83 112 float exposure; //!< Currently computed exposure value to use 84 113 float gain; //!< Currently computed gain value to use 85 114 }; 86 115 116 + static const char * 117 + state_to_string(enum u_aeg_state state) 118 + { 119 + if (state == IDLE) { 120 + return "IDLE"; 121 + } else if (state == BRIGHTEN) { 122 + return "BRIGHTEN"; 123 + } else if (state == STOP_BRIGHTEN) { 124 + return "STOP_BRIGHTEN"; 125 + } else if (state == DARKEN) { 126 + return "DARKEN"; 127 + } else if (state == STOP_DARKEN) { 128 + return "STOP_DARKEN"; 129 + } else { 130 + AEG_ASSERT_(false); 131 + } 132 + return NULL; 133 + } 134 + 135 + static const char * 136 + action_to_string(enum u_aeg_action action) 137 + { 138 + if (action == DARK) { 139 + return "DARK"; 140 + } else if (action == BRIGHT) { 141 + return "BRIGHT"; 142 + } else if (action == GOOD) { 143 + return "GOOD"; 144 + } else { 145 + AEG_ASSERT_(false); 146 + } 147 + return NULL; 148 + } 149 + 150 + /*! 151 + * Defines the AEG state machine transitions. 152 + * The main idea is that if brightness needs to change then we go from `IDLE` to 153 + * `BRIGHTEN`/`DARKEN`. To avoid oscillations we detect overshootings 154 + * and exponentially backoff our brightness step. We only reset our `overshoots` 155 + * counter after the image have been good for `frame_delay` frames, this delay 156 + * is counted during `STOP_DARKEN`/`STOP_BRIGHTEN` states. 157 + * 158 + * A diagram of the state machine is below: 159 + * ![AEG state machine](images/autoexpgain.drawio.svg) 160 + */ 161 + static void 162 + set_state(struct u_autoexpgain *aeg, enum u_aeg_action action) 163 + { 164 + enum u_aeg_state new_state; 165 + if (aeg->state == IDLE) { 166 + if (action == DARK) { 167 + new_state = BRIGHTEN; 168 + } else if (action == BRIGHT) { 169 + new_state = DARKEN; 170 + } else if (action == GOOD) { 171 + new_state = IDLE; 172 + } else { 173 + AEG_ASSERT_(false); 174 + } 175 + } else if (aeg->state == BRIGHTEN) { 176 + if (action == DARK) { 177 + new_state = BRIGHTEN; 178 + } else if (action == BRIGHT) { 179 + aeg->overshoots++; 180 + new_state = DARKEN; 181 + } else if (action == GOOD) { 182 + new_state = STOP_BRIGHTEN; 183 + } else { 184 + AEG_ASSERT_(false); 185 + } 186 + } else if (aeg->state == STOP_BRIGHTEN) { 187 + if (action == DARK) { 188 + new_state = BRIGHTEN; 189 + } else if (action == BRIGHT) { 190 + aeg->overshoots++; 191 + new_state = DARKEN; 192 + } else if (action == GOOD) { 193 + aeg->wait--; 194 + new_state = aeg->wait == 0 ? IDLE : STOP_BRIGHTEN; 195 + } else { 196 + AEG_ASSERT_(false); 197 + } 198 + 199 + if (new_state != STOP_BRIGHTEN) { 200 + aeg->wait = aeg->frame_delay; 201 + } 202 + } else if (aeg->state == DARKEN) { 203 + if (action == DARK) { 204 + aeg->overshoots++; 205 + new_state = BRIGHTEN; 206 + } else if (action == BRIGHT) { 207 + new_state = DARKEN; 208 + } else if (action == GOOD) { 209 + new_state = STOP_DARKEN; 210 + } else { 211 + AEG_ASSERT_(false); 212 + } 213 + } else if (aeg->state == STOP_DARKEN) { 214 + if (action == DARK) { 215 + aeg->overshoots++; 216 + new_state = BRIGHTEN; 217 + } else if (action == BRIGHT) { 218 + new_state = DARKEN; 219 + } else if (action == GOOD) { 220 + aeg->wait--; 221 + new_state = aeg->wait == 0 ? IDLE : STOP_DARKEN; 222 + } else { 223 + AEG_ASSERT_(false); 224 + } 225 + 226 + if (new_state != STOP_DARKEN) { 227 + aeg->wait = aeg->frame_delay; 228 + } 229 + } else { 230 + AEG_ASSERT_(false); 231 + } 232 + if (new_state == IDLE) { 233 + aeg->overshoots = 0; 234 + } 235 + aeg->overshoots = CLAMP(aeg->overshoots, 0, 3); 236 + 237 + AEG_TRACE("[%s] ---%s--> [%s] (overshoots=%d, wait=%d)", state_to_string(aeg->state), action_to_string(action), 238 + state_to_string(new_state), aeg->overshoots, aeg->wait); 239 + 240 + aeg->state = new_state; 241 + } 242 + 87 243 //! Maps a `brightness` in [0, 1] to a pair of exposure and gain values based on 88 244 //! a piecewise function. 89 245 static void ··· 227 383 return; 228 384 } 229 385 230 - aeg->frame_counter++; 231 - if (aeg->frame_counter % aeg->update_every != 0) { 232 - return; 386 + float target_score; 387 + if (aeg->strategy == U_AEG_STRATEGY_TRACKING) { 388 + target_score = -aeg->threshold; // Makes 0 the right bound of our "good enugh" range 389 + } else if (aeg->strategy == U_AEG_STRATEGY_DYNAMIC_RANGE) { 390 + target_score = 0; 391 + } else { 392 + AEG_ASSERT(false, "Unexpected strategy=%d", aeg->strategy); 233 393 } 234 394 235 - bool score_is_high = fabsf(score) > aeg->threshold; 236 - if (!score_is_high) { 395 + enum u_aeg_action action; // State machine input action 396 + if (score > target_score + aeg->threshold) { 397 + action = BRIGHT; 398 + } else if (score < target_score - aeg->threshold) { 399 + action = DARK; 400 + } else { 401 + action = GOOD; 402 + } 403 + 404 + set_state(aeg, action); 405 + 406 + if (aeg->state != BRIGHTEN && aeg->state != DARKEN) { 237 407 return; 238 408 } 239 409 240 410 float max_step = aeg->max_brightness_step; 241 - float step = CLAMP(max_step * score, -max_step, max_step); 242 - aeg->brightness.val -= step; 411 + float step = max_step * score / powf(2.0f, aeg->overshoots); 412 + aeg->brightness.val -= CLAMP(step, -max_step, max_step); 243 413 aeg->brightness.val = CLAMP(aeg->brightness.val, 0, 1); 244 414 } 245 415 ··· 250 420 */ 251 421 252 422 struct u_autoexpgain * 253 - u_autoexpgain_create(enum u_aeg_strategy strategy, bool enabled_from_start, uint8_t update_every) 423 + u_autoexpgain_create(enum u_aeg_strategy strategy, bool enabled_from_start, int frame_delay) 254 424 { 255 425 struct u_autoexpgain *aeg = U_TYPED_CALLOC(struct u_autoexpgain); 256 426 257 427 aeg->enable = enabled_from_start; 258 428 aeg->log_level = debug_get_log_option_aeg_log(); 429 + aeg->state = IDLE; 430 + aeg->wait = frame_delay; 431 + aeg->overshoots = 0; 259 432 aeg->strategy = strategy; 260 433 aeg->strategy_combo.count = U_AEG_STRATEGY_COUNT; 261 434 aeg->strategy_combo.options = "Tracking\0Dynamic Range\0\0"; ··· 272 445 aeg->max_brightness_step = INITIAL_MAX_BRIGHTNESS_STEP; 273 446 274 447 aeg->threshold = INITIAL_THRESHOLD; 275 - aeg->frame_counter = 0; 276 - aeg->update_every = update_every; 448 + aeg->frame_delay = frame_delay; 277 449 278 450 brightness_to_expgain(aeg, INITIAL_BRIGHTNESS, &aeg->exposure, &aeg->gain); 279 451 ··· 284 456 u_autoexpgain_add_vars(struct u_autoexpgain *aeg, void *root) 285 457 { 286 458 u_var_add_bool(root, &aeg->enable, "Update brightness automatically"); 287 - u_var_add_u8(root, &aeg->update_every, "Update every X frames"); 459 + u_var_add_i32(root, &aeg->frame_delay, "Frame update delay"); 288 460 u_var_add_combo(root, &aeg->strategy_combo, "Strategy"); 289 461 u_var_add_draggable_f32(root, &aeg->brightness, "Brightness"); 290 462 u_var_add_f32(root, &aeg->threshold, "Score threshold");
+2 -2
src/xrt/auxiliary/util/u_autoexpgain.h
··· 31 31 * 32 32 * @param strategy What objective is preferred for the algorithm. 33 33 * @param enabled_from_start Update exposure/gain from the start. 34 - * @param update_every Every how many frames should we update exposure/gain 34 + * @param frame_delay About how many frames does it take for exp and gain to settle in. 35 35 * @return struct u_autoexpgain* Created object 36 36 */ 37 37 struct u_autoexpgain * 38 - u_autoexpgain_create(enum u_aeg_strategy strategy, bool enabled_from_start, uint8_t update_every); 38 + u_autoexpgain_create(enum u_aeg_strategy strategy, bool enabled_from_start, int frame_delay); 39 39 40 40 //! Setup UI for the AEG algorithm 41 41 void
+2 -2
src/xrt/drivers/wmr/wmr_camera.c
··· 447 447 } 448 448 449 449 bool enable_aeg = debug_get_bool_option_wmr_autoexposure(); 450 - int aeg_update_every = 3; // WMR takes about three frames until the cmd changes the image 451 - cam->aeg = u_autoexpgain_create(U_AEG_STRATEGY_TRACKING, enable_aeg, aeg_update_every); 450 + int frame_delay = 3; // WMR takes about three frames until the cmd changes the image 451 + cam->aeg = u_autoexpgain_create(U_AEG_STRATEGY_TRACKING, enable_aeg, frame_delay); 452 452 453 453 cam->exposure_ui.val = &cam->exposure; 454 454 cam->exposure_ui.max = WMR_MAX_EXPOSURE;
+1 -1
src/xrt/drivers/wmr/wmr_protocol.h
··· 55 55 #define STR_TO_U32(s) ((uint32_t)(((s)[0]) | ((s)[1] << 8) | ((s)[2] << 16) | ((s)[3] << 24))) 56 56 #define WMR_MAGIC STR_TO_U32("Dlo+") 57 57 58 - #define WMR_MIN_EXPOSURE 120 58 + #define WMR_MIN_EXPOSURE 60 59 59 #define WMR_MAX_OBSERVED_EXPOSURE 6000 60 60 #define WMR_MAX_EXPOSURE 9000 61 61 #define WMR_MIN_GAIN 16