CEE, Earth
Comment by ~schnwalter on ~eliasnaur/gio
Looks like there are more cases that are problematic. I've prepared some tests and a patch.
Here's the new program that I'm using to test all edge cases:
// SPDX-License-Identifier: Unlicense OR MIT package main import ( "gioui.org/app" "gioui.org/f32" "gioui.org/op" "gioui.org/op/clip" "gioui.org/op/paint" "gioui.org/unit" "image/color" "log" "os" ) func main() { go func() { var appWindow app.Window appWindow.Option( app.Title("Render Bug Demo"), app.Size(unit.Dp(560), unit.Dp(320)), ) if err := appRun(&appWindow); err != nil { log.Fatal(err) } os.Exit(0) }() app.Main() } func appRun(appWindow *app.Window) error { var ops op.Ops for { switch windowEvent := appWindow.Event().(type) { case app.DestroyEvent: return windowEvent.Err case app.FrameEvent: gtx := app.NewContext(&ops, windowEvent) strokeWidth := float32(80) { var lePath clip.Path lePath.Begin(gtx.Ops) lePath.MoveTo(f32.Point{X: 80, Y: 80}) lePath.LineTo(f32.Point{X: 80 + strokeWidth, Y: 80}) pathSpec := lePath.End() leShape := clip.Stroke{Path: pathSpec, Width: strokeWidth} paint.FillShape(gtx.Ops, color.NRGBA{R: 0xAA, G: 0x33, B: 0x33, A: 0xFF}, leShape.Op()) } { var lePath clip.Path lePath.Begin(gtx.Ops) lePath.MoveTo(f32.Point{X: 80 + strokeWidth, Y: 240}) lePath.LineTo(f32.Point{X: 80, Y: 240}) pathSpec := lePath.End() leShape := clip.Stroke{Path: pathSpec, Width: strokeWidth} paint.FillShape(gtx.Ops, color.NRGBA{R: 0xAA, G: 0x33, B: 0x33, A: 0xFF}, leShape.Op()) } { var lePath clip.Path lePath.Begin(gtx.Ops) lePath.MoveTo(f32.Point{X: 320, Y: 120}) lePath.LineTo(f32.Point{X: 320, Y: 120 + strokeWidth}) pathSpec := lePath.End() leShape := clip.Stroke{Path: pathSpec, Width: strokeWidth} paint.FillShape(gtx.Ops, color.NRGBA{R: 0xAA, G: 0x33, B: 0x33, A: 0xFF}, leShape.Op()) } { var lePath clip.Path lePath.Begin(gtx.Ops) lePath.MoveTo(f32.Point{X: 480, Y: 120 + strokeWidth}) lePath.LineTo(f32.Point{X: 480, Y: 120}) pathSpec := lePath.End() leShape := clip.Stroke{Path: pathSpec, Width: strokeWidth} paint.FillShape(gtx.Ops, color.NRGBA{R: 0xAA, G: 0x33, B: 0x33, A: 0xFF}, leShape.Op()) } windowEvent.Frame(gtx.Ops) gtx.Ops.Reset() } } }
Comment by ~schnwalter on ~eliasnaur/gio
I was the impression this was happening also in openSUSE, but it might not be the case. I have just checked this again on Xen and it stops working because of:
xen:grant_table: xen/grant-table: max_grant_frames reached cur=2048 extra=1 limit=2048 gnttab_free_count=0 req_entries=1
And this happens with the app consuming barely any memory and with plenty of free memory to go around.
I'm assuming this will be mitigated by #560, but it's still worth checking, maybe there's some improvement to be had for everybody.
I'll continue to look into this.
Comment by ~schnwalter on ~eliasnaur/gio
Here's a better visual example of the issue. (I've also sent a patch.)
// SPDX-License-Identifier: Unlicense OR MIT package main import ( "gioui.org/app" "gioui.org/f32" "gioui.org/op" "gioui.org/op/clip" "gioui.org/op/paint" "gioui.org/unit" "image/color" "log" "os" ) func main() { go func() { var appWindow app.Window appWindow.Option( app.Title("Stroke Rendering Bug"), app.Size(unit.Dp(320), unit.Dp(320)), ) if err := appRun(&appWindow); err != nil { log.Fatal(err) } os.Exit(0) }() app.Main() } func appRun(appWindow *app.Window) error { var ops op.Ops for { switch windowEvent := appWindow.Event().(type) { case app.DestroyEvent: return windowEvent.Err case app.FrameEvent: gtx := app.NewContext(&ops, windowEvent) strokeWidth := float32(40) var p clip.Path p.Begin(gtx.Ops) p.MoveTo(f32.Point{X: 50, Y: 50}) p.LineTo(f32.Point{X: 200, Y: 50}) p.LineTo(f32.Point{X: 200, Y: 50 + strokeWidth}) p.LineTo(f32.Point{X: 50, Y: 200}) p.Close() paint.FillShape( gtx.Ops, color.NRGBA{R: 0x33, G: 0x33, B: 0x33, A: 0xFF}, clip.Stroke{Path: p.End(), Width: strokeWidth}.Op(), ) windowEvent.Frame(gtx.Ops) } } }
Comment by ~schnwalter on ~eliasnaur/gio
From what I can tell, the final commit, 691adf4, has a different effect than the patch I've (51388).
It fixed the white bands, they are now gone, but the EGLSurface refresh is a bit late and you can see the content jumping a lot during vertical window resize, this didn't happen with 51388.
I'll look more into this sometime in the next few days.
Comment by ~schnwalter on ~eliasnaur/gio
No, I've discovered this while debugging #565.
I've just tested with 691adf4e, the problem persists.
on ~eliasnaur/gio
On Fri Apr 26, 2024 at 12:43 PM CEST, ~schnwalter wrote:
Anyway, it looks like
inkeliz
did a good job on giosvg and it has support for arcs, so it works with that file.I think I will use this then, it seems to do the job well !
Thanks for the suggestion. I think that this can be closed then.
-- vigoux
Comment by ~schnwalter on ~eliasnaur/gio
I'm trying to reproduce the bug without Gio. I've got the X11 window, the EGLSurface is there and it should show its background color, but I doesn't show up, here's what I have so far:
#include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <EGL/egl.h> #include <GLES3/gl3.h> #include <X11/Xlib.h> #include <X11/Xutil.h> void paint() { GLenum glErrors; eglBindAPI(EGL_OPENGL_ES_API); glViewport(0, 0, 600, 600); glErrors = glGetError(); if (glErrors != 0) { printf("ERROR: glGetError\n"); exit(1); } glClearColor(1,1,0,1); glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT); glFlush(); } //int argc char **argv; void main() { Display *myDisplay; int myScreen; int myDepth; XSetWindowAttributes myWindowAttributes; unsigned long myWindowMask; Window myWindow; XSizeHints theSizeHints; const int x = 200; const int y = 150; const unsigned int width = 800; const unsigned int height = 800; myDisplay = XOpenDisplay(""); if (myDisplay == NULL) { fprintf(stderr, "ERROR: Could not open a connection to X on display %s\n", XDisplayName(NULL) ); exit(0); } myScreen = DefaultScreen(myDisplay); myDepth = DefaultDepth(myDisplay, myScreen); myWindowAttributes.background_pixmap = None; myWindowAttributes.border_pixel = BlackPixel(myDisplay, myScreen); myWindowAttributes.background_pixel = 0xFF808080; myWindowAttributes.override_redirect = False; myWindowMask = CWBackPixel | CWBackPixmap | CWBorderPixel | CWOverrideRedirect; const XID window = RootWindow(myDisplay, myScreen); myWindow = XCreateWindow(myDisplay, window, x, y, width, height, 0, myDepth, InputOutput, CopyFromParent, myWindowMask, &myWindowAttributes); theSizeHints.flags = PPosition | PSize; theSizeHints.x = x; theSizeHints.y = y; theSizeHints.width = width; theSizeHints.height = height; XSetWMNormalHints(myDisplay, myWindow, &theSizeHints); XMapWindow(myDisplay, myWindow); XFlush(myDisplay); const EGLDisplay _eglDisplay = eglGetDisplay(myDisplay); if( _eglDisplay == EGL_NO_DISPLAY ){ printf( "ERROR: eglGetDisplay\n" ); exit(1); } const EGLBoolean emcRet = eglMakeCurrent(_eglDisplay, NULL, NULL, NULL); if (emcRet != EGL_TRUE) { printf( "ERROR: eglMakeCurrent\n" ); exit(1); } EGLint majorVersion; EGLint minorVersion; const EGLBoolean eglInitRet = eglInitialize(_eglDisplay, &majorVersion, &minorVersion); if (!eglInitRet) { printf("ERROR: eglInitialize\n"); exit(1); } const XID _eglWindow = window; const EGLint defaultAttribList[] = { EGL_RED_SIZE, 8, EGL_GREEN_SIZE, 8, EGL_BLUE_SIZE, 8, EGL_ALPHA_SIZE, 8, EGL_SURFACE_TYPE, EGL_WINDOW_BIT, EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT, EGL_CONFIG_CAVEAT, EGL_NONE, EGL_NONE }; EGLConfig eglCfg; EGLint ncfg; const EGLBoolean eglCfgRet = eglChooseConfig(_eglDisplay, defaultAttribList, &eglCfg, 1, &ncfg); if (!eglCfgRet || ncfg != 1) { printf("ERROR: eglChooseConfig\n"); return; } const EGLint surfAttribs[] = { EGL_GL_COLORSPACE, EGL_GL_COLORSPACE_SRGB, EGL_NONE, }; const EGLSurface _eglSurface = eglCreateWindowSurface(_eglDisplay, eglCfg, _eglWindow, surfAttribs); if (_eglSurface == EGL_NO_SURFACE) { printf("ERROR: eglCreateWindowSurface\n"); exit(1); } const EGLint ctxAttribs[] = { EGL_CONTEXT_CLIENT_VERSION, 3, EGL_NONE, }; const EGLContext nilEGLContext = 0; //EGL_CONTEXT_OPENGL_DEBUG const EGLContext _eglCtx = eglCreateContext(_eglDisplay, eglCfg, NULL, ctxAttribs); if (_eglCtx == nilEGLContext) { printf("ERROR: eglCreateContext\n"); exit(1); } EGLBoolean eglMakeCurentRet; eglMakeCurentRet = eglMakeCurrent(_eglDisplay, _eglSurface, _eglSurface, _eglCtx); if (!eglMakeCurentRet) { printf("ERROR: eglMakeCurrent\n"); exit(1); } paint(); const EGLBoolean eglSwapBuffersRet = eglSwapBuffers(_eglDisplay, _eglSurface); if (!eglSwapBuffersRet) { printf("Error eglSwapBuffers!\n"); exit(1); } eglMakeCurentRet = eglMakeCurrent(_eglDisplay, _eglSurface, _eglSurface, _eglCtx); if (!eglMakeCurentRet) { printf("ERROR: eglMakeCurrent\n"); exit(1); } sleep(10); eglDestroySurface(_eglDisplay, _eglSurface); XDestroyWindow(myDisplay, myWindow); XCloseDisplay(myDisplay); exit(0); }
Ticket created by ~schnwalter on ~eliasnaur/gio
If you take a simple window with a background color and resize it continuously for about 30 seconds (just move the mouse in circles), the window will crash with
signal: killed
if it's executed usinggo run
and the built version will just have a redraw lag of several seconds and the fan will go crazy, might be related to #560
Comment by ~schnwalter on ~eliasnaur/gio
And... we have a patch, turns out the problem was something else. No need to muck around with
XCreateWindow
flags, just reuse the EGLSurface:
Comment by ~schnwalter on ~eliasnaur/gio
One more thing... the default value for
bit_gravity
isForgetGravity
, it indicates that the window contents will always be discarded after a window size change; So, if we make Gio respond in time, we can keep the defaultbit_gravity
.