Code Monkey home page Code Monkey logo

Comments (13)

totaam avatar totaam commented on September 26, 2024

Can you include a screenshot of the problematic paints?
What GPU and driver are you using? (the output of xpra opengl)
Can you reproduce it with --opengl=force:native ?
What about turning off scroll encoding? --encodings=all,-scroll

from xpra.

aerusso avatar aerusso commented on September 26, 2024
  1. weird-artifact

My desktop background is black, I've redacted some text with 255,0,0 red (i.e., there is no artifact on the titlebar).

The black background is "clear". I.e., if I drag that xpra client window over another window, I can see the other window, beneath it through the remote xpra window:

weird-artifact-2

That image was made by moving the kolourpaint window beneath the nextcloud window AFTER the corruption started.

The corruption often goes away after resizing or presumably any client repaint of the affected area.

GLU=1.3
array-handlers=<OpenGL.arrays.numpymodule.NumpyHandler object at 0x7fd54cb51110>
backend=egl
max-viewport-dims=16384, 16384
opengl=4.6
platform=linux
pyopengl=3.1.7
renderer=AMD Radeon Graphics (radeonsi, gfx1103_r1, LLVM 17.0.6, DRM 3.57, 6.7.9-amd64)
safe=True
shading-language-version=4.60
success=True
texture-size-limit=16384
vendor=AMD
zerocopy=
  1. I cannot reproduce with --opengl=force:native, presumably because it falls back to no acceleration:
2024-04-27 06:47:56,870 No OpenGL_accelerate module loaded: No module named 'OpenGL_accelerate'
2024-04-27 06:47:56,920 Warning: cannot import OpenGL window module native
2024-04-27 06:47:56,920  'EGLPlatform' object has no attribute 'GLX'
2024-04-27 06:47:56,920 Warning: no OpenGL backend module found

(I do not have pyopengl_accelerate installed).

  1. I'm not able to reproduce with the client starting with --encodings=all,-scroll

from xpra.

totaam avatar totaam commented on September 26, 2024

I can reproduce it, and I have no idea how to fix it.
Although the context is now EGL / core context, the do_scroll_paints method is unchanged. (only cosmetic formatting changes in the while method)
This is the one from v5.x:

def do_scroll_paints(self, context, scrolls, flush:int=0, callbacks:Iterable[Callable]=()) -> None:
log("do_scroll_paints%s", (context, scrolls, flush))
if not context:
log("%s.do_scroll_paints(..) no context!", self)
fire_paint_callbacks(callbacks, False, "no opengl context")
return
def fail(msg):
log.error("Error: %s", msg)
fire_paint_callbacks(callbacks, False, msg)
bw, bh = self.size
self.copy_fbo(bw, bh)
for x,y,w,h,xdelta,ydelta in scrolls:
if abs(xdelta)>=bw:
fail(f"invalid xdelta value: {xdelta}, backing width is {bw}")
continue
if abs(ydelta)>=bh:
fail(f"invalid ydelta value: {ydelta}, backing height is {bh}")
continue
if ydelta==0 and xdelta==0:
fail("scroll has no delta!")
continue
if w<=0 or h<=0:
fail(f"invalid scroll area size: {w}x{h}")
continue
# these should be errors,
# but desktop-scaling can cause a mismatch between the backing size
# and the real window size server-side... so we clamp the dimensions instead
if x+w>bw:
w = bw-x
if y+h>bh:
h = bh-y
if x+w+xdelta>bw:
w = bw-x-xdelta
if w<=0:
continue #nothing left!
if y+h+ydelta>bh:
h = bh-y-ydelta
if h<=0:
continue #nothing left!
if x+xdelta<0:
rect = (x, y, w, h)
fail(f"horizontal scroll by {xdelta}"
+f" rectangle {rect} overflows the backing buffer size {self.size}")
continue
if y+ydelta<0:
rect = (x, y, w, h)
fail(f"vertical scroll by {ydelta}"
+f" rectangle {rect} overflows the backing buffer size {self.size}")
continue
#opengl buffer is upside down, so we must invert Y coordinates: bh-(..)
glBlitFramebuffer(x, bh-y, x+w, bh-(y+h),
x+xdelta, bh-(y+ydelta), x+w+xdelta, bh-(y+h+ydelta),
GL_COLOR_BUFFER_BIT, GL_NEAREST)
self.paint_box("scroll", x+xdelta, y+ydelta, x+w+xdelta, y+h+ydelta)
glFlush()
self.swap_fbos()
target = GL_TEXTURE_RECTANGLE_ARB
#restore normal paint state:
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, target, self.textures[TEX_FBO], 0)
glBindFramebuffer(GL_READ_FRAMEBUFFER, self.offscreen_fbo)
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, self.offscreen_fbo)
glBindFramebuffer(GL_FRAMEBUFFER, self.offscreen_fbo)
glBindTexture(target, 0)
glDisable(target)
fire_paint_callbacks(callbacks, True)
if not self.draw_needs_refresh:
self.present_fbo(0, 0, bw, bh, flush)

And the current one:
def do_scroll_paints(self, context, scrolls, flush=0, callbacks: Iterable[Callable] = ()) -> None:
log("do_scroll_paints%s", (context, scrolls, flush))
if not context:
log("%s.do_scroll_paints(..) no context!", self)
fire_paint_callbacks(callbacks, False, "no opengl context")
return
def fail(msg):
log.error("Error: %s", msg)
fire_paint_callbacks(callbacks, False, msg)
bw, bh = self.size
self.copy_fbo(bw, bh)
for x, y, w, h, xdelta, ydelta in scrolls:
if abs(xdelta) >= bw:
fail(f"invalid xdelta value: {xdelta}, backing width is {bw}")
continue
if abs(ydelta) >= bh:
fail(f"invalid ydelta value: {ydelta}, backing height is {bh}")
continue
if ydelta == 0 and xdelta == 0:
fail("scroll has no delta!")
continue
if w <= 0 or h <= 0:
fail(f"invalid scroll area size: {w}x{h}")
continue
# these should be errors,
# but desktop-scaling can cause a mismatch between the backing size
# and the real window size server-side... so we clamp the dimensions instead
if x + w > bw:
w = bw - x
if y + h > bh:
h = bh - y
if x + w + xdelta > bw:
w = bw - x - xdelta
if w <= 0:
continue # nothing left!
if y + h + ydelta > bh:
h = bh - y - ydelta
if h <= 0:
continue # nothing left!
if x + xdelta < 0:
rect = (x, y, w, h)
fail(f"horizontal scroll by {xdelta} rectangle {rect} overflows the backing buffer size {self.size}")
continue
if y + ydelta < 0:
rect = (x, y, w, h)
fail(f"vertical scroll by {ydelta} rectangle {rect} overflows the backing buffer size {self.size}")
continue
# opengl buffer is upside down, so we must invert Y coordinates: bh-(..)
glBlitFramebuffer(x, bh - y, x + w, bh - (y + h),
x + xdelta, bh - (y + ydelta), x + w + xdelta, bh - (y + h + ydelta),
GL_COLOR_BUFFER_BIT, GL_NEAREST)
self.paint_box("scroll", x + xdelta, y + ydelta, x + w + xdelta, y + h + ydelta)
glFlush()
self.swap_fbos()
target = GL_TEXTURE_RECTANGLE
# restore normal paint state:
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, target, self.textures[TEX_FBO], 0)
glBindFramebuffer(GL_READ_FRAMEBUFFER, self.offscreen_fbo)
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, self.offscreen_fbo)
glBindFramebuffer(GL_FRAMEBUFFER, self.offscreen_fbo)
glBindTexture(target, 0)
fire_paint_callbacks(callbacks, True)
if not self.draw_needs_refresh:
self.present_fbo(context, 0, 0, bw, bh, flush)

from xpra.

totaam avatar totaam commented on September 26, 2024

'EGLPlatform' object has no attribute 'GLX'

Ah, is it a Wayland desktop? (then native isn't available)

from xpra.

totaam avatar totaam commented on September 26, 2024

So, this is a strange one.
I first thought that this was a true regression, but I can reproduce some corruption with v5.x LTS, just less often and far less drastic.
It would seem that the new OpenGL paint code is to blame - despite being unchanged since v5.x
But I can also reproduce some corruption with --opengl=no.

If I don't make progress, I could disable scroll for the next update as this will "fix" things - at least temporarily, buying some time.

from xpra.

bugreporter42 avatar bugreporter42 commented on September 26, 2024

opengl=force:native has the same issue (client version 6.0). I'm getting a lot of corruption between different windows (using shadow for a remote desktop).

Client version 4.4.5 works correctly.

from xpra.

cherio avatar cherio commented on September 26, 2024

Same issue when connecting from xpra 6.0-1 client (Arch linux, XFCE/GTK) to either another 6.0-1 server (Arch linux) or v6.0-r0 server (ubuntu 22.04) from xpra stable repository.

2024-05-13 16:14:27,738 Xpra GTK3 X11 client version 6.0-r0
2024-05-13 16:14:27,742  running on Linux 6.8.9-arch1-2
2024-05-13 16:14:27,742  cpython 3.12
2024-05-13 16:14:27,742  window manager is 'Xfwm4'
2024-05-13 16:14:27,941 GStreamer version 1.24.3
2024-05-13 16:14:27,968 created unix domain sockets:
2024-05-13 16:14:27,968  '/run/user/1000/xpra/clients/client-host-298575'
2024-05-13 16:14:28,345 No OpenGL_accelerate module loaded: No module named 'OpenGL_accelerate'
2024-05-13 16:14:28,539 OpenGL enabled on 'AMD Radeon Graphics'
2024-05-13 16:14:28,551  keyboard settings: rules=evdev, model=pc105, layout=us
2024-05-13 16:14:28,553  desktop size is 2560x1440:
2024-05-13 16:14:28,553   :0.0 (677x381 mm - DPI: 96x96) workarea: 2560x1420
2024-05-13 16:14:28,553     SAM HDMI-A-1     (597x336 mm - DPI: 109x109)
2024-05-13 16:14:29,162 enabled remote logging
2024-05-13 16:14:29,163 Xpra X11 seamless server version 6.0
2024-05-13 16:14:29,206 Attached to xpra server at tcp://localhost:12345/6
2024-05-13 16:14:29,206  (press Control-C to detach)

Previous Arch xpra-4.4.5-3 client did not have this issue, although it could never successfully use OpenGL in the first place, at least in my experience.

Setting --opengl=no seems to solve the issue, or at least make it unnoticeable.

from xpra.

alexisshaw avatar alexisshaw commented on September 26, 2024

Xpra client 6.0 on Windows has this issue, and the v5.0.8 client doesn't, though it successfully used openGL on 5.0.8

from xpra.

totaam avatar totaam commented on September 26, 2024

v6.0.1 will have scroll encoding disabled until I can figure out where the problem comes from: a65e0e2

from xpra.

totaam avatar totaam commented on September 26, 2024

I had forgotten to disable it again for 6.1: 8c05f44

After adding support for another fast hashing function: google's cityhash and replacing xxh3:

diff --git a/xpra/server/window/motion.pyx b/xpra/server/window/motion.pyx
index 1f7928eff3..b5c2beea17 100644
--- a/xpra/server/window/motion.pyx
+++ b/xpra/server/window/motion.pyx
@@ -15,7 +15,7 @@ from xpra.log import Logger
 log = Logger("encoding", "scroll")
 
 from xpra.buffers.membuf cimport memalign, buffer_context  # pylint: disable=syntax-error
-from xpra.buffers.xxh cimport xxh3
+from xpra.buffers.cityhash cimport cityhash64
 from xpra.util.rectangle import rectangle
 
 
@@ -124,7 +124,7 @@ cdef class ScrollData:
             assert row_len<=rowstride, "invalid row length: %ix%i=%i but rowstride is %i" % (width, bpp, width*bpp, rowstride)
             with nogil:
                 for i in range(height):
-                    a2[i] = xxh3(buf, row_len)
+                    a2[i] = cityhash64(buf, row_len)
                     buf += rowstride
 
 

We can also use the much slower hashlib variants:

diff --git a/xpra/server/window/motion.pyx b/xpra/server/window/motion.pyx
index 1f7928eff3..74076eb83d 100644
--- a/xpra/server/window/motion.pyx
+++ b/xpra/server/window/motion.pyx
@@ -117,15 +117,18 @@ cdef class ScrollData:
         cdef uint64_t *a2 = self.a2
         cdef uint16_t i
         cdef uint8_t *buf
+        from hashlib import sha256
+        from struct import unpack
         with buffer_context(pixels) as bc:
             buf = <uint8_t*> (<uintptr_t> int(bc))
             assert len(bc)>=min_buf_len, "buffer length=%i is too small for %ix%i with rowstride %i, should be %i" % (
                     len(bc), width, height, rowstride, min_buf_len)
             assert row_len<=rowstride, "invalid row length: %ix%i=%i but rowstride is %i" % (width, bpp, width*bpp, rowstride)
-            with nogil:
-                for i in range(height):
-                    a2[i] = xxh3(buf, row_len)
-                    buf += rowstride
+            for i in range(height):
+                row = buf[:row_len]
+                digest = sha256(row, usedforsecurity=False).digest()
+                a2[i] = unpack(">Q", digest[:8])[0]
+                buf += rowstride
 
 
     def calculate(self, uint16_t max_distance=1000) -> None:

The visual artifacts persists.

So it's unlikely to be caused by unexpected 64-bit hash collisions.

c4cc39b added the XPRA_IMAGE_ALWAYS_FREEZE toggle:

ALWAYS_FREEZE = envbool("XPRA_IMAGE_ALWAYS_FREEZE", False)

So the pixels probably aren't getting corrupted in between the time we calculate the checksum and the time we read them since the data is only held in this one image wrapper object?

from xpra.

totaam avatar totaam commented on September 26, 2024

References:

Should we be using render buffers instead of textures?
glFramebufferRenderbuffer states that Renderbuffers cannot be attached to the default draw and read framebuffer, so they are not valid targets of these commands so this would prevent us from copying from the render buffer?

from xpra.

totaam avatar totaam commented on September 26, 2024

I can't hold up the 6.1.1 release any longer, so scroll is disabled in the client again..

from xpra.

totaam avatar totaam commented on September 26, 2024

TLDR: use glClear(GL_COLOR_BUFFER_BIT).
I don't understand why the fix works, but it does: 617aa2e was a fix for desktop scaling (#4324) and applying the same fix to scroll paints fixes that too: 342dfa0


Why do we need to glClear the FBO since we're copying 100% of the source FBO into it immediately after?
Why would the previous contents matter at all?
And the textures attached to the fbos should have been cleared anyway since we glTexImage2D them with a NULL buffer on the statement just before that!?:

glTexImage2D(target, 0, self.internal_format, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, None)

from xpra.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.