Prototype: integrate EglDisplay as self-contained component
This commit is contained in:
parent
b92de63d25
commit
6bf8a0da7a
4 changed files with 151 additions and 200 deletions
|
|
@ -776,16 +776,13 @@
|
|||
<node CREATED="1783820461975" ID="ID_715616295" MODIFIED="1783820480357" TEXT="mit optimiser also praktisch direkter Kernel-Aufruf"/>
|
||||
<node CREATED="1783820481050" ID="ID_1869508632" MODIFIED="1783820542141" TEXT="liburing-ffi: definiert alle calls als binary-Symbols (⟹ langsamer)">
|
||||
<richcontent TYPE="NOTE"><html>
|
||||
<head>
|
||||
|
||||
</head>
|
||||
<head/>
|
||||
<body>
|
||||
<p>
|
||||
Ist notwendig für andere Sprach-Bindings oder ältere Compiler; dadurch hat dann natürlich jeder Call einen Overhead
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
||||
</richcontent>
|
||||
</html></richcontent>
|
||||
</node>
|
||||
</node>
|
||||
</node>
|
||||
|
|
@ -806,7 +803,8 @@
|
|||
<node CREATED="1783642938966" ID="ID_1117409154" MODIFIED="1783642955536" TEXT="mäßig sinnvoll"/>
|
||||
<node CREATED="1783642956739" ID="ID_141690825" MODIFIED="1783642968326" TEXT="hier nur ein Consumer"/>
|
||||
</node>
|
||||
<node CREATED="1783642985618" ID="ID_169416260" MODIFIED="1783642994611" TEXT="oder einen pull-Worker">
|
||||
<node COLOR="#5b280f" CREATED="1783642985618" ID="ID_169416260" MODIFIED="1784052474215" TEXT="oder einen pull-Worker">
|
||||
<icon BUILTIN="button_cancel"/>
|
||||
<node CREATED="1783642995707" ID="ID_216666777" MODIFIED="1783642999794" TEXT="das wäre näher an Lumiera"/>
|
||||
<node CREATED="1783643000727" ID="ID_737342556" MODIFIED="1783643655114" TEXT="der würde jeweils nur die Queue ausräumen"/>
|
||||
<node CREATED="1783643039177" ID="ID_1046849410" MODIFIED="1783643729328" TEXT="und eine Flag am Buffer setzen">
|
||||
|
|
@ -840,6 +838,14 @@
|
|||
</html></richcontent>
|
||||
</node>
|
||||
</node>
|
||||
<node CREATED="1784052477036" ID="ID_1273958721" MODIFIED="1784052501398" TEXT="nach Diskussion mit Claude: Proactor ist didaktisch vorzuziehen">
|
||||
<icon BUILTIN="yes"/>
|
||||
<node BACKGROUND_COLOR="#fbfdca" CREATED="1784052519992" ID="ID_1545269972" MODIFIED="1784052885403" TEXT="man kann auch die Timings darüber steuern">
|
||||
<arrowlink COLOR="#f4f3a4" DESTINATION="ID_1489274093" ENDARROW="Default" ENDINCLINATION="638;-170;" ID="Arrow_ID_396926940" STARTARROW="None" STARTINCLINATION="1155;67;"/>
|
||||
<icon BUILTIN="idea"/>
|
||||
</node>
|
||||
<node CREATED="1784052896300" ID="ID_746832214" MODIFIED="1784052909501" TEXT="kann auf die Weise alle zentralen Konzepte in einem Stück Code zeigen"/>
|
||||
</node>
|
||||
</node>
|
||||
</node>
|
||||
<node BACKGROUND_COLOR="#eef0c5" COLOR="#990000" CREATED="1783644313430" ID="ID_170028474" MODIFIED="1783788829437" TEXT="Prototyp entwickeln">
|
||||
|
|
@ -878,21 +884,20 @@
|
|||
<node CREATED="1783795475774" ID="ID_1250076625" MODIFIED="1783795489958" TEXT="als "external builder Make"-Projekt importieren"/>
|
||||
<node BACKGROUND_COLOR="#e0ceaa" COLOR="#690f14" CREATED="1783795490756" ID="ID_972729826" MODIFIED="1783795620602" TEXT="Vorsicht: brauche keinen C-Build">
|
||||
<richcontent TYPE="NOTE"><html>
|
||||
<head>
|
||||
|
||||
</head>
|
||||
<head/>
|
||||
<body>
|
||||
<p>
|
||||
Hatte immer die Fehlermeldung "build misconfigured" (o.ä). Hab lange rumgesucht, denn alle Settings waren effektiv gleich wie beim »VideoOutput«-Projekt. Bis ich dann im .project-File gesehen hab, daß auch noch ein C-Builder konfiguriert worden war (möglichweise ein Toolchain-Default).
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
||||
</richcontent>
|
||||
</html></richcontent>
|
||||
<icon BUILTIN="messagebox_warning"/>
|
||||
</node>
|
||||
</node>
|
||||
<node CREATED="1783644343706" ID="ID_481307677" MODIFIED="1783644354828" TEXT="ein GTK-Rahmen (wie letztes Jahr)"/>
|
||||
<node CREATED="1783644357376" ID="ID_1687423764" MODIFIED="1783644363091" TEXT="ein Worker-Thread"/>
|
||||
<node COLOR="#338800" CREATED="1783644343706" ID="ID_481307677" MODIFIED="1784052427730" TEXT="ein GTK-Rahmen (wie letztes Jahr)">
|
||||
<icon BUILTIN="button_ok"/>
|
||||
</node>
|
||||
<node CREATED="1783644357376" ID="ID_1687423764" MODIFIED="1784052436428" TEXT="ein Proactor-Thread"/>
|
||||
<node CREATED="1783644382004" ID="ID_222096554" MODIFIED="1783644392847" TEXT="Handler">
|
||||
<node CREATED="1783644394013" ID="ID_599467746" MODIFIED="1783644398783" TEXT="Completion-Handler"/>
|
||||
<node CREATED="1783644399671" ID="ID_1684157516" MODIFIED="1783644406037" TEXT="Submission-Handler"/>
|
||||
|
|
@ -933,25 +938,20 @@
|
|||
<node CREATED="1783901711226" ID="ID_1930870094" MODIFIED="1783901723228" TEXT="Claude schlägt vor, überhaupt nicht zu »synchronisieren«"/>
|
||||
<node CREATED="1783901727663" ID="ID_1596599158" MODIFIED="1783901972168" TEXT="Argument: da gibts nichts zu synchronisieren, denn die Sync geht nicht auf">
|
||||
<richcontent TYPE="NOTE"><html>
|
||||
<head>
|
||||
|
||||
</head>
|
||||
<head/>
|
||||
<body>
|
||||
<p>
|
||||
Der Desktop läuft mit z.B. 60fps, das video mit 25fps. Man sollte akzeptieren (und im Talk klar machen) daß das niemals aufgeht. Vielmehr sollte man regelmäßig die fertig geladenen Frames übergeben, wenn sie eben da sind. Für den Talk schlägt Claude vor, das Thema "tearing" mehr oder weniger zu ignorieren (hatte ich nicht gesagt, sehe ich aber genauso). Später, für die Prod-Version sei das ein nicht-trivialer Aspekt
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
||||
</richcontent>
|
||||
</html></richcontent>
|
||||
<node BACKGROUND_COLOR="#e0ceaa" COLOR="#690f14" CREATED="1783901847104" ID="ID_1936627376" MODIFIED="1783901856567" TEXT="Guter Punkt, da hätte ich mich möglicherweise verrant!">
|
||||
<icon BUILTIN="idea"/>
|
||||
</node>
|
||||
</node>
|
||||
<node CREATED="1783901974887" ID="ID_1974536015" MODIFIED="1783902062028" TEXT="Claude geht davon aus, daß die OpenGL-Pipeline im GUI-Thread laufen sollte">
|
||||
<richcontent TYPE="NOTE"><html>
|
||||
<head>
|
||||
|
||||
</head>
|
||||
<head/>
|
||||
<body>
|
||||
<p>
|
||||
...das sei zwar nicht notwendig (korrekt!), aber vermeide Komplexitäten. Ein OpenGL-Kontext ist an einen Thread gebunden, also müßte man nach jedem Thread-Wechsel umbinden.
|
||||
|
|
@ -960,8 +960,7 @@
|
|||
⟹ sehr gut, damit hat sich eine Frage von selber geklärt, die ich noch stellen wollte
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
||||
</richcontent>
|
||||
</html></richcontent>
|
||||
</node>
|
||||
<node CREATED="1783902186522" ID="ID_80755144" MODIFIED="1783902207310" TEXT="wegen dem Timing weist Claude auf die Möglichkeit hin, das über io_uring selber zu machen">
|
||||
<icon BUILTIN="back"/>
|
||||
|
|
@ -1021,9 +1020,7 @@
|
|||
<node CREATED="1783957017373" ID="ID_1419210108" MODIFIED="1783957033385" TEXT="wenn wir neue daten haben dann triggern wir die Anzige-Pipeline"/>
|
||||
<node BACKGROUND_COLOR="#accdc3" COLOR="#3f4015" CREATED="1783957040816" ID="ID_468719143" MODIFIED="1783957188965" STYLE="fork" TEXT="das funktioniert weil darunter ein Compositor sitzt">
|
||||
<richcontent TYPE="NOTE"><html>
|
||||
<head>
|
||||
|
||||
</head>
|
||||
<head/>
|
||||
<body>
|
||||
<!--
|
||||
body { font-family: SansSerif; font-size: 12pt }
|
||||
|
|
@ -1043,8 +1040,7 @@
|
|||
<strong http-equiv="content-type" content="text/html; charset=utf-8">Your aside — yes, and here's the actual mechanism:</strong> with swap interval 0 and swaps only triggered by <code class="bg-text-200/5 border border-0.5 border-border-300 text-danger-000 whitespace-pre-wrap rounded-[0.4rem] px-1 py-px text-[0.9rem]">frameReady.emit()</code>, you are <em>not</em> relying on OpenGL to "resend" anything between your swaps — OpenGL/EGL has no ongoing activity at all in between. What actually keeps the picture on screen is the desktop compositor: once <code class="bg-text-200/5 border border-0.5 border-border-300 text-danger-000 whitespace-pre-wrap rounded-[0.4rem] px-1 py-px text-[0.9rem]">eglSwapBuffers()</code> makes a buffer the current front buffer, that's simply what's there until you swap again, and the compositor samples it at its own repaint cadence (its vsync, typically 60Hz+) regardless of whether your app does anything. So your assumption holds, but the credit belongs to "a swapped buffer is persistent state the compositor keeps re-showing," not to any active redisplay behavior on your side — a good one-sentence clarification to have ready if someone in the audience asks "wait, doesn't something have to keep pushing frames?"
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
||||
</richcontent>
|
||||
</html></richcontent>
|
||||
<edge COLOR="#808080" STYLE="bezier" WIDTH="thin"/>
|
||||
<icon BUILTIN="wizard"/>
|
||||
</node>
|
||||
|
|
@ -1093,32 +1089,42 @@
|
|||
<node CREATED="1783952838505" ID="ID_1257919936" MODIFIED="1783952858029" TEXT="Worker Thread and State organisation">
|
||||
<node BACKGROUND_COLOR="#accdc3" COLOR="#3f4015" CREATED="1783952862448" ID="ID_842498915" MODIFIED="1783954578059" STYLE="fork">
|
||||
<richcontent TYPE="NODE"><html>
|
||||
<head>
|
||||
|
||||
</head>
|
||||
<head/>
|
||||
<body>
|
||||
<p>
|
||||
ich habe das Stichwort "<b>Proactor</b>" gebraucht. Claude bestätigt das
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
||||
</richcontent>
|
||||
</html></richcontent>
|
||||
<richcontent TYPE="NOTE"><html>
|
||||
<head>
|
||||
|
||||
</head>
|
||||
<head/>
|
||||
<body>
|
||||
<p>
|
||||
das heißt: die Lösung, auf die es nun für den Talk hinausläuft, ist daß ich nicht wirklich einen "Worker" hab (kein Vorgriff auf die Lumiera Engine), sondern einen Proactor.
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
||||
</richcontent>
|
||||
</html></richcontent>
|
||||
<edge COLOR="#808080" STYLE="bezier" WIDTH="thin"/>
|
||||
<icon BUILTIN="wizard"/>
|
||||
<node BACKGROUND_COLOR="#e0ceaa" COLOR="#690f14" CREATED="1783954584980" ID="ID_532077726" MODIFIED="1783954609626" TEXT="⟹ heißt: blocken auf wait_cqe()">
|
||||
<icon BUILTIN="messagebox_warning"/>
|
||||
</node>
|
||||
<node BACKGROUND_COLOR="#fefc4e" COLOR="#351d75" CREATED="1784052687896" ID="ID_1489274093" MODIFIED="1784052865429" TEXT="interessanter Ansatz: man kann einen Kernel-Timer in IO_Uring einbinden">
|
||||
<richcontent TYPE="NOTE"><html>
|
||||
<head/>
|
||||
<body>
|
||||
<p>
|
||||
Darauf wäre ich nicht gekommen; ich hätte an meinem von Lumiera abgeleiteten Schema festgehalten....
|
||||
</p>
|
||||
<p>
|
||||
Claude betont, das wäre idiomatisch und würde die Proactor-Loop ins Zentrum stellen. Das überzeugt mich ⟹ werde dann also doch einen Proactor in der Demo zeigen
|
||||
</p>
|
||||
</body>
|
||||
</html></richcontent>
|
||||
<linktarget COLOR="#f4f3a4" DESTINATION="ID_1489274093" ENDARROW="Default" ENDINCLINATION="638;-170;" ID="Arrow_ID_396926940" SOURCE="ID_1545269972" STARTARROW="None" STARTINCLINATION="1155;67;"/>
|
||||
<font BOLD="true" NAME="SansSerif" SIZE="12"/>
|
||||
<icon BUILTIN="idea"/>
|
||||
</node>
|
||||
</node>
|
||||
<node CREATED="1783953153918" ID="ID_1754327495" MODIFIED="1783953520369" TEXT="ich sage: für async IO braucht man immer eine Art State-Engine">
|
||||
<node CREATED="1783953183906" ID="ID_339096490" MODIFIED="1783953350863" TEXT="Claude widerspricht nicht">
|
||||
|
|
@ -1185,9 +1191,7 @@
|
|||
<node CREATED="1783953396149" ID="ID_12931299" MODIFIED="1783953416430" TEXT="ich sage: das bekommt man doch von selbst, wenn man die Buffer in einen Ring organisiert"/>
|
||||
<node BACKGROUND_COLOR="#accdc3" COLOR="#3f4015" CREATED="1783953941213" ID="ID_713186135" MODIFIED="1783954028109" STYLE="fork" TEXT="Claude greift das auf, betont aber (nochmal) daß die CQ-Reihenfolge nicht garantiert ist">
|
||||
<richcontent TYPE="NOTE"><html>
|
||||
<head>
|
||||
|
||||
</head>
|
||||
<head/>
|
||||
<body>
|
||||
<p http-equiv="content-type" content="text/html; charset=utf-8" class="font-claude-response-body break-words whitespace-normal">
|
||||
The ring idea is correct, and it's the right way to lay out storage — but it solves a different problem than the one we flagged last time, and I think that's the thing worth pulling apart carefully, because the two compose nicely rather than one replacing the other.
|
||||
|
|
@ -1199,8 +1203,7 @@
|
|||
<strong>What it does <em>not</em> give you for free:</strong> the display-order guarantee. The ring tells you <em>where</em> frame K's bytes live; it says nothing about <em>when</em> the read for frame K finishes relative to the read for frame K+1. Two SQEs submitted in order are not guaranteed to complete in order — for sequential reads against one local file on one machine it's very likely in practice, but "likely" is exactly the kind of unverified pragmatism you just said you don't accept. So you still need the mechanism from last time: track which frame is <em>next expected for display</em>, and only <code class="bg-text-200/5 border border-0.5 border-border-300 text-danger-000 whitespace-pre-wrap rounded-[0.4rem] px-1 py-px text-[0.9rem]">emit()</code> once that specific slot says <code class="bg-text-200/5 border border-0.5 border-border-300 text-danger-000 whitespace-pre-wrap rounded-[0.4rem] px-1 py-px text-[0.9rem]">Ready</code>  — regardless of what else has completed in the meantime.
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
||||
</richcontent>
|
||||
</html></richcontent>
|
||||
<edge COLOR="#808080" STYLE="bezier" WIDTH="thin"/>
|
||||
<icon BUILTIN="wizard"/>
|
||||
</node>
|
||||
|
|
@ -1212,9 +1215,7 @@
|
|||
</node>
|
||||
<node BACKGROUND_COLOR="#accdc3" COLOR="#3f4015" CREATED="1783954171957" ID="ID_1248856525" MODIFIED="1783954243633" STYLE="fork" TEXT="sollte einen "nextExpected"-Cursor im Thread-State mitführen">
|
||||
<richcontent TYPE="NOTE"><html>
|
||||
<head>
|
||||
|
||||
</head>
|
||||
<head/>
|
||||
<body>
|
||||
<ul>
|
||||
<li http-equiv="content-type" content="text/html; charset=utf-8" class="font-claude-response-body whitespace-normal break-words pl-2">
|
||||
|
|
@ -1225,8 +1226,7 @@
|
|||
</li>
|
||||
</ul>
|
||||
</body>
|
||||
</html>
|
||||
</richcontent>
|
||||
</html></richcontent>
|
||||
<edge COLOR="#808080" STYLE="bezier" WIDTH="thin"/>
|
||||
<icon BUILTIN="wizard"/>
|
||||
</node>
|
||||
|
|
@ -1377,9 +1377,7 @@
|
|||
</node>
|
||||
<node BACKGROUND_COLOR="#accdc3" COLOR="#3f4015" CREATED="1783957483612" ID="ID_918051178" MODIFIED="1783957589661" STYLE="fork" TEXT="a Zuckerl: Chrono-to-Kernel-Timespec">
|
||||
<richcontent TYPE="NOTE"><html>
|
||||
<head>
|
||||
|
||||
</head>
|
||||
<head/>
|
||||
<body>
|
||||
<!--
|
||||
body { font-family: SansSerif; font-size: 12pt }
|
||||
|
|
@ -1433,8 +1431,7 @@
|
|||
</p>
|
||||
<font color="#800c0c">auto ts = toKernelTimespec(40ms);</font>
|
||||
</body>
|
||||
</html>
|
||||
</richcontent>
|
||||
</html></richcontent>
|
||||
<edge COLOR="#808080" STYLE="bezier" WIDTH="thin"/>
|
||||
<icon BUILTIN="wizard"/>
|
||||
</node>
|
||||
|
|
@ -1442,16 +1439,13 @@
|
|||
<icon BUILTIN="back"/>
|
||||
<node CREATED="1783964913819" ID="ID_1290458999" MODIFIED="1783964940263" TEXT="gebe Claude eine »executive summary« bezüglich Lumiera Engine">
|
||||
<richcontent TYPE="NOTE"><html>
|
||||
<head>
|
||||
|
||||
</head>
|
||||
<head/>
|
||||
<body>
|
||||
<p>
|
||||
er hat dazu keine weiteren Fragen
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
||||
</richcontent>
|
||||
</html></richcontent>
|
||||
</node>
|
||||
<node COLOR="#338800" CREATED="1783964942767" ID="ID_993102807" MODIFIED="1783966105865" TEXT="lasse Claude die Diskrepanz herausarbeiten gegenüber dem Proactor-Pattern">
|
||||
<richcontent TYPE="NOTE"><html>
|
||||
|
|
@ -1520,9 +1514,7 @@
|
|||
</node>
|
||||
<node BACKGROUND_COLOR="#f8f1cb" COLOR="#a50125" CREATED="1783966752311" ID="ID_1363514128" MODIFIED="1783966837345" TEXT="whatever you do inside the token-held section must never block! ">
|
||||
<richcontent TYPE="NOTE"><html>
|
||||
<head>
|
||||
|
||||
</head>
|
||||
<head/>
|
||||
<body>
|
||||
That's a much bigger problem than in the FrOSCon demo, where blocking on
|
||||
|
||||
|
|
@ -1530,8 +1522,7 @@
|
|||
<code http-equiv="content-type" content="text/html; charset=utf-8" class="bg-text-200/5 border border-0.5 border-border-300 text-danger-000 whitespace-pre-wrap rounded-[0.4rem] px-1 py-px text-[0.9rem]">wait_cqe</code> was the worker's <em>entire job</em>. Here it would reintroduce exactly the kind of global stall your pull architecture is designed to avoid. The fix is straightforward but needs to be deliberate: only ever use the non-blocking <code class="bg-text-200/5 border border-0.5 border-border-300 text-danger-000 whitespace-pre-wrap rounded-[0.4rem] px-1 py-px text-[0.9rem]">io_uring_peek_cqe()</code>  inside grooming — check if anything's ready, harvest what's there, submit what's ready to submit, and move on regardless of whether anything was found. That keeps the ring interaction cheap and bounded, consistent with a critical section that's already supposed to be short.
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
||||
</richcontent>
|
||||
</html></richcontent>
|
||||
<icon BUILTIN="clanbomber"/>
|
||||
<node CREATED="1783966769728" ID="ID_882108638" MODIFIED="1783966784791" TEXT="Gefahr: wait_cqe() kann die ganze Engine stallen"/>
|
||||
<node CREATED="1783966793306" ID="ID_1685734854" MODIFIED="1783966801007" TEXT="stets nur io_uring_peek_cqe() verwenden">
|
||||
|
|
@ -1542,9 +1533,7 @@
|
|||
<icon BUILTIN="messagebox_warning"/>
|
||||
<node BACKGROUND_COLOR="#accdc3" COLOR="#3f4015" CREATED="1783966894277" ID="ID_231061601" MODIFIED="1783966904895" STYLE="fork" TEXT="">
|
||||
<richcontent TYPE="NOTE"><html>
|
||||
<head>
|
||||
|
||||
</head>
|
||||
<head/>
|
||||
<body>
|
||||
CQ overflow: if grooming genuinely doesn't run for a while under heavy CPU load, does a full completion queue drop completions, or buffer them? Recent kernels buffer overflow internally rather than dropping (subject to
|
||||
|
||||
|
|
@ -1552,30 +1541,24 @@
|
|||
<code http-equiv="content-type" content="text/html; charset=utf-8" class="bg-text-200/5 border border-0.5 border-border-300 text-danger-000 whitespace-pre-wrap rounded-[0.4rem] px-1 py-px text-[0.9rem]">IORING_FEATURE_NODROP</code>-era behavior), but it's worth confirming for whatever kernel baseline you commit to, rather than assuming.
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
||||
</richcontent>
|
||||
</html></richcontent>
|
||||
<edge COLOR="#808080" STYLE="bezier" WIDTH="thin"/>
|
||||
<icon BUILTIN="wizard"/>
|
||||
</node>
|
||||
</node>
|
||||
<node CREATED="1783966925433" ID="ID_852283957" MODIFIED="1783967012774">
|
||||
<richcontent TYPE="NODE"><html>
|
||||
<head>
|
||||
|
||||
</head>
|
||||
<head/>
|
||||
<body>
|
||||
<p>
|
||||
Deliberately avoid <code><font color="#7c5252">IORING_SETUP_SQPOLL</font></code>
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
||||
</richcontent>
|
||||
</html></richcontent>
|
||||
<icon BUILTIN="clanbomber"/>
|
||||
<node BACKGROUND_COLOR="#accdc3" COLOR="#3f4015" CREATED="1783967014652" ID="ID_758622095" MODIFIED="1783967890660" STYLE="fork" TEXT="">
|
||||
<richcontent TYPE="NOTE"><html>
|
||||
<head>
|
||||
|
||||
</head>
|
||||
<head/>
|
||||
<body>
|
||||
Deliberately avoid
|
||||
|
||||
|
|
@ -1583,8 +1566,7 @@
|
|||
<code http-equiv="content-type" content="text/html; charset=utf-8" class="bg-text-200/5 border border-0.5 border-border-300 text-danger-000 whitespace-pre-wrap rounded-[0.4rem] px-1 py-px text-[0.9rem]">IORING_SETUP_SQPOLL</code>. It's tempting since it removes the need to call into the kernel for submission most of the time, but it works by adding a kernel-side polling thread that reads the SQ ring on its own schedule — an actor outside your GroomingToken discipline and outside your capacity self-calibration entirely. That's exactly the kind of uncontrolled independent actor your architecture is built to avoid.
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
||||
</richcontent>
|
||||
</html></richcontent>
|
||||
<edge COLOR="#808080" STYLE="bezier" WIDTH="thin"/>
|
||||
<linktarget COLOR="#4389dd" DESTINATION="ID_758622095" ENDARROW="Default" ENDINCLINATION="196;89;" ID="Arrow_ID_200171107" SOURCE="ID_156133270" STARTARROW="None" STARTINCLINATION="334;27;"/>
|
||||
<icon BUILTIN="wizard"/>
|
||||
|
|
@ -1593,9 +1575,7 @@
|
|||
</node>
|
||||
<node BACKGROUND_COLOR="#accdc3" COLOR="#3f4015" CREATED="1783967051428" ID="ID_1173652481" MODIFIED="1783967077582" STYLE="fork" TEXT="Claude gibt eine »freundliche conclusion«">
|
||||
<richcontent TYPE="NOTE"><html>
|
||||
<head>
|
||||
|
||||
</head>
|
||||
<head/>
|
||||
<body>
|
||||
Net: I think folding I/O into the same single-threaded grooming discipline you already have is the
|
||||
|
||||
|
|
@ -1603,8 +1583,7 @@
|
|||
<em http-equiv="content-type" content="text/html; charset=utf-8">consistent</em> choice, not a compromise — you've already accepted one global serialization point for scheduling decisions, and a small, non-blocking peek/submit pair is cheap enough to ride along in that same section without becoming a new bottleneck category. The real design work is less "is this safe" (I think it is, modulo the ordering-semantics check and the non-blocking discipline) and more "how do we know, empirically, that grooming-section latency stays small enough once I/O bookkeeping is added" — which sounds like exactly the kind of thing you'd want numbers for before committing, rather than reasoning about further in the abstract.
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
||||
</richcontent>
|
||||
</html></richcontent>
|
||||
<edge COLOR="#808080" STYLE="bezier" WIDTH="thin"/>
|
||||
<icon BUILTIN="wizard"/>
|
||||
<node CREATED="1783967080199" ID="ID_820048763" MODIFIED="1783967099409" TEXT="geschickt schmeicheln wurde gut trainiert">
|
||||
|
|
@ -1640,9 +1619,7 @@
|
|||
</node>
|
||||
<node BACKGROUND_COLOR="#accdc3" COLOR="#3f4015" CREATED="1783967604917" ID="ID_1465824912" MODIFIED="1783967742187" STYLE="fork" TEXT="abschließene Einordnung">
|
||||
<richcontent TYPE="NOTE"><html>
|
||||
<head>
|
||||
|
||||
</head>
|
||||
<head/>
|
||||
<body>
|
||||
Even more directly relevant to your capacity-calibration idea: Glommio ships built-in "controllers" that automatically adjust per-task-queue scheduler shares to control throughput against a user-specified criterion — that's essentially your self-calibrating capacity-weights idea, independently arrived at by a different team solving an adjacent problem. Worth knowing that's not an idiosyncratic idea of yours — it's something the field has landed on more than once, which is generally a good sign for an architectural instinct.
|
||||
|
||||
|
|
@ -1659,22 +1636,18 @@
|
|||
<strong>One trend worth just keeping an eye on, not acting on:</strong> core counts keep climbing — high core-count workstation and consumer chips are increasingly normal — and any single serialization point gets proportionally more expensive as contention scales with thread count, even if each individual crossing is cheap. Not a problem today, and your task granularity buys you a lot of headroom, but it's the kind of thing worth having empirical data on (exactly the "more empirics needed" conclusion you already reached) if Lumiera is ever deployed on genuinely large core counts rather than typical desktop/workstation counts.
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
||||
</richcontent>
|
||||
</html></richcontent>
|
||||
<edge COLOR="#808080" STYLE="bezier" WIDTH="thin"/>
|
||||
<icon BUILTIN="wizard"/>
|
||||
<node CREATED="1783967750406" ID="ID_1287889954" MODIFIED="1783967801786" TEXT="Hinweis auf steigende Anzahl an Cores">
|
||||
<richcontent TYPE="NOTE"><html>
|
||||
<head>
|
||||
|
||||
</head>
|
||||
<head/>
|
||||
<body>
|
||||
<p>
|
||||
Lumiera könnte ja schon auch auf eine high-end-Workstation laufen
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
||||
</richcontent>
|
||||
</html></richcontent>
|
||||
</node>
|
||||
<node BACKGROUND_COLOR="#e0ceaa" COLOR="#690f14" CREATED="1783967758928" ID="ID_284611592" MODIFIED="1783967785981" TEXT="sollte Contention um das single-threaded bottleneck im Blick behalten">
|
||||
<icon BUILTIN="messagebox_warning"/>
|
||||
|
|
@ -1686,31 +1659,25 @@
|
|||
<icon BUILTIN="bell"/>
|
||||
<node COLOR="#435e98" CREATED="1783901558710" ID="ID_156133270" MODIFIED="1783967976008" STYLE="fork" TEXT="was ist IORING_SETUP_SQPOLL?">
|
||||
<richcontent TYPE="NOTE"><html>
|
||||
<head>
|
||||
|
||||
</head>
|
||||
<head/>
|
||||
<body>
|
||||
<p>
|
||||
von Claude erwähnt im Zusammenhang mit Locking visibility. Er weist auch darauf hin daß io_uring keine multiple thread submissions unterstützt. Zu dem Schluß war ich ja auch gekommen
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
||||
</richcontent>
|
||||
</html></richcontent>
|
||||
<arrowlink COLOR="#4389dd" DESTINATION="ID_758622095" ENDARROW="Default" ENDINCLINATION="196;89;" ID="Arrow_ID_200171107" STARTARROW="None" STARTINCLINATION="334;27;"/>
|
||||
<font NAME="SansSerif" SIZE="12"/>
|
||||
<icon BUILTIN="help"/>
|
||||
<node BACKGROUND_COLOR="#c8c0b6" COLOR="#435e98" CREATED="1783967899141" HGAP="34" ID="ID_1537697930" MODIFIED="1783967981234" TEXT="verstanden — klarer Fall" VSHIFT="23">
|
||||
<richcontent TYPE="NOTE"><html>
|
||||
<head>
|
||||
|
||||
</head>
|
||||
<head/>
|
||||
<body>
|
||||
<p>
|
||||
der Kernel kann nicht zaubern; stattdessen hat er dann einfach einen poll-Worker. Keine gute Idee in einer Architektur die selber alle Resourcen steuern möchte
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
||||
</richcontent>
|
||||
</html></richcontent>
|
||||
<icon BUILTIN="ksmiletris"/>
|
||||
</node>
|
||||
</node>
|
||||
|
|
@ -1723,9 +1690,7 @@
|
|||
<node CREATED="1783904515877" ID="ID_718620596" MODIFIED="1783904524313" TEXT="habe das nebenbei erwähnt"/>
|
||||
<node CREATED="1783904524844" ID="ID_473487490" MODIFIED="1783904606751" TEXT="Claude bestätigt: unter EGL ist die Anpassung nur minimal">
|
||||
<richcontent TYPE="NOTE"><html>
|
||||
<head>
|
||||
|
||||
</head>
|
||||
<head/>
|
||||
<body>
|
||||
<p http-equiv="content-type" content="text/html; charset=utf-8" class="font-claude-response-body break-words whitespace-normal">
|
||||
<strong>Wayland/X11</strong>
|
||||
|
|
@ -1745,8 +1710,7 @@
|
|||
So it's genuinely a small, well-isolated patch of platform glue — a handful of lines, gated behind a runtime check of which GDK backend is active (<code class="bg-text-200/5 border border-0.5 border-border-300 text-danger-000 whitespace-pre-wrap rounded-[0.4rem] px-1 py-px text-[0.9rem]">GDK_IS_X11_DISPLAY</code> / <code class="bg-text-200/5 border border-0.5 border-border-300 text-danger-000 whitespace-pre-wrap rounded-[0.4rem] px-1 py-px text-[0.9rem]">GDK_IS_WAYLAND_DISPLAY</code>) — everything downstream of surface creation is untouched.
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
||||
</richcontent>
|
||||
</html></richcontent>
|
||||
<icon BUILTIN="idea"/>
|
||||
</node>
|
||||
</node>
|
||||
|
|
@ -1908,6 +1872,9 @@
|
|||
</node>
|
||||
</node>
|
||||
<node CREATED="1783644425567" ID="ID_238189215" MODIFIED="1783644429274" TEXT="Flow-Steuerung">
|
||||
<node CREATED="1784052955974" ID="ID_1491751742" MODIFIED="1784052978769" TEXT="da nun Proactor ⟹ getrieben vom Timer-Tick">
|
||||
<icon BUILTIN="idea"/>
|
||||
</node>
|
||||
<node CREATED="1783644430659" ID="ID_269686877" MODIFIED="1783644452555" TEXT="Aufrabe: Vorlauf steuern">
|
||||
<node CREATED="1783644529049" ID="ID_486151338" MODIFIED="1783644875737" TEXT="zwei Phasen (Chase/Lock)">
|
||||
<richcontent TYPE="NOTE"><html>
|
||||
|
|
@ -1969,54 +1936,42 @@
|
|||
</node>
|
||||
<node COLOR="#435e98" CREATED="1783786668847" ID="ID_517750346" MODIFIED="1783787279327">
|
||||
<richcontent TYPE="NODE"><html>
|
||||
<head>
|
||||
|
||||
</head>
|
||||
<head/>
|
||||
<body>
|
||||
<p>
|
||||
mein Bauchgefühl: <b>GPL</b>
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
||||
</richcontent>
|
||||
</html></richcontent>
|
||||
<icon BUILTIN="back"/>
|
||||
<node CREATED="1783787032442" ID="ID_1472543330" MODIFIED="1783787496449">
|
||||
<richcontent TYPE="NODE"><html>
|
||||
<head>
|
||||
|
||||
</head>
|
||||
<head/>
|
||||
<body>
|
||||
<p>
|
||||
Das ist ein politisches Statement. <i>Das ist wichtiger denn je</i>
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
||||
</richcontent>
|
||||
</html></richcontent>
|
||||
<richcontent TYPE="NOTE"><html>
|
||||
<head>
|
||||
|
||||
</head>
|
||||
<head/>
|
||||
<body>
|
||||
<p>
|
||||
Der Vollständigkeit halber: es gibt den Unterschied zwischen negativer Freiheit und positiver Feiheit; letztere ist der Entschluß zu einer klar formulierten Vision. Die GPL formuliert hierzu die »vier Freiheiten«. Dahinter steht das Ideal des Gemeinwohls. Das muß leider verteidigt werden gegen Ausbeutung und Veruntreuung.
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
||||
</richcontent>
|
||||
</html></richcontent>
|
||||
</node>
|
||||
<node CREATED="1783787061169" ID="ID_1906878927" MODIFIED="1783787101544" TEXT="Der Code soll auf die Lumiera-Website. Eine Abweichende Lizenz schafft dort nur Komplikationen"/>
|
||||
<node CREATED="1783787106667" ID="ID_1055216820" MODIFIED="1783787173608" TEXT="und dann ist da noch der EGL-Code aus dem letzen Jahr (den ich tatsächlich kopiere)">
|
||||
<richcontent TYPE="NOTE"><html>
|
||||
<head>
|
||||
|
||||
</head>
|
||||
<head/>
|
||||
<body>
|
||||
<p>
|
||||
...und der beruht, transitiv argumentiert, nicht nur pro-forma, sondern auch dem Geist nach auf Publikationen unter Copyleft
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
||||
</richcontent>
|
||||
</html></richcontent>
|
||||
</node>
|
||||
</node>
|
||||
</node>
|
||||
|
|
|
|||
|
|
@ -29,12 +29,14 @@ class UringVideoPlayer
|
|||
Glib::Dispatcher dispatchFrame_;
|
||||
EglDisplay videoDisplayer_;
|
||||
std::thread proactorThread_;
|
||||
|
||||
|
||||
public:
|
||||
UringVideoPlayer (Gtk::Window& appWindow)
|
||||
: videoDisplayer_{appWindow, dispatchFrame_}
|
||||
, proactorThread_{[this]{ playVideo(); }}
|
||||
{ }
|
||||
|
||||
void terminate();
|
||||
|
||||
private:
|
||||
void
|
||||
|
|
@ -48,17 +50,20 @@ class UringVideoPlayer
|
|||
unique_ptr<UringVideoPlayer>
|
||||
launchPlayer (Gtk::Window& appWindow)
|
||||
{
|
||||
appWindow.resize (EglDisplay::VIDEO_WIDTH, EglDisplay::VIDEO_HEIGHT);
|
||||
|
||||
auto player = std::make_unique<UringVideoPlayer> (appWindow);
|
||||
|
||||
|
||||
return player;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void
|
||||
cleanUp (UringVideoPlayer& player)
|
||||
UringVideoPlayer::terminate()
|
||||
{
|
||||
|
||||
///// signal stop to proactor
|
||||
videoDisplayer_.cleanUp();
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -68,6 +73,6 @@ main (int, const char*[])
|
|||
{
|
||||
return GtkUringApp<UringVideoPlayer>{"io-uring-demo"}
|
||||
.onClick (launchPlayer)
|
||||
.onClose (cleanUp)
|
||||
.onClose ([](auto& player){ player.terminate();})
|
||||
.run();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,8 +12,7 @@
|
|||
|
||||
|
||||
#include "commons.hpp"
|
||||
#include "gtk-egl-app.hpp"
|
||||
#include "image-generator.hpp"
|
||||
#include "gtk-uring-app.hpp"
|
||||
|
||||
#include <iostream>
|
||||
#include <algorithm>
|
||||
|
|
@ -39,35 +38,43 @@ using std::string;
|
|||
class EglDisplay
|
||||
{
|
||||
/** EGL / X11 connection. */
|
||||
EGLDisplay display{nullptr};
|
||||
EGLSurface surface{nullptr};
|
||||
EGLDisplay display_{nullptr};
|
||||
EGLSurface surface_{nullptr};
|
||||
|
||||
EGLContext egl{nullptr};
|
||||
EGLContext egl_{nullptr};
|
||||
|
||||
uint texID{0};
|
||||
uint vboID{0};
|
||||
uint vaoID{0};
|
||||
uint texID_{0};
|
||||
uint vboID_{0};
|
||||
uint vaoID_{0};
|
||||
|
||||
float scaleX{1};
|
||||
float scaleY{1};
|
||||
float scaleX_{1};
|
||||
float scaleY_{1};
|
||||
|
||||
public:
|
||||
// hard wired here (should be dynamic in real-world usage)
|
||||
constexpr static uint VIDEO_WIDTH {320};
|
||||
constexpr static uint VIDEO_HEIGHT{240};
|
||||
|
||||
EglDisplay(FrameRate fps)
|
||||
{ }
|
||||
|
||||
EglDisplay(Gtk::Window& appWindow, Glib::Dispatcher& dispatchFrame)
|
||||
{
|
||||
openDisplay (appWindow);
|
||||
dispatchFrame.connect([this]{ displayFrame(); });
|
||||
}
|
||||
|
||||
void cleanUp();
|
||||
|
||||
private:
|
||||
void openDisplay (Gtk::Window&);
|
||||
void displayFrame();
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
EglDisplay
|
||||
openDisplay (Gtk::Window& appWindow, FrameRate fps)
|
||||
void
|
||||
EglDisplay::openDisplay (Gtk::Window& appWindow)
|
||||
{
|
||||
std::cout << "Open display-connection through EGL..." << std::endl;
|
||||
EglDisplay ctx{fps};
|
||||
|
||||
// use the X-Window as anchor to build an OpenGL context via EGL
|
||||
Glib::RefPtr<Gdk::Window> gdkWindow = appWindow.get_window();
|
||||
|
|
@ -85,9 +92,9 @@ openDisplay (Gtk::Window& appWindow, FrameRate fps)
|
|||
{EGL_PLATFORM_X11_SCREEN_EXT, xScreen
|
||||
,EGL_NONE};
|
||||
|
||||
ctx.display = eglGetPlatformDisplay (EGL_PLATFORM_X11_EXT, xDisplay, SCREEN_SPEC);
|
||||
if (EGL_NO_DISPLAY == ctx.display
|
||||
or not eglInitialize(ctx.display, NULL,NULL))
|
||||
display_ = eglGetPlatformDisplay (EGL_PLATFORM_X11_EXT, xDisplay, SCREEN_SPEC);
|
||||
if (EGL_NO_DISPLAY == display_
|
||||
or not eglInitialize(display_, NULL,NULL))
|
||||
__FAIL ("could not establish EGL Display connection.");
|
||||
|
||||
EGLint DESIRED_ATTRIBS[]
|
||||
|
|
@ -103,7 +110,7 @@ openDisplay (Gtk::Window& appWindow, FrameRate fps)
|
|||
|
||||
EGLint _cnt;
|
||||
EGLConfig config;
|
||||
if (not eglChooseConfig (ctx.display
|
||||
if (not eglChooseConfig (display_
|
||||
,DESIRED_ATTRIBS
|
||||
,& config
|
||||
,1,&_cnt)
|
||||
|
|
@ -111,8 +118,8 @@ openDisplay (Gtk::Window& appWindow, FrameRate fps)
|
|||
__FAIL ("unable to select a EGL display config with the required attributes");
|
||||
|
||||
|
||||
ctx.surface = eglCreateWindowSurface (ctx.display,config,xWindow,nullptr);
|
||||
if (not ctx.surface)
|
||||
surface_ = eglCreateWindowSurface (display_,config,xWindow,nullptr);
|
||||
if (not surface_)
|
||||
switch (eglGetError())
|
||||
{
|
||||
case EGL_BAD_CONFIG:
|
||||
|
|
@ -138,14 +145,14 @@ openDisplay (Gtk::Window& appWindow, FrameRate fps)
|
|||
// ,EGL_CONTEXT_MINOR_VERSION, 3
|
||||
,EGL_NONE};
|
||||
|
||||
ctx.egl = eglCreateContext (ctx.display, config
|
||||
,EGL_NO_CONTEXT // do not share definitions and data with another context
|
||||
,CTX_ATTRIBS);
|
||||
if (not ctx.egl)
|
||||
egl_ = eglCreateContext (display_, config
|
||||
,EGL_NO_CONTEXT // do not share definitions and data with another context
|
||||
,CTX_ATTRIBS);
|
||||
if (not egl_)
|
||||
__FAIL ("failed to create OpenGL context for this display with desired visuals");
|
||||
|
||||
// create a binding for the current thread to use this context on this window
|
||||
if (not eglMakeCurrent (ctx.display, ctx.surface,ctx.surface, ctx.egl))
|
||||
if (not eglMakeCurrent (display_, surface_,surface_, egl_))
|
||||
__FAIL ("failed to attach an OpenGL context to the application X-Window");
|
||||
|
||||
|
||||
|
|
@ -241,8 +248,8 @@ openDisplay (Gtk::Window& appWindow, FrameRate fps)
|
|||
|
||||
/* === setup a 2D texture, to be mapped into the viewport === */
|
||||
glActiveTexture(GL_TEXTURE0); // activate texture-unit #0 on the GPU
|
||||
glGenTextures (1, &ctx.texID); // allocate 1 new texture ID
|
||||
glBindTexture (GL_TEXTURE_2D, ctx.texID); // use this textureID as "the" TEXTURE_2D
|
||||
glGenTextures (1, &texID_); // allocate 1 new texture ID
|
||||
glBindTexture (GL_TEXTURE_2D, texID_); // use this textureID as "the" TEXTURE_2D
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); // configure image scaling filter
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); // clamp, don't wrap at the texture edges
|
||||
|
|
@ -255,13 +262,13 @@ openDisplay (Gtk::Window& appWindow, FrameRate fps)
|
|||
|
||||
/* === setup a fixed geometry to hold that texture === */
|
||||
glDisable (GL_DEPTH_TEST); // we do not need 3D layering / positioning
|
||||
glViewport (0, 0, ctx.VIDEO_WIDTH, ctx.VIDEO_HEIGHT); // Origin in the middle of the window (note Y points upwards)
|
||||
glViewport (0, 0, VIDEO_WIDTH, VIDEO_HEIGHT); // Origin in the middle of the window (note Y points upwards)
|
||||
|
||||
// Note: this demo uses a fixed-size window and hard-coded video size;
|
||||
// a real-world implementation would have to place the video frame
|
||||
// dynamically into the available screen space, possibly scaling up/down
|
||||
GLfloat sX{ctx.scaleX};
|
||||
GLfloat sY{ctx.scaleY}; // Note: positions use »normalised device coordinates« (NDC)
|
||||
GLfloat sX{scaleX_};
|
||||
GLfloat sY{scaleY_}; // Note: positions use »normalised device coordinates« (NDC)
|
||||
GLfloat w{1}; // TEXTURE_2D points cover the range (0,0) ... (1,1)
|
||||
GLfloat h{1};
|
||||
|
||||
|
|
@ -273,11 +280,11 @@ openDisplay (Gtk::Window& appWindow, FrameRate fps)
|
|||
,-sX, sY , 0,0 // have to map the texture flipped, since OpenGL orients Y upwards.
|
||||
};
|
||||
|
||||
glGenBuffers (1, &ctx.vboID); // allocate 1 new vertex-buffer-object
|
||||
glGenVertexArrays(1, &ctx.vaoID); // allocate 1 new vertex-array-object (to attach all definitions)
|
||||
glGenBuffers (1, &vboID_); // allocate 1 new vertex-buffer-object
|
||||
glGenVertexArrays(1, &vaoID_); // allocate 1 new vertex-array-object (to attach all definitions)
|
||||
|
||||
glBindVertexArray(ctx.vaoID); // activate the VAO to pick up the following definitions...
|
||||
glBindBuffer (GL_ARRAY_BUFFER, ctx.vboID);
|
||||
glBindVertexArray(vaoID_); // activate the VAO to pick up the following definitions...
|
||||
glBindBuffer (GL_ARRAY_BUFFER, vboID_);
|
||||
// copy the vertexData into the vertex-buffer-object currently bound to GL_ARRAY_BUFFER
|
||||
glBufferData (GL_ARRAY_BUFFER, sizeof(vertexData), vertexData, GL_STATIC_DRAW);
|
||||
|
||||
|
|
@ -294,29 +301,25 @@ openDisplay (Gtk::Window& appWindow, FrameRate fps)
|
|||
glEnableVertexAttribArray (0); // activate attribute #1 ≙ input argument `position` in vertexShader
|
||||
glEnableVertexAttribArray (1); // activate attribute #2 ≙ input argument `texCoord` in vertexShader
|
||||
|
||||
|
||||
// hand-over the activated connection context
|
||||
// to be managed by the GTK application...
|
||||
std::cout << "Started playback at "<<fps<<" frames/sec." << std::endl;
|
||||
return ctx;
|
||||
std::cout << "Successfully established OpenGL display ("<<VIDEO_WIDTH<<"x"<<VIDEO_HEIGHT<<"px) within GTK-Window." << std::endl;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void
|
||||
displayFrame (EglDisplay& ctx)
|
||||
EglDisplay::displayFrame()
|
||||
{
|
||||
uint frameNr = ctx.imgGen_.getFrameNr();
|
||||
uint fps = ctx.imgGen_.getFps();
|
||||
uint frameNr = imgGen_.getFrameNr();
|
||||
uint fps = imgGen_.getFps();
|
||||
if (0 == frameNr % fps)
|
||||
std::cout << "tick ... " << ctx.imgGen_.getFrameNr() << std::endl;
|
||||
std::cout << "tick ... " << imgGen_.getFrameNr() << std::endl;
|
||||
|
||||
// compute a buffer with RGB data and bind it into the prepared texture...
|
||||
const void* buffer = ctx.imgGen_.buildNext().data();
|
||||
const void* buffer = imgGen_.buildNext().data();
|
||||
glTexImage2D (GL_TEXTURE_2D // the target texture store to work on, here "the" TEXTURE_2D
|
||||
,0 // detail level (when using mipmap reduction, which we don't)
|
||||
,GL_RGB // internal format or features to use for this texture
|
||||
,ctx.VIDEO_WIDTH,ctx.VIDEO_HEIGHT, /*border*/ 0
|
||||
,VIDEO_WIDTH,VIDEO_HEIGHT, /*border*/ 0
|
||||
,GL_RGB // data layout of the provided pixels
|
||||
,GL_UNSIGNED_BYTE // data format / size of the pixels
|
||||
,buffer
|
||||
|
|
@ -326,30 +329,18 @@ displayFrame (EglDisplay& ctx)
|
|||
glDrawArrays(GL_QUADS, 0, 4);
|
||||
|
||||
// double-buffer flip, automatically invokes glFlush()
|
||||
eglSwapBuffers (ctx.display, ctx.surface);
|
||||
eglSwapBuffers (display_, surface_);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
cleanUp (EglDisplay& ctx)
|
||||
EglDisplay::cleanUp()
|
||||
{
|
||||
std::cout << "STOP " << ctx.imgGen_.getFrameNr() << " frames displayed." << std::endl;
|
||||
std::cout << "STOP " << imgGen_.getFrameNr() << " frames displayed." << std::endl;
|
||||
|
||||
// detach binding with OpenGL context
|
||||
eglMakeCurrent (ctx.display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
|
||||
eglDestroySurface (ctx.display, ctx.surface);
|
||||
eglDestroyContext (ctx.display, ctx.egl);
|
||||
eglTerminate(ctx.display); // detach EGL from display
|
||||
}
|
||||
|
||||
|
||||
|
||||
int
|
||||
main (int, const char*[])
|
||||
{
|
||||
return GtkEglApp<EglDisplay>{"demo.egl"}
|
||||
.onStart (openDisplay)
|
||||
.onFrame (displayFrame)
|
||||
.onClose (cleanUp)
|
||||
.run(30);
|
||||
eglMakeCurrent (display_, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
|
||||
eglDestroySurface (display_, surface_);
|
||||
eglDestroyContext (display_, egl_);
|
||||
eglTerminate(display_); // detach EGL from display
|
||||
}
|
||||
|
|
|
|||
|
|
@ -108,7 +108,7 @@ class GtkUringApp
|
|||
|
||||
demoWindow_.button_.set_sensitive(false); // disable the button
|
||||
demoWindow_.button_.set_label("active");
|
||||
|
||||
|
||||
auto closeHook = [this]{
|
||||
if (closeTask_)
|
||||
closeTask_(*processor_);
|
||||
|
|
|
|||
Loading…
Reference in a new issue