react-x11 2.15.0 → 2.15.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/src/wayland/context2d.js +28 -2
- package/src/wayland/device.js +23 -0
- package/src/wayland/target.js +9 -1
- package/src/wayland/xkb.js +19 -4
package/package.json
CHANGED
package/src/wayland/context2d.js
CHANGED
|
@@ -532,7 +532,7 @@ export class WaylandContext2D {
|
|
|
532
532
|
*/
|
|
533
533
|
begin(width, height, timestamp = 0) {
|
|
534
534
|
this.init();
|
|
535
|
-
this.
|
|
535
|
+
this._take();
|
|
536
536
|
const t = this._target;
|
|
537
537
|
if (t) {
|
|
538
538
|
t.bind();
|
|
@@ -612,7 +612,7 @@ export class WaylandContext2D {
|
|
|
612
612
|
// Mid stencil-then-cover the state is set up for the pass, not for a
|
|
613
613
|
// plain batch, and the device cannot have changed hands under it.
|
|
614
614
|
if (this._device.owner === this || this._stencilling) return;
|
|
615
|
-
this.
|
|
615
|
+
this._take();
|
|
616
616
|
this._makeCurrent?.();
|
|
617
617
|
this.init();
|
|
618
618
|
// As `begin()` has it: a target's size *is* the projection.
|
|
@@ -624,6 +624,26 @@ export class WaylandContext2D {
|
|
|
624
624
|
this._applyState();
|
|
625
625
|
}
|
|
626
626
|
|
|
627
|
+
/**
|
|
628
|
+
* Take the device, drawing whatever the last owner still had buffered.
|
|
629
|
+
*
|
|
630
|
+
* A context batches: its quads sit in a vertex buffer until the mode
|
|
631
|
+
* changes, the buffer fills, or someone flushes. So the handover is where
|
|
632
|
+
* the outgoing owner's batch is drawn — otherwise a frame's worth of work
|
|
633
|
+
* can sit there while the pixels it was meant to produce are read by
|
|
634
|
+
* whoever comes next, and stay there until that context happens to draw
|
|
635
|
+
* something of a different kind (#578). The state is still the outgoing
|
|
636
|
+
* owner's at this point, which is what the flush needs.
|
|
637
|
+
*
|
|
638
|
+
* It is also what device.js's invariant rests on: the owner is the only
|
|
639
|
+
* context that can be holding anything.
|
|
640
|
+
*/
|
|
641
|
+
_take() {
|
|
642
|
+
const previous = this._device.owner;
|
|
643
|
+
if (previous && previous !== this) previous._flush();
|
|
644
|
+
this._device.owner = this;
|
|
645
|
+
}
|
|
646
|
+
|
|
627
647
|
/** Give the device up, so the next draw through this context re-takes it. */
|
|
628
648
|
_release() {
|
|
629
649
|
if (this._device.owner === this) this._device.owner = null;
|
|
@@ -1950,6 +1970,11 @@ export class WaylandContext2D {
|
|
|
1950
1970
|
|
|
1951
1971
|
/** Two triangles from four corners, in order TL, TR, BR, BL. */
|
|
1952
1972
|
_quad(pos, uv, color, params) {
|
|
1973
|
+
// Buffering is taking the device, not a step before it: the quad is GL
|
|
1974
|
+
// work that has been decided on and not yet issued, and the handover in
|
|
1975
|
+
// `_take` is the only thing that can get it issued before someone reads
|
|
1976
|
+
// the pixels it makes. A property compare in the common case.
|
|
1977
|
+
this._claim();
|
|
1953
1978
|
if (this._n + 6 > MAX_VERTS) this._flush();
|
|
1954
1979
|
const v = this._verts;
|
|
1955
1980
|
let o = this._n * STRIDE;
|
|
@@ -1974,6 +1999,7 @@ export class WaylandContext2D {
|
|
|
1974
1999
|
|
|
1975
2000
|
/** One triangle, for the stencil pass. Colour and params are irrelevant. */
|
|
1976
2001
|
_tri(x0, y0, x1, y1, x2, y2) {
|
|
2002
|
+
this._claim();
|
|
1977
2003
|
if (this._n + 3 > MAX_VERTS) this._flush();
|
|
1978
2004
|
const v = this._verts;
|
|
1979
2005
|
let o = this._n * STRIDE;
|
package/src/wayland/device.js
CHANGED
|
@@ -16,6 +16,15 @@
|
|
|
16
16
|
// back. Whoever drew in between does not have to know who comes next, and a
|
|
17
17
|
// caller does not have to know there is a device at all.
|
|
18
18
|
//
|
|
19
|
+
// Claiming is also a *batch boundary*: a 2d context buffers its quads and
|
|
20
|
+
// draws them in one call later, so the outgoing owner is flushed on the way
|
|
21
|
+
// out. That is what makes the invariant this module offers true — **only the
|
|
22
|
+
// owner can have work still buffered** — and the invariant is what lets
|
|
23
|
+
// anyone about to read a target's pixels get them by flushing one context
|
|
24
|
+
// (`flushDevice`) rather than by knowing which one drew them. Without it a
|
|
25
|
+
// held surface context's whole frame could sit in a vertex buffer while the
|
|
26
|
+
// `drawImage` that should show it sampled the texture behind it (#578).
|
|
27
|
+
//
|
|
19
28
|
// One record per `gl`, keyed weakly: a GPU that goes away takes its record
|
|
20
29
|
// with it.
|
|
21
30
|
const devices = new WeakMap();
|
|
@@ -53,3 +62,17 @@ export function releaseDevice(gl) {
|
|
|
53
62
|
const device = shared(gl) ? devices.get(gl) : null;
|
|
54
63
|
if (device) device.owner = null;
|
|
55
64
|
}
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Draw what is still buffered, so that a target's texture holds everything
|
|
68
|
+
* that has been drawn into it.
|
|
69
|
+
*
|
|
70
|
+
* The owner is the only context that can be holding anything (see above), so
|
|
71
|
+
* flushing it is flushing the device. Call before *reading* a target's pixels
|
|
72
|
+
* behind the contexts' backs — a framebuffer blit, a scroll copy — the way
|
|
73
|
+
* `releaseDevice` is called after writing them.
|
|
74
|
+
*/
|
|
75
|
+
export function flushDevice(gl) {
|
|
76
|
+
const device = shared(gl) ? devices.get(gl) : null;
|
|
77
|
+
device?.owner?.flush();
|
|
78
|
+
}
|
package/src/wayland/target.js
CHANGED
|
@@ -21,7 +21,7 @@
|
|
|
21
21
|
// asking EGL for it means the window's own config no longer has to carry
|
|
22
22
|
// stencil bits at all; the request in glcontext.js stays as belt and braces.
|
|
23
23
|
|
|
24
|
-
import { releaseDevice } from './device.js';
|
|
24
|
+
import { flushDevice, releaseDevice } from './device.js';
|
|
25
25
|
|
|
26
26
|
export class GLTarget {
|
|
27
27
|
/**
|
|
@@ -133,6 +133,9 @@ export class GLTarget {
|
|
|
133
133
|
*/
|
|
134
134
|
blitTo(drawFbo, rects, dstWidth = this.width, dstHeight = this.height) {
|
|
135
135
|
const gl = this.gl;
|
|
136
|
+
// Reading these pixels, so everything drawn into them has to be in the
|
|
137
|
+
// texture and not still in a context's vertex buffer (device.js).
|
|
138
|
+
flushDevice(gl);
|
|
136
139
|
gl.bindFramebuffer(gl.READ_FRAMEBUFFER, this.fbo);
|
|
137
140
|
gl.bindFramebuffer(gl.DRAW_FRAMEBUFFER, drawFbo);
|
|
138
141
|
gl.disable(gl.SCISSOR_TEST);
|
|
@@ -201,6 +204,11 @@ export class GLTarget {
|
|
|
201
204
|
const sy = dstY0 - dy;
|
|
202
205
|
|
|
203
206
|
const gl = this.gl;
|
|
207
|
+
// A scroll reads this target before it writes it, so anything a context
|
|
208
|
+
// still has buffered has to land first — or the band that moves is the
|
|
209
|
+
// frame before last's, and the buffered quads arrive afterwards at the
|
|
210
|
+
// position the scroll just left (device.js).
|
|
211
|
+
flushDevice(gl);
|
|
204
212
|
const scratch = scratchFor(gl, bw, bh);
|
|
205
213
|
// out: this[sx,sy,bw,bh] -> scratch[0,0]
|
|
206
214
|
gl.bindFramebuffer(gl.READ_FRAMEBUFFER, this.fbo);
|
package/src/wayland/xkb.js
CHANGED
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
// xkb_types `type "FOUR_LEVEL" { modifiers= Shift+LevelThree;
|
|
18
18
|
// map[Shift]= 2; ... }` modifier set -> level
|
|
19
19
|
// xkb_symbols `key <AD01> { [ q, Q ] };` keycode -> keysyms per level,
|
|
20
|
-
// with `symbols[Group2]` and `type=` where given
|
|
20
|
+
// with `symbols[Group2]`/`symbols[2]` and `type=` where given
|
|
21
21
|
// `modifier_map Mod5 { <LVL3> }` real modifier -> keycodes
|
|
22
22
|
// xkb_compat `interpret ISO_Level3_Shift { virtualModifier= LevelThree; }`
|
|
23
23
|
// keysym -> virtual modifier
|
|
@@ -187,17 +187,32 @@ export class XkbKeymap {
|
|
|
187
187
|
// explicit per-group or global type
|
|
188
188
|
const typeAll = body.match(/(?:^|[,{\s])type\s*=\s*"([^"]+)"/);
|
|
189
189
|
const typeByGroup = new Map();
|
|
190
|
-
for (const t of body.matchAll(/type\[Group(\d)\]\s*=\s*"([^"]+)"/g))
|
|
190
|
+
for (const t of body.matchAll(/type\[(?:Group)?(\d)\]\s*=\s*"([^"]+)"/g))
|
|
191
191
|
typeByGroup.set(+t[1], t[2]);
|
|
192
192
|
// symbols[GroupN]= [ a, b ] and the bare form { [ a, b ] }
|
|
193
|
+
//
|
|
194
|
+
// The group subscript has two spellings, and the one this file was
|
|
195
|
+
// written against is the one a compositor never sends. `xkbcomp -xkb`
|
|
196
|
+
// writes `symbols[Group1]`; **libxkbcommon writes `symbols[1]`**, and
|
|
197
|
+
// libxkbcommon is what serialises the keymap on the other end of
|
|
198
|
+
// `wl_keyboard.keymap` — so every keymap that reaches this parser for
|
|
199
|
+
// real uses the bare number. Both are accepted, because a keymap also
|
|
200
|
+
// arrives here from `xkbcomp` output in a test or a bug report.
|
|
193
201
|
const lists = [];
|
|
194
202
|
for (const g of body.matchAll(
|
|
195
|
-
/symbols\[Group(\d)\]\s*=\s*\[([^\]]*)\]/g,
|
|
203
|
+
/symbols\[(?:Group)?(\d)\]\s*=\s*\[([^\]]*)\]/g,
|
|
196
204
|
)) {
|
|
197
205
|
lists[+g[1] - 1] = g[2];
|
|
198
206
|
}
|
|
199
207
|
if (lists.length === 0) {
|
|
200
|
-
|
|
208
|
+
// The bare form, `key <ESC> { [ Escape ] };` — the list is the one
|
|
209
|
+
// bracket that is *not* a subscript, which is what the leading
|
|
210
|
+
// delimiter says: a subscript is always glued to the word in front
|
|
211
|
+
// of it (`symbols[`, `type[`, `actions[`). Matching any bracket at
|
|
212
|
+
// all is how an unrecognised subscript spelling used to end up here
|
|
213
|
+
// and take `[1]` for the symbol list, which decodes every key on the
|
|
214
|
+
// keyboard to the keysym named `1`.
|
|
215
|
+
const bare = body.match(/(?:^|[,{\s])\[([^\]]*)\]/);
|
|
201
216
|
if (bare) lists[0] = bare[1];
|
|
202
217
|
}
|
|
203
218
|
for (let gi = 0; gi < lists.length; gi++) {
|