diff --git a/doc/images/autoexpgain.drawio.svg b/doc/images/autoexpgain.drawio.svg new file mode 100644 index 000000000..84eb8c87f --- /dev/null +++ b/doc/images/autoexpgain.drawio.svg @@ -0,0 +1,4 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- Do not edit this file with editors other than diagrams.net --> +<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"> +<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="<mxfile host="app.diagrams.net" modified="2022-05-18T11:34:31.416Z" agent="5.0 (X11)" etag="lviUBxbUCX1CSFnUuSq4" version="18.0.6" type="device"><diagram name="Page-1" id="58cdce13-f638-feb5-8d6f-7d28b1aa9fa0">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</diagram></mxfile>"><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> \ No newline at end of file diff --git a/doc/images/autoexpgain.drawio.svg.license b/doc/images/autoexpgain.drawio.svg.license new file mode 100644 index 000000000..8704c1f1c --- /dev/null +++ b/doc/images/autoexpgain.drawio.svg.license @@ -0,0 +1,3 @@ +Copyright 2022, Collabora, Ltd. + +SPDX-License-Identifier: BSL-1.0 diff --git a/src/xrt/auxiliary/util/u_autoexpgain.c b/src/xrt/auxiliary/util/u_autoexpgain.c index 359af0f1b..96778f8d8 100644 --- a/src/xrt/auxiliary/util/u_autoexpgain.c +++ b/src/xrt/auxiliary/util/u_autoexpgain.c @@ -39,18 +39,48 @@ DEBUG_GET_ONCE_LOG_OPTION(aeg_log, "AEG_LOG", U_LOGGING_WARN) #define LEVELS 256 //!< Possible pixel intensity values, only 8-bit supported #define INITIAL_BRIGHTNESS 0.5 -#define INITIAL_MAX_BRIGHTNESS_STEP 0.05 //!< 0.1 is faster but introduces oscillations more often +#define INITIAL_MAX_BRIGHTNESS_STEP 0.1 #define INITIAL_THRESHOLD 0.1 #define GRID_COLS 40 //!< Amount of columns for the histogram sample grid +//! AEG State machine states +enum u_aeg_state +{ + IDLE, + BRIGHTEN, + STOP_BRIGHTEN, //!< Avoid oscillations by + DARKEN, + STOP_DARKEN, //!< Similar to STOP_BRIGHTEN +}; + +//! This actions are triggered when the image is too dark, bright or good enough +enum u_aeg_action +{ + GOOD, + DARK, + BRIGHT, +}; + //! Auto exposure and gain (AEG) adjustment algorithm state. struct u_autoexpgain { bool enable; //!< Whether to enable auto exposure and gain adjustment + //! AEG is a finite state machine. @see set_state. + enum u_aeg_state state; + enum u_logging_level log_level; - //! Algorithm strategy that affects how score and brightness are computed + //! Counts how many times we've overshooted in the last brightness change. + //! It's then used for exponential backoff of the brightness step. + int overshoots; + + //! There are buffer states that wait `frame_delay` frames to ensure we are + //! not overshooting. This field counts the remaining frames to wait. + //! @see set_state + int wait; + + //! The selected strategy affects various targets of the algorithm. enum u_aeg_strategy strategy; struct u_var_combo strategy_combo; //!< UI combo box for selecting `strategy` @@ -70,20 +100,146 @@ struct u_autoexpgain //! images with a good enough `brightness` value. float current_score; - //! Scores further than `threshold` from zero will trigger a `brightness` update. + //! Scores further than `threshold` from the target score will trigger a + //! `brightness` update. float threshold; - uint32_t frame_counter; //!< Number of frames received - - //! Every how many frames should we update `brightness`. Some cameras take a - //! couple of frames until the new exposure/gain sets in and a new score can - //! be recomputed properly. - uint8_t update_every; + //! A camera might take a couple of frames until the new exposure/gain sets in + //! the image. Knowing how many (this variable) helps in avoiding overshooting + //! brightness changes. + int frame_delay; float exposure; //!< Currently computed exposure value to use float gain; //!< Currently computed gain value to use }; +static const char * +state_to_string(enum u_aeg_state state) +{ + if (state == IDLE) { + return "IDLE"; + } else if (state == BRIGHTEN) { + return "BRIGHTEN"; + } else if (state == STOP_BRIGHTEN) { + return "STOP_BRIGHTEN"; + } else if (state == DARKEN) { + return "DARKEN"; + } else if (state == STOP_DARKEN) { + return "STOP_DARKEN"; + } else { + AEG_ASSERT_(false); + } + return NULL; +} + +static const char * +action_to_string(enum u_aeg_action action) +{ + if (action == DARK) { + return "DARK"; + } else if (action == BRIGHT) { + return "BRIGHT"; + } else if (action == GOOD) { + return "GOOD"; + } else { + AEG_ASSERT_(false); + } + return NULL; +} + +/*! + * Defines the AEG state machine transitions. + * The main idea is that if brightness needs to change then we go from `IDLE` to + * `BRIGHTEN`/`DARKEN`. To avoid oscillations we detect overshootings + * and exponentially backoff our brightness step. We only reset our `overshoots` + * counter after the image have been good for `frame_delay` frames, this delay + * is counted during `STOP_DARKEN`/`STOP_BRIGHTEN` states. + * + * A diagram of the state machine is below: + * ![AEG state machine](images/autoexpgain.drawio.svg) + */ +static void +set_state(struct u_autoexpgain *aeg, enum u_aeg_action action) +{ + enum u_aeg_state new_state; + if (aeg->state == IDLE) { + if (action == DARK) { + new_state = BRIGHTEN; + } else if (action == BRIGHT) { + new_state = DARKEN; + } else if (action == GOOD) { + new_state = IDLE; + } else { + AEG_ASSERT_(false); + } + } else if (aeg->state == BRIGHTEN) { + if (action == DARK) { + new_state = BRIGHTEN; + } else if (action == BRIGHT) { + aeg->overshoots++; + new_state = DARKEN; + } else if (action == GOOD) { + new_state = STOP_BRIGHTEN; + } else { + AEG_ASSERT_(false); + } + } else if (aeg->state == STOP_BRIGHTEN) { + if (action == DARK) { + new_state = BRIGHTEN; + } else if (action == BRIGHT) { + aeg->overshoots++; + new_state = DARKEN; + } else if (action == GOOD) { + aeg->wait--; + new_state = aeg->wait == 0 ? IDLE : STOP_BRIGHTEN; + } else { + AEG_ASSERT_(false); + } + + if (new_state != STOP_BRIGHTEN) { + aeg->wait = aeg->frame_delay; + } + } else if (aeg->state == DARKEN) { + if (action == DARK) { + aeg->overshoots++; + new_state = BRIGHTEN; + } else if (action == BRIGHT) { + new_state = DARKEN; + } else if (action == GOOD) { + new_state = STOP_DARKEN; + } else { + AEG_ASSERT_(false); + } + } else if (aeg->state == STOP_DARKEN) { + if (action == DARK) { + aeg->overshoots++; + new_state = BRIGHTEN; + } else if (action == BRIGHT) { + new_state = DARKEN; + } else if (action == GOOD) { + aeg->wait--; + new_state = aeg->wait == 0 ? IDLE : STOP_DARKEN; + } else { + AEG_ASSERT_(false); + } + + if (new_state != STOP_DARKEN) { + aeg->wait = aeg->frame_delay; + } + } else { + AEG_ASSERT_(false); + } + if (new_state == IDLE) { + aeg->overshoots = 0; + } + aeg->overshoots = CLAMP(aeg->overshoots, 0, 3); + + AEG_TRACE("[%s] ---%s--> [%s] (overshoots=%d, wait=%d)", state_to_string(aeg->state), action_to_string(action), + state_to_string(new_state), aeg->overshoots, aeg->wait); + + aeg->state = new_state; +} + //! Maps a `brightness` in [0, 1] to a pair of exposure and gain values based on //! a piecewise function. static void @@ -227,19 +383,33 @@ update_brightness(struct u_autoexpgain *aeg, struct xrt_frame *xf) return; } - aeg->frame_counter++; - if (aeg->frame_counter % aeg->update_every != 0) { - return; + float target_score; + if (aeg->strategy == U_AEG_STRATEGY_TRACKING) { + target_score = -aeg->threshold; // Makes 0 the right bound of our "good enugh" range + } else if (aeg->strategy == U_AEG_STRATEGY_DYNAMIC_RANGE) { + target_score = 0; + } else { + AEG_ASSERT(false, "Unexpected strategy=%d", aeg->strategy); } - bool score_is_high = fabsf(score) > aeg->threshold; - if (!score_is_high) { + enum u_aeg_action action; // State machine input action + if (score > target_score + aeg->threshold) { + action = BRIGHT; + } else if (score < target_score - aeg->threshold) { + action = DARK; + } else { + action = GOOD; + } + + set_state(aeg, action); + + if (aeg->state != BRIGHTEN && aeg->state != DARKEN) { return; } float max_step = aeg->max_brightness_step; - float step = CLAMP(max_step * score, -max_step, max_step); - aeg->brightness.val -= step; + float step = max_step * score / powf(2.0f, aeg->overshoots); + aeg->brightness.val -= CLAMP(step, -max_step, max_step); aeg->brightness.val = CLAMP(aeg->brightness.val, 0, 1); } @@ -250,12 +420,15 @@ update_brightness(struct u_autoexpgain *aeg, struct xrt_frame *xf) */ struct u_autoexpgain * -u_autoexpgain_create(enum u_aeg_strategy strategy, bool enabled_from_start, uint8_t update_every) +u_autoexpgain_create(enum u_aeg_strategy strategy, bool enabled_from_start, int frame_delay) { struct u_autoexpgain *aeg = U_TYPED_CALLOC(struct u_autoexpgain); aeg->enable = enabled_from_start; aeg->log_level = debug_get_log_option_aeg_log(); + aeg->state = IDLE; + aeg->wait = frame_delay; + aeg->overshoots = 0; aeg->strategy = strategy; aeg->strategy_combo.count = U_AEG_STRATEGY_COUNT; aeg->strategy_combo.options = "Tracking\0Dynamic Range\0\0"; @@ -272,8 +445,7 @@ u_autoexpgain_create(enum u_aeg_strategy strategy, bool enabled_from_start, uint aeg->max_brightness_step = INITIAL_MAX_BRIGHTNESS_STEP; aeg->threshold = INITIAL_THRESHOLD; - aeg->frame_counter = 0; - aeg->update_every = update_every; + aeg->frame_delay = frame_delay; brightness_to_expgain(aeg, INITIAL_BRIGHTNESS, &aeg->exposure, &aeg->gain); @@ -284,7 +456,7 @@ void u_autoexpgain_add_vars(struct u_autoexpgain *aeg, void *root) { u_var_add_bool(root, &aeg->enable, "Update brightness automatically"); - u_var_add_u8(root, &aeg->update_every, "Update every X frames"); + u_var_add_i32(root, &aeg->frame_delay, "Frame update delay"); u_var_add_combo(root, &aeg->strategy_combo, "Strategy"); u_var_add_draggable_f32(root, &aeg->brightness, "Brightness"); u_var_add_f32(root, &aeg->threshold, "Score threshold"); diff --git a/src/xrt/auxiliary/util/u_autoexpgain.h b/src/xrt/auxiliary/util/u_autoexpgain.h index 6871a0f1f..bf8373b1e 100644 --- a/src/xrt/auxiliary/util/u_autoexpgain.h +++ b/src/xrt/auxiliary/util/u_autoexpgain.h @@ -31,11 +31,11 @@ struct u_autoexpgain; * * @param strategy What objective is preferred for the algorithm. * @param enabled_from_start Update exposure/gain from the start. - * @param update_every Every how many frames should we update exposure/gain + * @param frame_delay About how many frames does it take for exp and gain to settle in. * @return struct u_autoexpgain* Created object */ struct u_autoexpgain * -u_autoexpgain_create(enum u_aeg_strategy strategy, bool enabled_from_start, uint8_t update_every); +u_autoexpgain_create(enum u_aeg_strategy strategy, bool enabled_from_start, int frame_delay); //! Setup UI for the AEG algorithm void diff --git a/src/xrt/drivers/wmr/wmr_camera.c b/src/xrt/drivers/wmr/wmr_camera.c index daa332db2..618c93a45 100644 --- a/src/xrt/drivers/wmr/wmr_camera.c +++ b/src/xrt/drivers/wmr/wmr_camera.c @@ -447,8 +447,8 @@ wmr_camera_open(struct xrt_prober_device *dev_holo, } bool enable_aeg = debug_get_bool_option_wmr_autoexposure(); - int aeg_update_every = 3; // WMR takes about three frames until the cmd changes the image - cam->aeg = u_autoexpgain_create(U_AEG_STRATEGY_TRACKING, enable_aeg, aeg_update_every); + int frame_delay = 3; // WMR takes about three frames until the cmd changes the image + cam->aeg = u_autoexpgain_create(U_AEG_STRATEGY_TRACKING, enable_aeg, frame_delay); cam->exposure_ui.val = &cam->exposure; cam->exposure_ui.max = WMR_MAX_EXPOSURE; diff --git a/src/xrt/drivers/wmr/wmr_protocol.h b/src/xrt/drivers/wmr/wmr_protocol.h index 428d6ec8f..45323d11a 100644 --- a/src/xrt/drivers/wmr/wmr_protocol.h +++ b/src/xrt/drivers/wmr/wmr_protocol.h @@ -55,7 +55,7 @@ extern "C" { #define STR_TO_U32(s) ((uint32_t)(((s)[0]) | ((s)[1] << 8) | ((s)[2] << 16) | ((s)[3] << 24))) #define WMR_MAGIC STR_TO_U32("Dlo+") -#define WMR_MIN_EXPOSURE 120 +#define WMR_MIN_EXPOSURE 60 #define WMR_MAX_OBSERVED_EXPOSURE 6000 #define WMR_MAX_EXPOSURE 9000 #define WMR_MIN_GAIN 16