From 199488dac14bb0e866601652518c1c9d337c4c1e Mon Sep 17 00:00:00 2001 From: Antoine Martin Date: Wed, 10 Jun 2020 05:34:11 +0000 Subject: [PATCH] #2052 remove delta compression support git-svn-id: https://xpra.org/svn/Xpra/trunk@26663 3bb7dfac-3a0b-4e04-842a-767bc560f471 --- src/xpra/client/mixins/encodings.py | 1 - src/xpra/client/mixins/window_manager.py | 2 - src/xpra/client/window_backing_base.py | 74 +++------------ src/xpra/log.py | 1 - src/xpra/server/window/window_source.py | 113 +---------------------- 5 files changed, 15 insertions(+), 176 deletions(-) diff --git a/src/xpra/client/mixins/encodings.py b/src/xpra/client/mixins/encodings.py index bb477eeb6d..9eb13d2ca5 100644 --- a/src/xpra/client/mixins/encodings.py +++ b/src/xpra/client/mixins/encodings.py @@ -172,7 +172,6 @@ def get_encodings_caps(self) -> dict: "video_max_size" : self.video_max_size, "max-soft-expired" : MAX_SOFT_EXPIRED, "send-timestamps" : SEND_TIMESTAMPS, - "supports_delta" : tuple(x for x in ("png", "rgb24", "rgb32") if x in self.get_core_encodings()), } if self.video_scaling is not None: caps["scaling.control"] = self.video_scaling diff --git a/src/xpra/client/mixins/window_manager.py b/src/xpra/client/mixins/window_manager.py index 3f7cd2b01e..7eb003ea0b 100644 --- a/src/xpra/client/mixins/window_manager.py +++ b/src/xpra/client/mixins/window_manager.py @@ -958,7 +958,6 @@ def fake_send(*args): delta_pixel_data, video_decoder, csc_decoder, decoder_lock = None, None, None, None try: if backing: - delta_pixel_data = backing._delta_pixel_data video_decoder = backing._video_decoder csc_decoder = backing._csc_decoder decoder_lock = backing._decoder_lock @@ -993,7 +992,6 @@ def fake_send(*args): #restore the attributes we had saved from it if backing: backing = window._backing - backing._delta_pixel_data = delta_pixel_data backing._video_decoder = video_decoder backing._csc_decoder = csc_decoder backing._decoder_lock = decoder_lock diff --git a/src/xpra/client/window_backing_base.py b/src/xpra/client/window_backing_base.py index 6c70854b3a..5c8c016a53 100644 --- a/src/xpra/client/window_backing_base.py +++ b/src/xpra/client/window_backing_base.py @@ -1,6 +1,6 @@ # This file is part of Xpra. # Copyright (C) 2008 Nathaniel Smith -# Copyright (C) 2012-2019 Antoine Martin +# Copyright (C) 2012-2020 Antoine Martin # Xpra is released under the terms of the GNU GPL v2, or, at your option, any # later version. See the file COPYING for details. @@ -9,7 +9,7 @@ from xpra.net.mmap_pipe import mmap_read from xpra.net import compression -from xpra.util import typedict, csv, envint, envbool, repr_ellipsized, first_time +from xpra.util import typedict, csv, envint, envbool, first_time from xpra.codecs.loader import get_codec from xpra.codecs.video_helper import getVideoHelper from xpra.os_util import bytestostr @@ -29,9 +29,7 @@ from xpra.log import Logger log = Logger("paint") -deltalog = Logger("delta") -DELTA_BUCKETS = envint("XPRA_DELTA_BUCKETS", 5) INTEGRITY_HASH = envbool("XPRA_INTEGRITY_HASH", False) PAINT_BOX = envint("XPRA_PAINT_BOX", 0) or envint("XPRA_OPENGL_PAINT_BOX", 0) WEBP_PILLOW = envbool("XPRA_WEBP_PILLOW", False) @@ -95,7 +93,6 @@ def __init__(self, wid : int, window_alpha : bool): self.gravity = 0 self._alpha_enabled = window_alpha self._backing = None - self._delta_pixel_data = [None for _ in range(DELTA_BUCKETS)] self._video_decoder = None self._csc_decoder = None self._decoder_lock = Lock() @@ -329,50 +326,6 @@ def set_cursor_data(self, cursor_data): self.cursor_data = cursor_data - def process_delta(self, raw_data, width, height, rowstride, options): - """ - Can be called from any thread, decompresses and xors the rgb raw_data, - then stores it for later xoring if needed. - """ - img_data = raw_data - if options: - #check for one of the compressors: - comp = [x for x in compression.ALL_COMPRESSORS if options.intget(x, 0)] - if comp: - assert len(comp)==1, "more than one compressor specified: %s" % str(comp) - img_data = compression.decompress_by_name(raw_data, algo=comp[0]) - scaled_size = options.intpair("scaled-size") - if scaled_size: - return img_data - if len(img_data)!=rowstride * height: - deltalog.error("Error: invalid img data length: expected %s but got %s (%s: %s)", - rowstride * height, len(img_data), type(img_data), repr_ellipsized(img_data)) - raise Exception("expected %s bytes for %sx%s with rowstride=%s but received %s (%s compressed)" % - (rowstride * height, width, height, rowstride, len(img_data), len(raw_data))) - delta = options.intget(b"delta", -1) - bucket = options.intget(b"bucket", 0) - rgb_format = options.strget(b"rgb_format") - rgb_data = img_data - if delta>=0: - assert 0<=bucket=0: - deltalog("delta: storing sequence %i in bucket %i", store, bucket) - self._delta_pixel_data[bucket] = width, height, rgb_format, store, rgb_data - return rgb_data - - def paint_jpeg(self, img_data, x, y, width, height, options, callbacks): img = self.jpeg_decoder.decompress_to_rgb("RGBX", img_data, width, height, options) rgb_format = img.get_pixel_format() @@ -380,13 +333,12 @@ def paint_jpeg(self, img_data, x, y, width, height, options, callbacks): rowstride = img.get_rowstride() w = img.get_width() h = img.get_height() - self.idle_add(self.paint_rgb, rgb_format, img_data, x, y, w, h, rowstride, options, callbacks) + self.idle_add(self.do_paint_rgb, rgb_format, img_data, x, y, w, h, rowstride, options, callbacks) def paint_image(self, coding, img_data, x, y, width, height, options, callbacks): # can be called from any thread - rgb_format, raw_data, rowstride = self.pil_decoder.decompress(coding, img_data, options) - img_data = self.process_delta(raw_data, width, height, rowstride, options) + rgb_format, img_data, rowstride = self.pil_decoder.decompress(coding, img_data, options) self.idle_add(self.do_paint_rgb, rgb_format, img_data, x, y, width, height, rowstride, options, callbacks) def paint_webp(self, img_data, x, y, width, height, options, callbacks): @@ -418,15 +370,17 @@ def free_buffer(*_args): stride = img.get_rowstride() #replace with the actual rgb format we get from the decoder: options[b"rgb_format"] = rgb_format - return self.paint_rgb(rgb_format, data, x, y, width, height, stride, options, callbacks) + return self.do_paint_rgb(rgb_format, data, x, y, width, height, stride, options, callbacks) def paint_rgb(self, rgb_format, raw_data, x, y, width, height, rowstride, options, callbacks): - """ can be called from a non-UI thread - this method calls process_delta - before calling _do_paint_rgb from the UI thread via idle_add - """ - rgb_data = self.process_delta(raw_data, width, height, rowstride, options) - x, y = self.gravity_adjust(x, y, options) + """ can be called from a non-UI thread """ + rgb_data = raw_data + if options: + #check for one of the compressors: + comp = tuple(x for x in compression.ALL_COMPRESSORS if options.intget(x, 0)) + if comp: + assert len(comp)==1, "more than one compressor specified: %s" % str(comp) + rgb_data = compression.decompress_by_name(raw_data, algo=comp[0]) self.idle_add(self.do_paint_rgb, rgb_format, rgb_data, x, y, width, height, rowstride, options, callbacks) def do_paint_rgb(self, rgb_format, img_data, x, y, width, height, rowstride, options, callbacks): @@ -434,6 +388,7 @@ def do_paint_rgb(self, rgb_format, img_data, x, y, width, height, rowstride, opt this method is only here to ensure that we always fire the callbacks, the actual paint code is in _do_paint_rgb[24|32] """ + x, y = self.gravity_adjust(x, y, options) try: if not options.boolget("paint", True): fire_paint_callbacks(callbacks) @@ -696,7 +651,6 @@ def draw_region(self, x, y, width, height, coding, img_data, rowstride, options, if h: hd = h.hexdigest() assert chksum==hd, "pixel data failed compressed chksum integrity check: expected %s but got %s" % (chksum, hd) - deltalog("passed compressed data integrity checks: len=%s, chksum=%s (type=%s)", l, chksum, type(img_data)) unscaled_size = options.intpair("unscaled-size") if coding == "mmap": self.idle_add(self.paint_mmap, img_data, x, y, width, height, rowstride, options, callbacks) diff --git a/src/xpra/log.py b/src/xpra/log.py index be4bf41ea4..2305e96f13 100644 --- a/src/xpra/log.py +++ b/src/xpra/log.py @@ -217,7 +217,6 @@ def enable_format(format_string): "score" : "Video pipeline scoring and selection", "encoding" : "Server side encoding selection and compression", "scaling" : "Picture scaling", - "delta" : "Delta pre-compression", "scroll" : "Scrolling detection and compression", "xor" : "XOR delta pre-compression", "subregion" : "Video subregion processing", diff --git a/src/xpra/server/window/window_source.py b/src/xpra/server/window/window_source.py index 1ebbdcf04d..b1f2176d23 100644 --- a/src/xpra/server/window/window_source.py +++ b/src/xpra/server/window/window_source.py @@ -12,7 +12,7 @@ from math import sqrt from collections import deque -from xpra.os_util import memoryview_to_bytes, strtobytes, bytestostr, monotonic_time +from xpra.os_util import strtobytes, bytestostr, monotonic_time from xpra.util import envint, envbool, csv, typedict, first_time from xpra.common import MAX_WINDOW_SIZE from xpra.server.window.windowicon_source import WindowIconSource @@ -23,7 +23,6 @@ from xpra.rectangle import rectangle, add_rectangle, remove_rectangle, merge_all #@UnresolvedImport from xpra.server.picture_encode import rgb_encode, webp_encode, mmap_send from xpra.simple_stats import get_list_stats -from xpra.codecs.xor.cyxor import xor_str #@UnresolvedImport from xpra.codecs.argb.argb import argb_swap #@UnresolvedImport from xpra.codecs.rgb_transform import rgb_reformat from xpra.codecs.loader import get_codec @@ -37,7 +36,6 @@ damagelog = Logger("window", "damage") scalinglog = Logger("scaling") iconlog = Logger("icon") -deltalog = Logger("delta") avsynclog = Logger("av-sync") statslog = Logger("stats") bandwidthlog = Logger("bandwidth") @@ -55,10 +53,6 @@ MAX_PIXELS_PREFER_RGB = envint("XPRA_MAX_PIXELS_PREFER_RGB", 4096) MAX_RGB = envint("XPRA_MAX_RGB", 512*1024) -DELTA = envbool("XPRA_DELTA", True) -MIN_DELTA_SIZE = envint("XPRA_MIN_DELTA_SIZE", 1024) -MAX_DELTA_SIZE = envint("XPRA_MAX_DELTA_SIZE", 32768) -MAX_DELTA_HITS = envint("XPRA_MAX_DELTA_HITS", 20) MIN_WINDOW_REGION_SIZE = envint("XPRA_MIN_WINDOW_REGION_SIZE", 1024) MAX_SOFT_EXPIRED = envint("XPRA_MAX_SOFT_EXPIRED", 5) ACK_JITTER = envint("XPRA_ACK_JITTER", 20) @@ -182,20 +176,12 @@ def __init__(self, self.max_soft_expired = max(0, min(100, encoding_options.intget("max-soft-expired", MAX_SOFT_EXPIRED))) self.send_timetamps = encoding_options.boolget("send-timestamps", SEND_TIMESTAMPS) self.send_window_size = encoding_options.boolget("send-window-size", False) - self.supports_delta = () - if not window.is_tray() and DELTA: - self.supports_delta = [x for x in encoding_options.strtupleget("supports_delta") if x in ("png", "rgb24", "rgb32")] - if self.supports_delta: - self.delta_buckets = min(25, encoding_options.intget("delta_buckets", 1)) - self.delta_pixel_data = [None for _ in range(self.delta_buckets)] self.batch_config = batch_config #auto-refresh: self.auto_refresh_delay = auto_refresh_delay self.base_auto_refresh_delay = auto_refresh_delay self.last_auto_refresh_message = None self.video_helper = video_helper - if window.is_shadow(): - self.max_delta_size = -1 self.is_idle = False self.is_OR = window.is_OR() @@ -351,9 +337,6 @@ def init_vars(self): self.rgb_lzo = False self.supports_transparency = False self.full_frames_only = False - self.supports_delta = () - self.delta_buckets = 0 - self.delta_pixel_data = () self.suspended = False self.strict = STRICT_MODE # @@ -374,8 +357,6 @@ def init_vars(self): self.soft_timer = None self.soft_expired = 0 self.max_soft_expired = MAX_SOFT_EXPIRED - self.min_delta_size = MIN_DELTA_SIZE - self.max_delta_size = MAX_DELTA_SIZE self.is_OR = False self.is_tray = False self.is_shadow = False @@ -479,12 +460,6 @@ def get_info(self) -> dict: } } - now = monotonic_time() - buckets_info = {} - for i,x in enumerate(self.delta_pixel_data): - if x: - w, h, pixel_format, coding, store, buflen, _, hits, last_used = x - buckets_info[i] = w, h, pixel_format, coding, store, buflen, hits, int((now-last_used)*1000) #remove large default dict: info.update({ "idle" : self.is_idle, @@ -502,10 +477,6 @@ def get_info(self) -> dict: "last_used" : self.encoding_last_used or "", "full-frames-only" : self.full_frames_only, "supports-transparency" : self.supports_transparency, - "delta" : {"" : self.supports_delta, - "buckets" : self.delta_buckets, - "bucket" : buckets_info, - }, "property" : self.get_property_info(), "content-type" : self.content_type or "", "batch" : self.batch_config.get_info(), @@ -767,7 +738,6 @@ def set_new_encoding(self, encoding, strict): if self.encoding==encoding: return self.statistics.reset() - self.delta_pixel_data = [None for _ in range(self.delta_buckets)] self.update_encoding_selection(encoding) @@ -1000,7 +970,6 @@ def cancel_damage(self): #if a region was delayed, we can just drop it now: self.refresh_regions = [] self._damage_delayed = None - self.delta_pixel_data = [None for _ in range(self.delta_buckets)] #make sure we don't account for those as they will get dropped #(generally before encoding - only one may still get encoded): for sequence in tuple(self.statistics.encoding_pending.keys()): @@ -2278,8 +2247,6 @@ def s(v): else: log.warn(" unknown cause") self.global_statistics.decode_errors += 1 - #something failed client-side, so we can't rely on the delta being available - self.delta_pixel_data = [None for _ in range(self.delta_buckets)] if self.window: delay = min(1000, 250+self.global_statistics.decode_errors*100) self.decode_error_refresh_timer = self.timeout_add(delay, self.decode_error_refresh) @@ -2331,48 +2298,7 @@ def make_data_packet(self, damage_time, process_damage_time, image, coding, sequ psize = isize*4 log("make_data_packet: image=%s, damage data: %s", image, (self.wid, x, y, w, h, coding)) start = monotonic_time() - delta, store, bucket, hits = -1, -1, -1, 0 pixel_format = image.get_pixel_format() - #use delta pre-compression for this encoding if: - #* client must support delta (at least one bucket) - #* encoding must be one that supports delta (usually rgb24/rgb32 or png) - #* size is worth xoring (too small is pointless, too big is too expensive) - #* the pixel format is supported by the client - # (if we have to rgb_reformat the buffer, it really complicates things) - if self.delta_buckets>0 and (coding in self.supports_delta) and self.min_delta_size0 and hits=0: - client_options["delta"] = delta - client_options["bucket"] = bucket csize = len(data) - if store>0: - if delta>0 and csize>=psize*40//100: - #compressed size is more than 40% of the original - #maybe delta is not helping us, so clear it: - self.delta_pixel_data[bucket] = None - deltalog("delta: clearing bucket %i (compressed size=%s, original size=%s)", bucket, csize, psize) - #we could tell the clients they can clear it too - meh - #(add a new client capability and send it a zero store value) - else: - #find the bucket to use: - if bucket<0: - lpd = self.delta_pixel_data - try: - bucket = lpd.index(None) - deltalog("delta: found empty bucket %i", bucket) - except ValueError: - #find a bucket which has not been used recently - t = 0 - bucket = 0 - for i,dr in enumerate(lpd): - if dr and (t==0 or dr[-1]