From 589efee4f8d980354dbed7173c483bb6282d73a7 Mon Sep 17 00:00:00 2001 From: Sergio Date: Mon, 14 Sep 2026 14:35:13 +0000 Subject: [PATCH] =?UTF-8?q?atuq:=20en=20la=20imagen=20el=20navegador=20S?= =?UTF-8?q?=C3=8D=20pinta=20=E2=80=94=20la=20segunda=20pantalla=20no=20era?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit La sospecha salía del propio serial: el arranque del §6.10.ter veía DOS dispositivos DRM (`drm: card0 card1 renderD128`) y uno nuevo ve uno solo. Sin `-vga none`, QEMU agrega una VGA estándar además del virtio-gpu, OVMF pinta su GOP ahí y el kernel levanta simpledrm encima: un compositor con dos tarjetas puede componer en la que el `screendump` no muestra, y eso se ve igual que «la ventana no aparece». Por eso el guion lleva `VGA=1`, para pedir ese caso por su nombre. Medido con las dos configuraciones y el mismo lanzamiento: -vga none → card0 → 703766 px magenta VGA=1 → card0 card1 → 703766 px magenta El mismo número al píxel. La ventana aparece —panel, dock y el navegador con su barra lateral—, `nsWindow::Create() Toplevel` está en el MOZ_LOG, la superficie se mapea y `mIsFullyOccluded 0`, con `WaylandBufferSHM` de 1280x696, el mismo camino de buffers que bajo sway. ⇒ la segunda pantalla no es la causa. Queda una sola diferencia con aquella corrida: cómo se lanzó el navegador. Acá va con perfil nuevo y MOZ_ENABLE_WAYLAND puesto; allá fue un `atuq` pelado con su perfil por defecto tecleado en el serial. Para eso está `--como-usuario`, que es la corrida que sigue. ⚠ Dos trampas del arnés, medidas y escritas en el guion: el terminal hace ECO de lo que se le escribe, así que una marca de fin literal se lee en el eco y las órdenes se pisan; y `cmd & ; echo` es error de sintaxis en ash ⇒ el navegador no se lanzó y la corrida siguió dando capturas de un escritorio vacío, que se leen igual que el fallo que se investiga. --- docs/26-atuq-envoltorio-gecko.md | 42 +++++++++++++++++++ scripts/cosmic/atuq-en-imagen.py | 70 ++++++++++++++++++++++++++------ 2 files changed, 99 insertions(+), 13 deletions(-) diff --git a/docs/26-atuq-envoltorio-gecko.md b/docs/26-atuq-envoltorio-gecko.md index 4da0c379..c19d37cf 100644 --- a/docs/26-atuq-envoltorio-gecko.md +++ b/docs/26-atuq-envoltorio-gecko.md @@ -1671,6 +1671,48 @@ Lo que queda como variable —y es donde sigue la caza— es el arranque de verd mismo `MOZ_LOG` y pide capturas por QMP — la corrida del §6.10.ter fue a mano y no dejó un solo log que se pueda releer, que es exactamente lo que hace falta para comparar. +#### 6.10.quinquies En la imagen, el navegador SÍ pinta — y la segunda pantalla no era (2026-09-14) + +`scripts/cosmic/atuq-en-imagen.py` arranca la imagen del §6.10.ter, maneja el serial, lanza el +navegador con `MOZ_LOG` del widget de Wayland y pide capturas por QMP. La corrida de aquel día fue a +mano y no dejó un log que se pueda releer; ésta deja todo en `work/atuq-imagen-*`. + +**La sospecha que se fue a probar** salía del propio serial: aquel arranque veía DOS dispositivos DRM +y éste uno solo. + + == cosmic :: kernel 6.16.12 · drm: card0 card1 renderD128 ← §6.10.ter (sin `-vga none`) + == cosmic :: kernel 6.16.12 · drm: card0 renderD128 ← con `-vga none` + +Sin `-vga none`, QEMU agrega una VGA estándar ADEMÁS del virtio-gpu, OVMF pinta su GOP ahí y el +kernel levanta `simpledrm` encima. Un compositor con dos tarjetas puede componer en la que el +`screendump` no muestra, y eso se vería exactamente como «la ventana no aparece». + +**Medido, con las dos configuraciones y el mismo lanzamiento** (perfil nuevo, `MOZ_ENABLE_WAYLAND=1`, +página de un solo color): + +| vídeo de QEMU | DRM en el guest | magenta en pantalla | +|---|---|---| +| `-vga none` | `card0` | **703 766 px** | +| `VGA=1` (como el §6.10.ter) | `card0 card1` | **703 766 px** | + +El mismo número en las dos, al píxel. La ventana aparece —panel de COSMIC, dock y el navegador con su +barra lateral—, `nsWindow::Create() Toplevel` sale en el `MOZ_LOG`, la superficie se mapea y +`NotifyOcclusionState() mIsFullyOccluded 0`. El camino de buffers es el mismo que bajo sway: +`WaylandBufferSHM`, 1280×696. + +⇒ **la segunda pantalla NO es la causa**, y el síntoma del §6.10.ter no se reproduce así. Eso deja una +sola diferencia entre aquella corrida y ésta, y es la que sigue: **cómo se lanzó el navegador**. Acá +va con perfil nuevo y las variables puestas; allá fue un `atuq` pelado, con su perfil por defecto —el +que trae la barra lateral y la IA— tecleado en el serial. Por eso el guion tiene `--como-usuario`: +lanza exactamente eso. + +⚠ **Y la trampa del método que costó una corrida entera**, escrita en el guion para que no se repita: +el terminal hace **eco** de lo que se le escribe, así que una marca de fin escrita literal aparece en +el serial ANTES de que el shell ejecute nada — el arnés la lee en el eco, da la orden por terminada y +manda la siguiente encima. Y `cmd & ; echo …` es **error de sintaxis** en ash: el navegador no se +lanzó y la corrida siguió como si todo fuera bien, con capturas de un escritorio vacío que se leían +igual que el fallo que se estaba investigando. + ### 6.11 Y ahora la pregunta que faltaba: ¿REPRODUCE? (2026-09-07) El §6.10 preguntó «¿qué NO puede hacer?» y contestó leyendo cadenas. Media pregunta. La otra mitad diff --git a/scripts/cosmic/atuq-en-imagen.py b/scripts/cosmic/atuq-en-imagen.py index 2c6e2eb1..b4932f31 100755 --- a/scripts/cosmic/atuq-en-imagen.py +++ b/scripts/cosmic/atuq-en-imagen.py @@ -25,6 +25,10 @@ causa. """ import argparse, json, os, shutil, socket, subprocess, sys, time +# Sin esto la salida sale por tandas cuando se redirige a un fichero, y una corrida de 20 minutos se +# lee como si estuviera colgada. +sys.stdout.reconfigure(line_buffering=True) + RAIZ = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) IMG = os.environ.get("IMG", "/mnt/cosecha/takana-cosmic-qemu.img") OVMF_CODE = os.environ.get("OVMF_CODE", "/usr/share/edk2/x64/OVMF_CODE.4m.fd") @@ -32,6 +36,18 @@ OVMF_VARS = os.environ.get("OVMF_VARS", "/usr/share/edk2/x64/OVMF_VARS.4m.fd") MEM = os.environ.get("MEM", "2560") SMP = os.environ.get("SMP", "2") +# ⚠ `VGA=1` reproduce el arranque del §6.10.ter, y la diferencia NO es cosmética: sin `-vga none`, +# QEMU agrega una VGA estándar ADEMÁS del virtio-gpu, OVMF pinta su GOP ahí y el kernel levanta +# `simpledrm` encima ⇒ el guest ve DOS dispositivos DRM. En el serial se lee tal cual: +# +# == cosmic :: kernel 6.16.12 · drm: card0 card1 renderD128 (corrida del §6.10.ter) +# == cosmic :: kernel 6.16.12 · drm: card0 renderD128 (con -vga none) +# +# Un compositor con dos tarjetas puede componer en la que el `screendump` NO muestra. Por eso el +# default acá es UNA sola (-vga none) y la reproducción del caso original es una opción explícita: +# son dos mediciones distintas y hay que poder pedir cada una por su nombre. +VGA_ARGS = [] if os.environ.get("VGA") == "1" else ["-vga", "none"] + class Serial: """El serial de la VM. Todo lo que entra queda en el .log crudo, pase lo que pase.""" @@ -76,12 +92,27 @@ class Serial: print(f" ⚠ nunca llegó «{marca}» {nombre} en {segundos}s", flush=True) return self.buf[vistos:].decode("utf-8", "replace") - def cmd(self, orden, segundos=30): - """Manda una orden y devuelve su salida (delimitada por una marca propia).""" - marca = f"__FIN{int(time.time()*1000) % 100000}__" - self.s.sendall(f"{orden}; echo {marca}\n".encode()) - sal = self.esperar(marca, segundos, nombre=f"de «{orden[:40]}»") - return sal + def cmd(self, orden, segundos=30, fondo=False): + """Manda una orden y devuelve su salida (delimitada por una marca propia). + + ⚠ DOS TRAMPAS MEDIDAS, las dos hacen que la orden NO CORRA y el guion siga como si nada: + + · **el terminal hace ECO de lo que se le escribe**, así que una marca escrita literal en la + línea aparece en el serial ANTES de que el shell ejecute nada: el `esperar` la ve en el eco + y vuelve al instante, y las órdenes se pisan unas a otras. Por eso la marca se ARMA EN EL + GUEST partida en dos (`'FIN''-123'`): el eco muestra las comillas y sólo la salida trae la + marca entera. + · **`cmd & ; echo …` es un error de sintaxis** en ash: pegarle un `;` a un `&` no lanza nada + y el shell contesta «syntax error». Lo de fondo va en su propia línea (`fondo=True`). + """ + n = int(time.time() * 1000) % 100000 + marca = f"FIN-{n}" + if fondo: + self.s.sendall(f"{orden}\n".encode()); time.sleep(0.5) + self.s.sendall(f"echo 'FIN''-{n}'\n".encode()) + else: + self.s.sendall(f"{orden}; echo 'FIN''-{n}'\n".encode()) + return self.esperar(marca, segundos, nombre=f"de «{orden[:40]}»") def qmp(ruta, ordenes): @@ -99,6 +130,8 @@ def qmp(ruta, ordenes): def main(): ap = argparse.ArgumentParser() ap.add_argument("--solo-cosmic", action="store_true", help="control: no lanza el navegador") + ap.add_argument("--como-usuario", action="store_true", + help="lanza `atuq` a secas —perfil por defecto, sin MOZ_ENABLE_WAYLAND— como se hizo a mano en el §6.10.ter") ap.add_argument("--espera", type=int, default=180, help="segundos para que el navegador pinte") ap.add_argument("--out", default=os.path.join(RAIZ, "work/atuq-imagen")) a = ap.parse_args() @@ -114,7 +147,7 @@ def main(): qemu = [ "nice", "-n", "10", "qemu-system-x86_64", "-machine", "q35", "-accel", "tcg", "-cpu", "max", "-m", MEM, "-smp", SMP, - "-vga", "none", "-device", "virtio-gpu-pci", "-display", "none", "-nic", "none", + *VGA_ARGS, "-device", "virtio-gpu-pci", "-display", "none", "-nic", "none", "-drive", f"if=pflash,format=raw,unit=0,file={OVMF_CODE},readonly=on", "-drive", f"if=pflash,format=raw,unit=1,file={vars_fd}", "-drive", f"file={IMG},format=raw,if=virtio", @@ -156,12 +189,23 @@ def main(): "

ATUQ PINTA

' > /tmp/pagina.html") ser.cmd("printf '%s\\n' 'user_pref(\"browser.dom.window.dump.enabled\", true);' > /tmp/perfil/user.js") ser.cmd("printf '%s\\n' 'user_pref(\"browser.shell.checkDefaultBrowser\", false);' >> /tmp/perfil/user.js") - lanz = ("MOZ_ENABLE_WAYLAND=1 GDK_BACKEND=wayland " - "MOZ_LOG='Widget:5,WidgetWayland:5,WaylandBackend:5,timestamp' " - "MOZ_LOG_FILE=/var/log/cosmic/moz " - "/usr/bin/atuq --no-remote --profile /tmp/perfil file:///tmp/pagina.html " - "> /var/log/cosmic/atuq.log 2>&1 &") - print(ser.cmd(lanz).strip()) + # ⚠ LOS DOS LANZAMIENTOS NO SON EL MISMO EXPERIMENTO. El de por defecto fija el + # entorno (perfil nuevo, `MOZ_ENABLE_WAYLAND`) para que la medición no dependa de lo que + # haya quedado en el estado del usuario; `--como-usuario` reproduce lo que se tecleó a + # mano en el §6.10.ter —`atuq` pelado, con SU perfil y sin variables— que es lo único que + # sigue distinto entre aquella corrida y ésta. El `MOZ_LOG` va en los dos: no cambia el + # comportamiento, sólo deja rastro. + if a.como_usuario: + lanz = ("MOZ_LOG='Widget:5,WidgetWayland:5,WaylandBackend:5,timestamp' " + "MOZ_LOG_FILE=/var/log/cosmic/moz " + "/usr/bin/atuq file:///tmp/pagina.html > /var/log/cosmic/atuq.log 2>&1 &") + else: + lanz = ("MOZ_ENABLE_WAYLAND=1 GDK_BACKEND=wayland " + "MOZ_LOG='Widget:5,WidgetWayland:5,WaylandBackend:5,timestamp' " + "MOZ_LOG_FILE=/var/log/cosmic/moz " + "/usr/bin/atuq --no-remote --profile /tmp/perfil file:///tmp/pagina.html " + "> /var/log/cosmic/atuq.log 2>&1 &") + print(ser.cmd(lanz, fondo=True).strip()) print(f"== navegador lanzado; observando {a.espera}s", flush=True) t0 = time.time(); n = 0 while time.time() - t0 < a.espera: